Kaynağa Gözat

Add VR video fixes see #2622

Julio Montoya 6 yıl önce
ebeveyn
işleme
a65d4121c2
43 değiştirilmiş dosya ile 13819 ekleme ve 2 silme
  1. 27 0
      app/Resources/public/assets/vrview/CONTRIBUTING
  2. 202 0
      app/Resources/public/assets/vrview/LICENSE
  3. 73 0
      app/Resources/public/assets/vrview/README.md
  4. 1 0
      app/Resources/public/assets/vrview/build/device-motion-sender.min.js
  5. 2548 0
      app/Resources/public/assets/vrview/build/embed.js
  6. 0 0
      app/Resources/public/assets/vrview/build/embed.min.js
  7. 4183 0
      app/Resources/public/assets/vrview/build/three.js
  8. 200 0
      app/Resources/public/assets/vrview/build/three.min.js
  9. 784 0
      app/Resources/public/assets/vrview/build/vrview.js
  10. 0 0
      app/Resources/public/assets/vrview/build/vrview.min.js
  11. 41 0
      app/Resources/public/assets/vrview/index-minified.html
  12. 41 0
      app/Resources/public/assets/vrview/index.html
  13. 2836 0
      app/Resources/public/assets/vrview/package-lock.json
  14. 56 0
      app/Resources/public/assets/vrview/package.json
  15. 21 0
      app/Resources/public/assets/vrview/scripts/acl.txt
  16. 21 0
      app/Resources/public/assets/vrview/scripts/deploy-2.0.sh
  17. 88 0
      app/Resources/public/assets/vrview/scripts/js/device-motion-sender.js
  18. 2 0
      app/Resources/public/assets/vrview/src/api/README.md
  19. 80 0
      app/Resources/public/assets/vrview/src/api/iframe-message-sender.js
  20. 22 0
      app/Resources/public/assets/vrview/src/api/main.js
  21. 316 0
      app/Resources/public/assets/vrview/src/api/player.js
  22. 147 0
      app/Resources/public/assets/vrview/src/embed/adaptive-player.js
  23. 56 0
      app/Resources/public/assets/vrview/src/embed/analytics.js
  24. 20 0
      app/Resources/public/assets/vrview/src/embed/eyes.js
  25. 403 0
      app/Resources/public/assets/vrview/src/embed/hotspot-renderer.js
  26. 68 0
      app/Resources/public/assets/vrview/src/embed/iframe-message-receiver.js
  27. 54 0
      app/Resources/public/assets/vrview/src/embed/loading-indicator.js
  28. 369 0
      app/Resources/public/assets/vrview/src/embed/main.js
  29. 41 0
      app/Resources/public/assets/vrview/src/embed/reticle-renderer.js
  30. 125 0
      app/Resources/public/assets/vrview/src/embed/scene-info.js
  31. 205 0
      app/Resources/public/assets/vrview/src/embed/sphere-renderer.js
  32. 130 0
      app/Resources/public/assets/vrview/src/embed/video-proxy.js
  33. 20 0
      app/Resources/public/assets/vrview/src/embed/with-analytics.js
  34. 372 0
      app/Resources/public/assets/vrview/src/embed/world-renderer.js
  35. 33 0
      app/Resources/public/assets/vrview/src/message.js
  36. 29 0
      app/Resources/public/assets/vrview/src/third_party/three/Three.js
  37. BIN
      app/Resources/public/assets/vrview/src/third_party/three/closure-compiler-v20160713.jar
  38. 10 0
      app/Resources/public/assets/vrview/src/third_party/three/externs.js
  39. 34 0
      app/Resources/public/assets/vrview/src/third_party/three/rollup.config.js
  40. 33 0
      app/Resources/public/assets/vrview/src/util.js
  41. 25 0
      app/Resources/public/assets/vrview/src/video-type.js
  42. 100 0
      app/Resources/public/assets/vrview/style.css
  43. 3 2
      main/template/default/layout/main.js.tpl

+ 27 - 0
app/Resources/public/assets/vrview/CONTRIBUTING

@@ -0,0 +1,27 @@
+Want to contribute? Great! First, read this page (including the small print at the end).
+
+### Before you contribute
+Before we can use your code, you must sign the
+[Google Individual Contributor License Agreement]
+(https://cla.developers.google.com/about/google-individual)
+(CLA), which you can do online. The CLA is necessary mainly because you own the
+copyright to your changes, even after your contribution becomes part of our
+codebase, so we need your permission to use and distribute your code. We also
+need to be sure of various other things—for instance that you'll tell us if you
+know that your code infringes on other people's patents. You don't have to sign
+the CLA until after you've submitted your code for review and a member has
+approved it, but you must do it before we can put your code into our codebase.
+Before you start working on a larger contribution, you should get in touch with
+us first through the issue tracker with your idea so that we can help out and
+possibly guide you. Coordinating up front makes it much easier to avoid
+frustration later on.
+
+### Code reviews
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose.
+
+### The small print
+Contributions made by corporations are covered by a different agreement than
+the one above, the
+[Software Grant and Corporate Contributor License Agreement]
+(https://cla.developers.google.com/about/google-corporate).

+ 202 - 0
app/Resources/public/assets/vrview/LICENSE

@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2015 Google Inc
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 73 - 0
app/Resources/public/assets/vrview/README.md

@@ -0,0 +1,73 @@
+# VR View
+
+[![Build Status](https://travis-ci.org/googlevr/vrview.svg?branch=master)](https://travis-ci.org/googlevr/vrview)
+[![dependencies Status](https://david-dm.org/googlevr/vrview/status.svg)](https://david-dm.org/googlevr/vrview)
+[![devDependencies Status](https://david-dm.org/googlevr/vrview/dev-status.svg)](https://david-dm.org/googlevr/vrview?type=dev)
+
+VR View allows you to embed 360 degree VR media into websites on desktop and
+mobile. For more information, please read the documentation available at
+<http://developers.google.com/cardboard/vrview>.
+
+# Configuration
+
+A complete list of VR View parameters can be found in the table below.
+
+Name | Type | Parameter description
+---- | ---- | ---------------------
+`video` | String | URL to a 360° video file or an adaptive streaming manifest file (.mpd or .m3u8). Exactly one of video or image is required.
+`image` | String | URL to a 360° image file. Exactly one of video or image is required.
+`width` | String | String value for the iframe's width attribute.
+`height` | String | String value for the iframe's height attribute.
+`preview` | String | (Optional) URL to a preview image for a 360° image file.
+`is_stereo` | Boolean | (Optional) Indicates whether the content at the image or video URL is stereo or not.
+`is_debug` | Boolean | (Optional) When true, turns on debug features like rendering hotspots ad showing the FPS meter.
+`is_vr_off` | Boolean | (Optional) When true, disables the VR mode button.
+`is_autopan_off` | Boolean | (Optional) When true, disables the autopan introduction on desktop.
+`default_yaw` | Number | (Optional) Numeric angle in degrees of the initial heading for the 360° content. By default, the camera points at the center of the underlying image.
+`is_yaw_only` | Boolean | (Optional) When true, prevents roll and pitch. This is intended for stereo panoramas.
+`loop` | Boolean | (Optional) When false, stops the loop in the video.
+`hide_fullscreen_button` | Boolean | (Optional) When true, the fullscreen button contained inside the VR View iframe will be hidden. This parameter is useful if the user wants to use VR View's fullscreen workflow (via `vrView.setFullscreen()` callback) with an element outside the iframe. 
+`volume` | Number | (Optional) The initial volume of the media; it ranges between 0 and 1; zero equals muted.
+`muted` | Boolean | (Optional) When true, mutes the sound of the video.
+
+# Downloading files
+
+The `gh-pages` branch hosts the built files. Download these instead of linking to these
+locations, since the directory structure of the repo may change in the future.
+
+* [https://googlevr.github.io/vrview/build/vrview.js](https://googlevr.github.io/vrview/build/vrview.js)
+* [https://googlevr.github.io/vrview/build/vrview.min.js](https://googlevr.github.io/vrview/build/vrview.min.js)
+* [https://googlevr.github.io/vrview/build/embed.js](https://googlevr.github.io/vrview/build/embed.js)
+* [https://googlevr.github.io/vrview/build/embed.min.js](https://googlevr.github.io/vrview/build/embed.min.js)
+* [https://googlevr.github.io/vrview/build/three.js](https://googlevr.github.io/vrview/build/three.js)
+* [https://googlevr.github.io/vrview/build/three.min.js](https://googlevr.github.io/vrview/build/three.min.js)
+* [https://googlevr.github.io/vrview/build/device-motion-sender.min.js](https://googlevr.github.io/vrview/build/device-motion-sender.min.js)
+
+# Building
+
+This project uses `browserify` to manage dependencies and build. `watchify` is
+especially convenient to preserve the write-and-reload model of development.
+This package lives in the npm index.
+
+**Current builds are not working on Windows ([#261](https://github.com/googlevr/vrview/issues/261))**
+
+Relevant commands:
+```shell
+$ npm run build # builds the iframe embed and JS API (full and minified versions).
+$ npm run build-api # builds the JS API (full and minified versions).
+
+$ npm run build-min # builds the minified iframe embed.
+$ npm run build-dev # builds the full iframe embed.
+
+$ npm run build-api-min # builds the minified JS API.
+$ npm run build-api-dev # builds the full JS API.
+
+$ npm run watch # auto-builds the iframe embed whenever any source changes.
+$ npm run watch-api # auto-builds the JS API code whenever any source changes.
+```
+As of 2017/06/13, the pre-built js artifacts have been removed from source
+control. You must run `npm run build` prior to trying any of the examples.
+
+# Release Notes
+## 2.0.2
+Close vulnerability with unsanitized user strings being injected into DOM

+ 1 - 0
app/Resources/public/assets/vrview/build/device-motion-sender.min.js

@@ -0,0 +1 @@
+function DeviceMotionSender(){if(!this.isIOS_()){return}window.addEventListener("devicemotion",this.onDeviceMotion_.bind(this),false);this.iframes=document.querySelectorAll("iframe.vrview")}DeviceMotionSender.prototype.onDeviceMotion_=function(e){var message={type:"DeviceMotion",deviceMotionEvent:this.cloneDeviceMotionEvent_(e)};for(var i=0;i<this.iframes.length;i++){var iframe=this.iframes[i];var iframeWindow=iframe.contentWindow;if(this.isCrossDomainIframe_(iframe)){iframeWindow.postMessage(message,"*")}}};DeviceMotionSender.prototype.cloneDeviceMotionEvent_=function(e){return{acceleration:{x:e.acceleration.x,y:e.acceleration.y,z:e.acceleration.z},accelerationIncludingGravity:{x:e.accelerationIncludingGravity.x,y:e.accelerationIncludingGravity.y,z:e.accelerationIncludingGravity.z},rotationRate:{alpha:e.rotationRate.alpha,beta:e.rotationRate.beta,gamma:e.rotationRate.gamma},interval:e.interval}};DeviceMotionSender.prototype.isIOS_=function(){return/iPad|iPhone|iPod/.test(navigator.userAgent)&&!window.MSStream};DeviceMotionSender.prototype.isCrossDomainIframe_=function(iframe){var html=null;try{var doc=iframe.contentDocument||iframe.contentWindow.document;html=doc.body.innerHTML}catch(err){}return html===null};var dms=new DeviceMotionSender;

Dosya farkı çok büyük olduğundan ihmal edildi
+ 2548 - 0
app/Resources/public/assets/vrview/build/embed.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
app/Resources/public/assets/vrview/build/embed.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 4183 - 0
app/Resources/public/assets/vrview/build/three.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 200 - 0
app/Resources/public/assets/vrview/build/three.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 784 - 0
app/Resources/public/assets/vrview/build/vrview.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
app/Resources/public/assets/vrview/build/vrview.min.js


+ 41 - 0
app/Resources/public/assets/vrview/index-minified.html

@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <title>VR view</title>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+  <meta name="mobile-web-app-capable" content="yes">
+  <meta name="apple-mobile-web-app-capable" content="yes" />
+  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
+  <link rel="stylesheet" href="style.css">
+</head>
+
+<body>
+  <div id="error" class="dialog">
+    <div class="wrap">
+      <h1 class="title">Error</h1>
+      <p class="message">An unknown error occurred.</p>
+    </div>
+  </div>
+
+  <div id="play-overlay">
+    <img src="images/ic_play_arrow_white_24dp.svg" />
+  </div>
+
+  <a id="watermark" href="http://g.co/vr/view" target="_blank">
+    <img src="images/ic_info_outline_black_24dp.svg" />
+  </a>
+
+  <script>
+    WebVRConfig = {
+      BUFFER_SCALE: 0.5,
+      TOUCH_PANNER_DISABLED: false
+    };
+  </script>
+
+  <script src="build/three.min.js"></script>
+  <script src="build/embed.min.js"></script>
+</body>
+
+</html>

+ 41 - 0
app/Resources/public/assets/vrview/index.html

@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <title>VR view</title>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+  <meta name="mobile-web-app-capable" content="yes">
+  <meta name="apple-mobile-web-app-capable" content="yes" />
+  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
+  <link rel="stylesheet" href="style.css">
+</head>
+
+<body>
+  <div id="error" class="dialog">
+    <div class="wrap">
+      <h1 class="title">Error</h1>
+      <p class="message">An unknown error occurred.</p>
+    </div>
+  </div>
+
+  <div id="play-overlay">
+    <img src="images/ic_play_arrow_white_24dp.svg" />
+  </div>
+
+  <a id="watermark" href="http://g.co/vr/view" target="_blank">
+    <img src="images/ic_info_outline_black_24dp.svg" />
+  </a>
+
+  <script>
+    WebVRConfig = {
+      BUFFER_SCALE: 0.5,
+      TOUCH_PANNER_DISABLED: false
+    };
+  </script>
+
+  <script src="build/three.js"></script>
+  <script src="build/embed.js"></script>
+</body>
+
+</html>

+ 2836 - 0
app/Resources/public/assets/vrview/package-lock.json

@@ -0,0 +1,2836 @@
+{
+  "name": "vrview",
+  "version": "2.0.1",
+  "lockfileVersion": 1,
+  "dependencies": {
+    "@tweenjs/tween.js": {
+      "version": "16.8.0",
+      "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-16.8.0.tgz",
+      "integrity": "sha1-XEOWWQH9lVSycOISUfTRjuSQadM="
+    },
+    "acorn": {
+      "version": "4.0.13",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
+      "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=",
+      "dev": true
+    },
+    "acorn-jsx": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
+      "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
+      "dev": true,
+      "dependencies": {
+        "acorn": {
+          "version": "3.3.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
+          "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
+          "dev": true
+        }
+      }
+    },
+    "ajv": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.2.tgz",
+      "integrity": "sha1-R8aNaehvXZUxA7AHSpQw3GPaXjk=",
+      "dev": true,
+      "dependencies": {
+        "json-stable-stringify": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
+          "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
+          "dev": true
+        }
+      }
+    },
+    "ajv-keywords": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz",
+      "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=",
+      "dev": true
+    },
+    "ansi-escapes": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-2.0.0.tgz",
+      "integrity": "sha1-W65SvkJIeN2Xg+iRDj/Cki6DyBs=",
+      "dev": true
+    },
+    "ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+      "dev": true
+    },
+    "ansi-styles": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+      "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+      "dev": true
+    },
+    "anymatch": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz",
+      "integrity": "sha1-o+Uvo5FoyCX/V7AkgSbOWo/5VQc=",
+      "dev": true
+    },
+    "argparse": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
+      "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=",
+      "dev": true
+    },
+    "arr-diff": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+      "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+      "dev": true
+    },
+    "arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+      "dev": true
+    },
+    "array-filter": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
+      "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=",
+      "dev": true
+    },
+    "array-map": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
+      "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=",
+      "dev": true
+    },
+    "array-reduce": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
+      "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=",
+      "dev": true
+    },
+    "array-union": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+      "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+      "dev": true
+    },
+    "array-uniq": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+      "dev": true
+    },
+    "array-unique": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+      "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+      "dev": true
+    },
+    "arrify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+      "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+      "dev": true
+    },
+    "asn1.js": {
+      "version": "4.9.1",
+      "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz",
+      "integrity": "sha1-SLokC0WpKA6UdImQull9IWYX/UA=",
+      "dev": true
+    },
+    "assert": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
+      "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
+      "dev": true
+    },
+    "astw": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz",
+      "integrity": "sha1-e9QXhNMkk5h66yOba04cV6hzuRc=",
+      "dev": true
+    },
+    "async-each": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
+      "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=",
+      "dev": true
+    },
+    "babel-code-frame": {
+      "version": "6.22.0",
+      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz",
+      "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=",
+      "dev": true
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "dev": true
+    },
+    "base64-js": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
+      "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==",
+      "dev": true
+    },
+    "binary-extensions": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.8.0.tgz",
+      "integrity": "sha1-SOyNFt9Dd+rl+liEaCSAr02Vx3Q=",
+      "dev": true
+    },
+    "bn.js": {
+      "version": "4.11.7",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.7.tgz",
+      "integrity": "sha512-LxFiV5mefv0ley0SzqkOPR1bC4EbpPx8LkOz5vMe/Yi15t5hzwgO/G+tc7wOtL4PZTYjwHu8JnEiSLumuSjSfA==",
+      "dev": true
+    },
+    "brace-expansion": {
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
+      "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
+      "dev": true
+    },
+    "braces": {
+      "version": "1.8.5",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+      "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+      "dev": true
+    },
+    "brorand": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+      "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
+      "dev": true
+    },
+    "browser-pack": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.0.2.tgz",
+      "integrity": "sha1-+GzWzvT1MAyOY+B6TVEvZfv/RTE=",
+      "dev": true
+    },
+    "browser-resolve": {
+      "version": "1.11.2",
+      "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz",
+      "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=",
+      "dev": true,
+      "dependencies": {
+        "resolve": {
+          "version": "1.1.7",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+          "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
+          "dev": true
+        }
+      }
+    },
+    "browserify": {
+      "version": "13.3.0",
+      "resolved": "https://registry.npmjs.org/browserify/-/browserify-13.3.0.tgz",
+      "integrity": "sha1-tanJAgJD8McORnW+yCI7xifkFc4=",
+      "dev": true
+    },
+    "browserify-aes": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.6.tgz",
+      "integrity": "sha1-Xncl297x/Vkw1OurSFZ85FHEigo=",
+      "dev": true
+    },
+    "browserify-cipher": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz",
+      "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=",
+      "dev": true
+    },
+    "browserify-des": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz",
+      "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=",
+      "dev": true
+    },
+    "browserify-rsa": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+      "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
+      "dev": true
+    },
+    "browserify-sign": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
+      "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
+      "dev": true
+    },
+    "browserify-zlib": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
+      "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=",
+      "dev": true
+    },
+    "buffer": {
+      "version": "4.9.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
+      "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
+      "dev": true
+    },
+    "buffer-xor": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+      "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
+      "dev": true
+    },
+    "builtin-modules": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+      "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+      "dev": true
+    },
+    "builtin-status-codes": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+      "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
+      "dev": true
+    },
+    "cached-path-relative": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz",
+      "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc=",
+      "dev": true
+    },
+    "caller-path": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
+      "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
+      "dev": true
+    },
+    "callsites": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
+      "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
+      "dev": true
+    },
+    "camelcase": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+      "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
+      "dev": true
+    },
+    "chalk": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+      "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+      "dev": true
+    },
+    "chokidar": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
+      "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
+      "dev": true
+    },
+    "cipher-base": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+      "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+      "dev": true
+    },
+    "circular-json": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz",
+      "integrity": "sha1-vos2rvzN6LPKeqLWr8B6NyQsDS0=",
+      "dev": true
+    },
+    "cli-cursor": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+      "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+      "dev": true
+    },
+    "cli-width": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz",
+      "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=",
+      "dev": true
+    },
+    "cliui": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+      "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+      "dev": true
+    },
+    "co": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+      "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
+      "dev": true
+    },
+    "code-point-at": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+      "dev": true
+    },
+    "color-convert": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz",
+      "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=",
+      "dev": true
+    },
+    "color-name": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.2.tgz",
+      "integrity": "sha1-XIq3K2S9IhXWF66VWeuxSEdc+Y0=",
+      "dev": true
+    },
+    "combine-source-map": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.7.2.tgz",
+      "integrity": "sha1-CHAxKFazB6h8xKxIbzqaYq7MwJ4=",
+      "dev": true
+    },
+    "commander": {
+      "version": "2.9.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+      "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
+      "dev": true
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "concat-stream": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz",
+      "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=",
+      "dev": true,
+      "dependencies": {
+        "readable-stream": {
+          "version": "2.0.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
+          "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
+          "dev": true
+        }
+      }
+    },
+    "console-browserify": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+      "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
+      "dev": true
+    },
+    "constants-browserify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+      "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
+      "dev": true
+    },
+    "convert-source-map": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
+      "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=",
+      "dev": true
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
+    },
+    "create-ecdh": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz",
+      "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=",
+      "dev": true
+    },
+    "create-hash": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
+      "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=",
+      "dev": true
+    },
+    "create-hmac": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz",
+      "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=",
+      "dev": true
+    },
+    "crypto-browserify": {
+      "version": "3.11.1",
+      "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.1.tgz",
+      "integrity": "sha512-Na7ZlwCOqoaW5RwUK1WpXws2kv8mNhWdTlzob0UXulk6G9BDbyiJaGTYBIX61Ozn9l1EPPJpICZb4DaOpT9NlQ==",
+      "dev": true
+    },
+    "d": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
+      "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
+      "dev": true
+    },
+    "date-now": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+      "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
+      "dev": true
+    },
+    "debug": {
+      "version": "2.6.8",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+      "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
+      "dev": true
+    },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+      "dev": true
+    },
+    "deep-is": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+      "dev": true
+    },
+    "defined": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+      "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
+      "dev": true
+    },
+    "del": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
+      "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
+      "dev": true
+    },
+    "deps-sort": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz",
+      "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=",
+      "dev": true
+    },
+    "derequire": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/derequire/-/derequire-2.0.6.tgz",
+      "integrity": "sha1-MaQUu3yhdiOfp4sRZjbvd9UX52g=",
+      "dev": true
+    },
+    "des.js": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz",
+      "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=",
+      "dev": true
+    },
+    "detective": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/detective/-/detective-4.5.0.tgz",
+      "integrity": "sha1-blqMaybmx6JUsca210kNmOyR7dE=",
+      "dev": true
+    },
+    "diffie-hellman": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz",
+      "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=",
+      "dev": true
+    },
+    "doctrine": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz",
+      "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=",
+      "dev": true
+    },
+    "domain-browser": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz",
+      "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=",
+      "dev": true
+    },
+    "duplexer2": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+      "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
+      "dev": true
+    },
+    "elliptic": {
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz",
+      "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=",
+      "dev": true
+    },
+    "error-ex": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz",
+      "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=",
+      "dev": true
+    },
+    "es5-ext": {
+      "version": "0.10.24",
+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.24.tgz",
+      "integrity": "sha1-pVh3yZJLwMjZvTwsvhdJWsFwmxQ=",
+      "dev": true
+    },
+    "es6-iterator": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz",
+      "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=",
+      "dev": true
+    },
+    "es6-map": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz",
+      "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
+      "dev": true
+    },
+    "es6-promise": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
+      "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM="
+    },
+    "es6-set": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
+      "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
+      "dev": true
+    },
+    "es6-symbol": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
+      "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
+      "dev": true
+    },
+    "es6-weak-map": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
+      "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
+      "dev": true
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "dev": true
+    },
+    "escope": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
+      "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=",
+      "dev": true
+    },
+    "eslint": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.2.0.tgz",
+      "integrity": "sha1-orMYQRGxmOAunH88ymJaXgHFaz0=",
+      "dev": true,
+      "dependencies": {
+        "concat-stream": {
+          "version": "1.6.0",
+          "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz",
+          "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=",
+          "dev": true
+        },
+        "json-stable-stringify": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
+          "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
+          "dev": true
+        }
+      }
+    },
+    "eslint-config-google": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.9.1.tgz",
+      "integrity": "sha512-5A83D+lH0PA81QMESKbLJd/a3ic8tPZtwUmqNrxMRo54nfFaUvtt89q/+icQ+fd66c2xQHn0KyFkzJDoAUfpZA==",
+      "dev": true
+    },
+    "eslint-scope": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
+      "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
+      "dev": true
+    },
+    "espree": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz",
+      "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=",
+      "dev": true,
+      "dependencies": {
+        "acorn": {
+          "version": "5.1.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz",
+          "integrity": "sha512-vOk6uEMctu0vQrvuSqFdJyqj1Q0S5VTDL79qtjo+DhRr+1mmaD+tluFSCZqhvi/JUhXSzoZN2BhtstaPEeE8cw==",
+          "dev": true
+        }
+      }
+    },
+    "esprima": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
+      "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==",
+      "dev": true
+    },
+    "esquery": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz",
+      "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=",
+      "dev": true
+    },
+    "esrecurse": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz",
+      "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=",
+      "dev": true
+    },
+    "estraverse": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+      "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+      "dev": true
+    },
+    "esutils": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+      "dev": true
+    },
+    "event-emitter": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
+      "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
+      "dev": true
+    },
+    "eventemitter3": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz",
+      "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg="
+    },
+    "events": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
+      "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
+      "dev": true
+    },
+    "evp_bytestokey": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz",
+      "integrity": "sha1-SXtmrZ/vZc18CKYYCCS6FHa2blM=",
+      "dev": true
+    },
+    "expand-brackets": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+      "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+      "dev": true
+    },
+    "expand-range": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+      "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+      "dev": true
+    },
+    "external-editor": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.4.tgz",
+      "integrity": "sha1-HtkZnanL/i7y96MbL96LDRI2iXI=",
+      "dev": true
+    },
+    "extglob": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+      "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+      "dev": true
+    },
+    "fast-deep-equal": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",
+      "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=",
+      "dev": true
+    },
+    "fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+      "dev": true
+    },
+    "figures": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+      "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+      "dev": true
+    },
+    "file-entry-cache": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
+      "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
+      "dev": true
+    },
+    "filename-regex": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+      "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+      "dev": true
+    },
+    "fill-range": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
+      "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=",
+      "dev": true
+    },
+    "find-up": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+      "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+      "dev": true
+    },
+    "flat-cache": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz",
+      "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=",
+      "dev": true
+    },
+    "for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+      "dev": true
+    },
+    "for-own": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+      "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+      "dev": true
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "fsevents": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz",
+      "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "abbrev": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "ajv": {
+          "version": "4.11.8",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "ansi-regex": {
+          "version": "2.1.1",
+          "bundled": true,
+          "dev": true
+        },
+        "aproba": {
+          "version": "1.1.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "are-we-there-yet": {
+          "version": "1.1.4",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "asn1": {
+          "version": "0.2.3",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "assert-plus": {
+          "version": "0.2.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "asynckit": {
+          "version": "0.4.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "aws-sign2": {
+          "version": "0.6.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "aws4": {
+          "version": "1.6.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "balanced-match": {
+          "version": "0.4.2",
+          "bundled": true,
+          "dev": true
+        },
+        "bcrypt-pbkdf": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "block-stream": {
+          "version": "0.0.9",
+          "bundled": true,
+          "dev": true
+        },
+        "boom": {
+          "version": "2.10.1",
+          "bundled": true,
+          "dev": true
+        },
+        "brace-expansion": {
+          "version": "1.1.7",
+          "bundled": true,
+          "dev": true
+        },
+        "buffer-shims": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "caseless": {
+          "version": "0.12.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "co": {
+          "version": "4.6.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "code-point-at": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true
+        },
+        "combined-stream": {
+          "version": "1.0.5",
+          "bundled": true,
+          "dev": true
+        },
+        "concat-map": {
+          "version": "0.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "console-control-strings": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true
+        },
+        "core-util-is": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true
+        },
+        "cryptiles": {
+          "version": "2.0.5",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "dashdash": {
+          "version": "1.14.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "dependencies": {
+            "assert-plus": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "optional": true
+            }
+          }
+        },
+        "debug": {
+          "version": "2.6.8",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "deep-extend": {
+          "version": "0.4.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "delayed-stream": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "delegates": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "ecc-jsbn": {
+          "version": "0.1.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "extend": {
+          "version": "3.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "extsprintf": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true
+        },
+        "forever-agent": {
+          "version": "0.6.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "form-data": {
+          "version": "2.1.4",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "fs.realpath": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "fstream": {
+          "version": "1.0.11",
+          "bundled": true,
+          "dev": true
+        },
+        "fstream-ignore": {
+          "version": "1.0.5",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "gauge": {
+          "version": "2.7.4",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "getpass": {
+          "version": "0.1.7",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "dependencies": {
+            "assert-plus": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "optional": true
+            }
+          }
+        },
+        "glob": {
+          "version": "7.1.2",
+          "bundled": true,
+          "dev": true
+        },
+        "graceful-fs": {
+          "version": "4.1.11",
+          "bundled": true,
+          "dev": true
+        },
+        "har-schema": {
+          "version": "1.0.5",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "har-validator": {
+          "version": "4.2.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "has-unicode": {
+          "version": "2.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "hawk": {
+          "version": "3.1.3",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "hoek": {
+          "version": "2.16.3",
+          "bundled": true,
+          "dev": true
+        },
+        "http-signature": {
+          "version": "1.1.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "inflight": {
+          "version": "1.0.6",
+          "bundled": true,
+          "dev": true
+        },
+        "inherits": {
+          "version": "2.0.3",
+          "bundled": true,
+          "dev": true
+        },
+        "ini": {
+          "version": "1.3.4",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "is-typedarray": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true
+        },
+        "isstream": {
+          "version": "0.1.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "jodid25519": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "jsbn": {
+          "version": "0.1.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "json-schema": {
+          "version": "0.2.3",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "json-stable-stringify": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "json-stringify-safe": {
+          "version": "5.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "jsonify": {
+          "version": "0.0.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "jsprim": {
+          "version": "1.4.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "dependencies": {
+            "assert-plus": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "optional": true
+            }
+          }
+        },
+        "mime-db": {
+          "version": "1.27.0",
+          "bundled": true,
+          "dev": true
+        },
+        "mime-types": {
+          "version": "2.1.15",
+          "bundled": true,
+          "dev": true
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "bundled": true,
+          "dev": true
+        },
+        "minimist": {
+          "version": "0.0.8",
+          "bundled": true,
+          "dev": true
+        },
+        "mkdirp": {
+          "version": "0.5.1",
+          "bundled": true,
+          "dev": true
+        },
+        "ms": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "node-pre-gyp": {
+          "version": "0.6.36",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "nopt": {
+          "version": "4.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "npmlog": {
+          "version": "4.1.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "number-is-nan": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "oauth-sign": {
+          "version": "0.8.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "object-assign": {
+          "version": "4.1.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "once": {
+          "version": "1.4.0",
+          "bundled": true,
+          "dev": true
+        },
+        "os-homedir": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "os-tmpdir": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "osenv": {
+          "version": "0.1.4",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "path-is-absolute": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "performance-now": {
+          "version": "0.2.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "process-nextick-args": {
+          "version": "1.0.7",
+          "bundled": true,
+          "dev": true
+        },
+        "punycode": {
+          "version": "1.4.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "qs": {
+          "version": "6.4.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "rc": {
+          "version": "1.2.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "dependencies": {
+            "minimist": {
+              "version": "1.2.0",
+              "bundled": true,
+              "dev": true,
+              "optional": true
+            }
+          }
+        },
+        "readable-stream": {
+          "version": "2.2.9",
+          "bundled": true,
+          "dev": true
+        },
+        "request": {
+          "version": "2.81.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "rimraf": {
+          "version": "2.6.1",
+          "bundled": true,
+          "dev": true
+        },
+        "safe-buffer": {
+          "version": "5.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "semver": {
+          "version": "5.3.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "set-blocking": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "signal-exit": {
+          "version": "3.0.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "sntp": {
+          "version": "1.0.9",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "sshpk": {
+          "version": "1.13.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "dependencies": {
+            "assert-plus": {
+              "version": "1.0.0",
+              "bundled": true,
+              "dev": true,
+              "optional": true
+            }
+          }
+        },
+        "string_decoder": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true
+        },
+        "stringstream": {
+          "version": "0.0.5",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "strip-ansi": {
+          "version": "3.0.1",
+          "bundled": true,
+          "dev": true
+        },
+        "strip-json-comments": {
+          "version": "2.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "tar": {
+          "version": "2.2.1",
+          "bundled": true,
+          "dev": true
+        },
+        "tar-pack": {
+          "version": "3.4.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "tough-cookie": {
+          "version": "2.3.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "tunnel-agent": {
+          "version": "0.6.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "tweetnacl": {
+          "version": "0.14.5",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "uid-number": {
+          "version": "0.0.6",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "util-deprecate": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true
+        },
+        "uuid": {
+          "version": "3.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "verror": {
+          "version": "1.3.6",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "wide-align": {
+          "version": "1.1.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "wrappy": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true
+        }
+      }
+    },
+    "function-bind": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz",
+      "integrity": "sha1-FhdnFMgBeY5Ojyz391KUZ7tKV3E=",
+      "dev": true
+    },
+    "get-caller-file": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz",
+      "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=",
+      "dev": true
+    },
+    "glob": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+      "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+      "dev": true
+    },
+    "glob-base": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+      "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+      "dev": true
+    },
+    "glob-parent": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+      "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+      "dev": true
+    },
+    "globals": {
+      "version": "9.18.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+      "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
+      "dev": true
+    },
+    "globby": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
+      "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
+      "dev": true
+    },
+    "graceful-fs": {
+      "version": "4.1.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+      "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
+      "dev": true
+    },
+    "graceful-readlink": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+      "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
+      "dev": true
+    },
+    "has": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz",
+      "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=",
+      "dev": true
+    },
+    "has-ansi": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+      "dev": true
+    },
+    "has-flag": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+      "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
+      "dev": true
+    },
+    "hash-base": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz",
+      "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=",
+      "dev": true
+    },
+    "hash.js": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
+      "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
+      "dev": true
+    },
+    "hmac-drbg": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+      "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+      "dev": true
+    },
+    "hosted-git-info": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",
+      "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==",
+      "dev": true
+    },
+    "htmlescape": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz",
+      "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=",
+      "dev": true
+    },
+    "https-browserify": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz",
+      "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=",
+      "dev": true
+    },
+    "iconv-lite": {
+      "version": "0.4.18",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz",
+      "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==",
+      "dev": true
+    },
+    "ieee754": {
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
+      "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=",
+      "dev": true
+    },
+    "ignore": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz",
+      "integrity": "sha1-QyNS5XrM2HqzEQ6C0/6g5HgSFW0=",
+      "dev": true
+    },
+    "imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+      "dev": true
+    },
+    "indexof": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
+      "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
+      "dev": true
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true
+    },
+    "inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+      "dev": true
+    },
+    "inline-source-map": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz",
+      "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=",
+      "dev": true
+    },
+    "inquirer": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.2.0.tgz",
+      "integrity": "sha512-4CyUYMP7lOBkiUU1rR24WGrfRX6SucwbY2Mqb1PdApU24wnTIk4TsnkQwV72dDdIKZ2ycLP+fWCV+tA7wwgoew==",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.1.0.tgz",
+          "integrity": "sha1-CcIC1ckX7CMYjKpcnLkXnNlUd1A=",
+          "dev": true
+        },
+        "chalk": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.0.1.tgz",
+          "integrity": "sha512-Mp+FXEI+FrwY/XYV45b2YD3E8i3HwnEAoFcM0qlZzq/RZ9RwWitt2Y/c7cqRAz70U7hfekqx6qNYthuKFO6K0g==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+          "dev": true
+        },
+        "string-width": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz",
+          "integrity": "sha1-AwZkVh/BRslCPsfZeP4kV0N/5tA=",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.0.tgz",
+          "integrity": "sha512-Ts0Mu/A1S1aZxEJNG88I4Oc9rcZSBFNac5e27yh4j2mqbhZSSzR1Ah79EYwSn9Zuh7lrlGD2cVGzw1RKGzyLSg==",
+          "dev": true
+        }
+      }
+    },
+    "insert-module-globals": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.0.1.tgz",
+      "integrity": "sha1-wDv04BywhtW15azorQr+eInWOMM=",
+      "dev": true
+    },
+    "invert-kv": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+      "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
+      "dev": true
+    },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+      "dev": true
+    },
+    "is-binary-path": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+      "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+      "dev": true
+    },
+    "is-buffer": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz",
+      "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=",
+      "dev": true
+    },
+    "is-builtin-module": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
+      "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
+      "dev": true
+    },
+    "is-dotfile": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+      "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+      "dev": true
+    },
+    "is-equal-shallow": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+      "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+      "dev": true
+    },
+    "is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+      "dev": true
+    },
+    "is-extglob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+      "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+      "dev": true
+    },
+    "is-fullwidth-code-point": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+      "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+      "dev": true
+    },
+    "is-glob": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+      "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+      "dev": true
+    },
+    "is-number": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+      "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+      "dev": true
+    },
+    "is-path-cwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
+      "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
+      "dev": true
+    },
+    "is-path-in-cwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz",
+      "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=",
+      "dev": true
+    },
+    "is-path-inside": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz",
+      "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=",
+      "dev": true
+    },
+    "is-posix-bracket": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+      "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+      "dev": true
+    },
+    "is-primitive": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+      "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+      "dev": true
+    },
+    "is-promise": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+      "dev": true
+    },
+    "is-resolvable": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz",
+      "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=",
+      "dev": true
+    },
+    "is-utf8": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+      "dev": true
+    },
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
+    },
+    "isobject": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+      "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+      "dev": true
+    },
+    "js-tokens": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+      "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+      "dev": true
+    },
+    "js-yaml": {
+      "version": "3.9.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.9.0.tgz",
+      "integrity": "sha512-0LoUNELX4S+iofCT8f4uEHIiRBR+c2AINyC8qRWfC6QNruLtxVZRJaPcu/xwMgFIgDxF25tGHaDjvxzJCNE9yw==",
+      "dev": true
+    },
+    "jschardet": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.4.2.tgz",
+      "integrity": "sha1-KqEH8UKvQSHRRWWdRPUIMJYeaZo=",
+      "dev": true
+    },
+    "json-schema-traverse": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
+      "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
+      "dev": true
+    },
+    "json-stable-stringify": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz",
+      "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=",
+      "dev": true
+    },
+    "jsonify": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+      "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
+      "dev": true
+    },
+    "jsonparse": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+      "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
+      "dev": true
+    },
+    "JSONStream": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz",
+      "integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=",
+      "dev": true
+    },
+    "kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+      "dev": true
+    },
+    "labeled-stream-splicer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz",
+      "integrity": "sha1-pS4dE4AkwAuGscDJH2d5GLiuClk=",
+      "dev": true,
+      "dependencies": {
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+          "dev": true
+        }
+      }
+    },
+    "lcid": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+      "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
+      "dev": true
+    },
+    "levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+      "dev": true
+    },
+    "lexical-scope": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz",
+      "integrity": "sha1-/Ope3HBKSzqHls3KQZw6CvryLfQ=",
+      "dev": true
+    },
+    "load-json-file": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+      "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+      "dev": true
+    },
+    "lodash": {
+      "version": "4.17.4",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
+      "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
+      "dev": true
+    },
+    "lodash.memoize": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
+      "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=",
+      "dev": true
+    },
+    "micromatch": {
+      "version": "2.3.11",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+      "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+      "dev": true
+    },
+    "miller-rabin": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.0.tgz",
+      "integrity": "sha1-SmL7HUKTPAVYOYL0xxb2+55sbT0=",
+      "dev": true
+    },
+    "mimic-fn": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz",
+      "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=",
+      "dev": true
+    },
+    "minimalistic-assert": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
+      "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=",
+      "dev": true
+    },
+    "minimalistic-crypto-utils": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+      "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
+      "dev": true
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true
+    },
+    "minimist": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+      "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+      "dev": true
+    },
+    "mkdirp": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "dev": true,
+      "dependencies": {
+        "minimist": {
+          "version": "0.0.8",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+          "dev": true
+        }
+      }
+    },
+    "module-deps": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-4.1.1.tgz",
+      "integrity": "sha1-IyFYM/HaE/1gbMuAh7RIUty4If0=",
+      "dev": true
+    },
+    "ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "mute-stream": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
+      "dev": true
+    },
+    "nan": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz",
+      "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=",
+      "dev": true,
+      "optional": true
+    },
+    "natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+      "dev": true
+    },
+    "normalize-package-data": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+      "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
+      "dev": true
+    },
+    "normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+      "dev": true
+    },
+    "number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+      "dev": true
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+      "dev": true
+    },
+    "object.omit": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+      "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+      "dev": true
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true
+    },
+    "onetime": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+      "dev": true
+    },
+    "optionator": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+      "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+      "dev": true
+    },
+    "os-browserify": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.1.2.tgz",
+      "integrity": "sha1-ScoCk+CxlZCl9d4Qx/JlphfY/lQ=",
+      "dev": true
+    },
+    "os-locale": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+      "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+      "dev": true
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+      "dev": true
+    },
+    "outpipe": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz",
+      "integrity": "sha1-UM+GFjZeh+Ax4ppeyTOaPaRyX6I=",
+      "dev": true
+    },
+    "pako": {
+      "version": "0.2.9",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
+      "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=",
+      "dev": true
+    },
+    "parents": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
+      "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=",
+      "dev": true
+    },
+    "parse-asn1": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz",
+      "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=",
+      "dev": true
+    },
+    "parse-glob": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+      "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+      "dev": true
+    },
+    "parse-json": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+      "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+      "dev": true
+    },
+    "path-browserify": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
+      "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=",
+      "dev": true
+    },
+    "path-exists": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+      "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+      "dev": true
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true
+    },
+    "path-is-inside": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+      "dev": true
+    },
+    "path-parse": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
+      "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
+      "dev": true
+    },
+    "path-platform": {
+      "version": "0.11.15",
+      "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz",
+      "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=",
+      "dev": true
+    },
+    "path-type": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+      "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+      "dev": true
+    },
+    "pbkdf2": {
+      "version": "3.0.12",
+      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.12.tgz",
+      "integrity": "sha1-vjZ4XFBn6kjYBv+SMojF91C2uKI=",
+      "dev": true
+    },
+    "pify": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+      "dev": true
+    },
+    "pinkie": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+      "dev": true
+    },
+    "pinkie-promise": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "dev": true
+    },
+    "pluralize": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-4.0.0.tgz",
+      "integrity": "sha1-WbcIwcAZCi9pLxx2GMRGsFL9F2I=",
+      "dev": true
+    },
+    "prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+      "dev": true
+    },
+    "preserve": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+      "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+      "dev": true
+    },
+    "process": {
+      "version": "0.11.10",
+      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+      "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
+      "dev": true
+    },
+    "process-nextick-args": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+      "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
+      "dev": true
+    },
+    "progress": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz",
+      "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=",
+      "dev": true
+    },
+    "public-encrypt": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz",
+      "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=",
+      "dev": true
+    },
+    "punycode": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+      "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+      "dev": true
+    },
+    "querystring": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+      "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
+      "dev": true
+    },
+    "querystring-es3": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+      "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
+      "dev": true
+    },
+    "randomatic": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
+      "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==",
+      "dev": true,
+      "dependencies": {
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true
+            }
+          }
+        },
+        "kind-of": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+          "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+          "dev": true
+        }
+      }
+    },
+    "randombytes": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz",
+      "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==",
+      "dev": true
+    },
+    "read-only-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz",
+      "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=",
+      "dev": true
+    },
+    "read-pkg": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+      "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+      "dev": true
+    },
+    "read-pkg-up": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+      "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+      "dev": true
+    },
+    "readable-stream": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
+      "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
+      "dev": true,
+      "dependencies": {
+        "string_decoder": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+          "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+          "dev": true
+        }
+      }
+    },
+    "readdirp": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
+      "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=",
+      "dev": true
+    },
+    "regex-cache": {
+      "version": "0.4.3",
+      "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz",
+      "integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=",
+      "dev": true
+    },
+    "remove-trailing-separator": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz",
+      "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=",
+      "dev": true
+    },
+    "repeat-element": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
+      "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
+      "dev": true
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+      "dev": true
+    },
+    "require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+      "dev": true
+    },
+    "require-main-filename": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+      "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+      "dev": true
+    },
+    "require-uncached": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
+      "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
+      "dev": true
+    },
+    "resolve": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz",
+      "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=",
+      "dev": true
+    },
+    "resolve-from": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
+      "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
+      "dev": true
+    },
+    "restore-cursor": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+      "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+      "dev": true
+    },
+    "rimraf": {
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz",
+      "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=",
+      "dev": true
+    },
+    "ripemd160": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
+      "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=",
+      "dev": true
+    },
+    "rollup": {
+      "version": "0.37.2",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.37.2.tgz",
+      "integrity": "sha1-zBWdIKLzYVzMIkikOFqsuz1tYEI=",
+      "dev": true
+    },
+    "run-async": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+      "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+      "dev": true
+    },
+    "rx-lite": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
+      "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=",
+      "dev": true
+    },
+    "rx-lite-aggregates": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
+      "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
+      "dev": true
+    },
+    "safe-buffer": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+      "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
+      "dev": true
+    },
+    "semver": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+      "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
+      "dev": true
+    },
+    "set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+      "dev": true
+    },
+    "set-immediate-shim": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
+      "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
+      "dev": true
+    },
+    "sha.js": {
+      "version": "2.4.8",
+      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.8.tgz",
+      "integrity": "sha1-NwaMLEdra69ALRSknGf1l5IfY08=",
+      "dev": true
+    },
+    "shaka-player": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/shaka-player/-/shaka-player-2.1.4.tgz",
+      "integrity": "sha1-3uXDOLfwgnpkfOLATJ3sJioDt9Y="
+    },
+    "shasum": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz",
+      "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=",
+      "dev": true
+    },
+    "shell-quote": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
+      "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=",
+      "dev": true
+    },
+    "signal-exit": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+      "dev": true
+    },
+    "slice-ansi": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
+      "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=",
+      "dev": true
+    },
+    "source-map": {
+      "version": "0.5.6",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
+      "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=",
+      "dev": true
+    },
+    "source-map-support": {
+      "version": "0.4.15",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz",
+      "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=",
+      "dev": true
+    },
+    "spdx-correct": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz",
+      "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=",
+      "dev": true
+    },
+    "spdx-expression-parse": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz",
+      "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=",
+      "dev": true
+    },
+    "spdx-license-ids": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz",
+      "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=",
+      "dev": true
+    },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+      "dev": true
+    },
+    "stats-js": {
+      "version": "1.0.0-alpha1",
+      "resolved": "https://registry.npmjs.org/stats-js/-/stats-js-1.0.0-alpha1.tgz",
+      "integrity": "sha1-RK6C5kIRI7q5l1DZXD9VJrjyV9s="
+    },
+    "stream-browserify": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
+      "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=",
+      "dev": true
+    },
+    "stream-combiner2": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz",
+      "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=",
+      "dev": true
+    },
+    "stream-http": {
+      "version": "2.7.2",
+      "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz",
+      "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==",
+      "dev": true
+    },
+    "stream-splicer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz",
+      "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=",
+      "dev": true
+    },
+    "string_decoder": {
+      "version": "0.10.31",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+      "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+      "dev": true
+    },
+    "string-width": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+      "dev": true
+    },
+    "strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+      "dev": true
+    },
+    "strip-bom": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+      "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+      "dev": true
+    },
+    "strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+      "dev": true
+    },
+    "subarg": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
+      "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=",
+      "dev": true
+    },
+    "supports-color": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+      "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+      "dev": true
+    },
+    "syntax-error": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.3.0.tgz",
+      "integrity": "sha1-HtkmbE1AvnXcVb+bsct3Biu5bKE=",
+      "dev": true
+    },
+    "table": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/table/-/table-4.0.1.tgz",
+      "integrity": "sha1-qBFsEz+sLGH0pCCrbN9cTWHw5DU=",
+      "dev": true,
+      "dependencies": {
+        "ajv": {
+          "version": "4.11.8",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
+          "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
+          "dev": true
+        },
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+          "dev": true
+        },
+        "json-stable-stringify": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
+          "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
+          "dev": true
+        },
+        "string-width": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz",
+          "integrity": "sha1-AwZkVh/BRslCPsfZeP4kV0N/5tA=",
+          "dev": true
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "dev": true
+        }
+      }
+    },
+    "text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+      "dev": true
+    },
+    "three": {
+      "version": "0.84.0",
+      "resolved": "https://registry.npmjs.org/three/-/three-0.84.0.tgz",
+      "integrity": "sha1-lb6FpVoPoAKqYl7VWRMJV9z/2Rg="
+    },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+      "dev": true
+    },
+    "through2": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+      "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
+      "dev": true
+    },
+    "timers-browserify": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz",
+      "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=",
+      "dev": true
+    },
+    "tmp": {
+      "version": "0.0.31",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz",
+      "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=",
+      "dev": true
+    },
+    "to-arraybuffer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+      "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
+      "dev": true
+    },
+    "tryit": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz",
+      "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=",
+      "dev": true
+    },
+    "tty-browserify": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
+      "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
+      "dev": true
+    },
+    "type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+      "dev": true
+    },
+    "typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+      "dev": true
+    },
+    "uglify-es": {
+      "version": "3.0.24",
+      "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.0.24.tgz",
+      "integrity": "sha512-5BfuaLWF0idSXopD0iAK6osMvyo1jEyuQ8MtSpOdLvqUDjlfDDf18qEyz3M7athqorybUuAoKpKW1DhFIhxP2w==",
+      "dev": true
+    },
+    "umd": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.1.tgz",
+      "integrity": "sha1-iuVW4RAR9jwllnCKiDclnwGz1g4=",
+      "dev": true
+    },
+    "urijs": {
+      "version": "1.18.10",
+      "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.18.10.tgz",
+      "integrity": "sha1-uURj6rpZoaeWA2pGe7YzxmfyIas="
+    },
+    "url": {
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+      "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+      "dev": true,
+      "dependencies": {
+        "punycode": {
+          "version": "1.3.2",
+          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+          "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
+          "dev": true
+        }
+      }
+    },
+    "util": {
+      "version": "0.10.3",
+      "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+      "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+      "dev": true,
+      "dependencies": {
+        "inherits": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+          "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
+          "dev": true
+        }
+      }
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
+    "validate-npm-package-license": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
+      "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=",
+      "dev": true
+    },
+    "vm-browserify": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
+      "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=",
+      "dev": true
+    },
+    "watchify": {
+      "version": "3.9.0",
+      "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.9.0.tgz",
+      "integrity": "sha1-8HX9LoqGrN6Eztum5cKgvt1SPZ4=",
+      "dev": true,
+      "dependencies": {
+        "browserify": {
+          "version": "14.4.0",
+          "resolved": "https://registry.npmjs.org/browserify/-/browserify-14.4.0.tgz",
+          "integrity": "sha1-CJo0Y69Y0OSNjNQHCz90ZU1avKk=",
+          "dev": true
+        },
+        "buffer": {
+          "version": "5.0.6",
+          "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.0.6.tgz",
+          "integrity": "sha1-LqZp9+7Atu2gWwj4tf9mGyhXNYg=",
+          "dev": true
+        },
+        "https-browserify": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+          "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
+          "dev": true
+        },
+        "string_decoder": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+          "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+          "dev": true
+        }
+      }
+    },
+    "webvr-boilerplate": {
+      "version": "0.4.9",
+      "resolved": "https://registry.npmjs.org/webvr-boilerplate/-/webvr-boilerplate-0.4.9.tgz",
+      "integrity": "sha1-AeEiuUoSh0n7eIyMLh6fv7Kt5Mk="
+    },
+    "webvr-polyfill": {
+      "version": "0.9.35",
+      "resolved": "https://registry.npmjs.org/webvr-polyfill/-/webvr-polyfill-0.9.35.tgz",
+      "integrity": "sha1-V0DX70HwEjTAUc5SmNGLh6UyEC8="
+    },
+    "which-module": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
+      "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
+      "dev": true
+    },
+    "wordwrap": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+      "dev": true
+    },
+    "wrap-ansi": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+      "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+      "dev": true
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
+    },
+    "write": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
+      "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
+      "dev": true
+    },
+    "xtend": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+      "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
+      "dev": true
+    },
+    "y18n": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+      "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
+      "dev": true
+    },
+    "yargs": {
+      "version": "6.6.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz",
+      "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=",
+      "dev": true
+    },
+    "yargs-parser": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz",
+      "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=",
+      "dev": true
+    }
+  }
+}

+ 56 - 0
app/Resources/public/assets/vrview/package.json

@@ -0,0 +1,56 @@
+{
+  "name": "vrview",
+  "version": "2.0.2",
+  "description": "Embed VR content into your webpage.",
+  "main": "index.js",
+  "dependencies": {
+    "@tweenjs/tween.js": "^16.8.0",
+    "es6-promise": "^3.0.2",
+    "eventemitter3": "^1.2.0",
+    "lodash": "^4.17.5",
+    "shaka-player": "^2.0.0",
+    "stats-js": "^1.0.0-alpha1",
+    "three": "^0.84.0",
+    "urijs": "^1.18.2",
+    "webvr-boilerplate": "^0.4.6",
+    "webvr-polyfill": "^0.9.38"
+  },
+  "devDependencies": {
+    "browserify": "^13.1.1",
+    "debug": "^2.6.9",
+    "derequire": "^2.0.6",
+    "eslint": "^4.2.0",
+    "eslint-config-google": "^0.9.1",
+    "rollup": "^0.37.2",
+    "uglify-es": "^3.0.24",
+    "watchify": "^3.8.0"
+  },
+  "scripts": {
+    "_mkdir": "mkdir -p build",
+    "build-min": "npm run _mkdir && browserify src/embed/main.js | derequire | uglifyjs -c > build/embed.min.js && npm run build-three-closure",
+    "build-dev": "npm run _mkdir && browserify src/embed/main.js | derequire > build/embed.js && npm run build-three-closure",
+    "build-analytics-min": "npm run _mkdir && browserify src/embed/with-analytics.js | derequire | uglifyjs -c > build/embed.min.js && npm run build-three-closure",
+    "build-analytics-dev": "npm run _mkdir && browserify src/embed/with-analytics.js | derequire > build/embed.js && npm run build-three-closure",
+    "build-api-min": "npm run _mkdir && browserify --standalone VRView src/api/main.js | derequire | uglifyjs -c > build/vrview.min.js",
+    "build-api-dev": "npm run _mkdir && browserify --standalone VRView src/api/main.js | derequire > build/vrview.js",
+    "build": "npm run build-min; npm run build-dev; npm run build-api",
+    "build-analytics": "npm run build-analytics-min; npm run build-analytics-dev; npm run build-api",
+    "build-api": "npm run build-api-min; npm run build-api-dev",
+    "watch": "npm run _mkdir && watchify src/embed/main.js -v -d -o build/embed.js",
+    "watch-api": "npm run _mkdir && watchify --standalone VRView src/api/main.js -v -d -o build/vrview.js",
+    "build-three-closure": "npm run _mkdir && rollup -c src/third_party/three/rollup.config.js && java -jar src/third_party/three/closure-compiler-v20160713.jar --warning_level=VERBOSE --jscomp_off=globalThis --jscomp_off=checkTypes --externs src/third_party/three/externs.js --language_in=ECMASCRIPT5_STRICT --js build/three.js --js_output_file build/three.min.js",
+    "build-dms": "npm run _mkdir && uglifyjs scripts/js/device-motion-sender.js > build/device-motion-sender.min.js",
+    "build-all": "npm run build-analytics; npm run build-three-closure; npm run build-dms",
+    "test": "npm run build"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/google/vrview.git"
+  },
+  "author": "",
+  "license": "Apache-2.0",
+  "bugs": {
+    "url": "https://github.com/google/vrview/issues"
+  },
+  "homepage": "https://github.com/google/vrview#readme"
+}

+ 21 - 0
app/Resources/public/assets/vrview/scripts/acl.txt

@@ -0,0 +1,21 @@
+[
+  {
+    "entity": "allUsers",
+    "role": "READER"
+  },
+  {
+    "email": "smus@google.com",
+    "entity": "user-smus@google.com",
+    "role": "OWNER"
+  },
+  {
+    "email": "bwuest@google.com",
+    "entity": "user-bwuest@google.com",
+    "role": "OWNER"
+  },
+  {
+    "email": "nathanmartz@google.com",
+    "entity": "user-nathanmartz@google.com",
+    "role": "OWNER"
+  }
+]

+ 21 - 0
app/Resources/public/assets/vrview/scripts/deploy-2.0.sh

@@ -0,0 +1,21 @@
+#!/usr/bin/env sh
+#
+# Copyright 2016 Google Inc. All Rights Reserved.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+SCRIPT_DIR=`dirname $BASH_SOURCE`
+
+gsutil cp index-minified.html gs://vrview/2.0/index.html
+gsutil cp -r style.css images/ build/ examples/ gs://vrview/2.0/
+gsutil -m acl set -r $SCRIPT_DIR/acl.txt gs://vrview/2.0/

+ 88 - 0
app/Resources/public/assets/vrview/scripts/js/device-motion-sender.js

@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/**
+ * Sends DeviceMotion events to all embedded VR views via postMessage. Note:
+ * each iframe must have a class 'vrview'.
+ *
+ * This is a workaround for https://bugs.webkit.org/show_bug.cgi?id=150072.
+ */
+function DeviceMotionSender() {
+  // This is an iOS-specific workaround.
+  if (!this.isIOS_()) {
+    return;
+  }
+
+  window.addEventListener('devicemotion', this.onDeviceMotion_.bind(this), false);
+
+  // Find the right iFrame to send data to.
+  this.iframes = document.querySelectorAll('iframe.vrview');
+}
+
+DeviceMotionSender.prototype.onDeviceMotion_ = function(e) {
+  var message = {
+    type: 'DeviceMotion',
+    deviceMotionEvent: this.cloneDeviceMotionEvent_(e)
+  };
+  for (var i = 0; i < this.iframes.length; i++) {
+    // Only send data if we're on iOS and we are dealing with a cross-domain
+    // iframe.
+    var iframe = this.iframes[i];
+    var iframeWindow = iframe.contentWindow;
+    if (this.isCrossDomainIframe_(iframe)) {
+      iframeWindow.postMessage(message, '*');
+    }
+  }
+};
+
+DeviceMotionSender.prototype.cloneDeviceMotionEvent_ = function(e) {
+  return {
+    acceleration: {
+      x: e.acceleration.x,
+      y: e.acceleration.y,
+      z: e.acceleration.z,
+    },
+    accelerationIncludingGravity: {
+      x: e.accelerationIncludingGravity.x,
+      y: e.accelerationIncludingGravity.y,
+      z: e.accelerationIncludingGravity.z,
+    },
+    rotationRate: {
+      alpha: e.rotationRate.alpha,
+      beta: e.rotationRate.beta,
+      gamma: e.rotationRate.gamma,
+    },
+    interval: e.interval
+  };
+};
+
+DeviceMotionSender.prototype.isIOS_ = function() {
+  return /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
+};
+
+// From http://stackoverflow.com/questions/12381334/foolproof-way-to-detect-if-iframe-is-cross-domain.
+DeviceMotionSender.prototype.isCrossDomainIframe_ = function(iframe) {
+  var html = null;
+  try { 
+    var doc = iframe.contentDocument || iframe.contentWindow.document;
+    html = doc.body.innerHTML;
+  } catch (err) {
+  }
+
+  return (html === null);
+};
+
+var dms = new DeviceMotionSender();

+ 2 - 0
app/Resources/public/assets/vrview/src/api/README.md

@@ -0,0 +1,2 @@
+This directory contains all of the JavaScript that is required for the
+VR View JavaScript API.

+ 80 - 0
app/Resources/public/assets/vrview/src/api/iframe-message-sender.js

@@ -0,0 +1,80 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var Message = require('../message');
+
+/**
+ * Sends events to the embedded VR view IFrame via postMessage. Also handles
+ * messages sent back from the IFrame:
+ *
+ *    click: When a hotspot was clicked.
+ *    modechange: When the user changes viewing mode (VR|Fullscreen|etc).
+ */
+function IFrameMessageSender(iframe) {
+  if (!iframe) {
+    console.error('No iframe specified');
+    return;
+  }
+  this.iframe = iframe;
+
+  // On iOS, if the iframe is across domains, also send DeviceMotion data.
+  if (this.isIOS_()) {
+    window.addEventListener('devicemotion', this.onDeviceMotion_.bind(this), false);
+  }
+}
+
+/**
+ * Sends a message to the associated VR View IFrame.
+ */
+IFrameMessageSender.prototype.send = function(message) {
+  var iframeWindow = this.iframe.contentWindow;
+  iframeWindow.postMessage(message, '*');
+};
+
+IFrameMessageSender.prototype.onDeviceMotion_ = function(e) {
+  var message = {
+    type: Message.DEVICE_MOTION,
+    deviceMotionEvent: this.cloneDeviceMotionEvent_(e)
+  };
+
+  this.send(message);
+};
+
+IFrameMessageSender.prototype.cloneDeviceMotionEvent_ = function(e) {
+  return {
+    acceleration: {
+      x: e.acceleration.x,
+      y: e.acceleration.y,
+      z: e.acceleration.z,
+    },
+    accelerationIncludingGravity: {
+      x: e.accelerationIncludingGravity.x,
+      y: e.accelerationIncludingGravity.y,
+      z: e.accelerationIncludingGravity.z,
+    },
+    rotationRate: {
+      alpha: e.rotationRate.alpha,
+      beta: e.rotationRate.beta,
+      gamma: e.rotationRate.gamma,
+    },
+    interval: e.interval,
+    timeStamp: e.timeStamp
+  };
+};
+
+IFrameMessageSender.prototype.isIOS_ = function() {
+  return /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
+};
+
+module.exports = IFrameMessageSender;

+ 22 - 0
app/Resources/public/assets/vrview/src/api/main.js

@@ -0,0 +1,22 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var Player = require('./player');
+
+var VRView = {
+  Player: Player
+};
+
+module.exports = VRView;

+ 316 - 0
app/Resources/public/assets/vrview/src/api/player.js

@@ -0,0 +1,316 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var EventEmitter = require('eventemitter3');
+var IFrameMessageSender = require('./iframe-message-sender');
+var Message = require('../message');
+var Util = require('../util');
+
+// Save the executing script. This will be used to calculate the embed URL.
+var CURRENT_SCRIPT_SRC = Util.getCurrentScript().src;
+var FAKE_FULLSCREEN_CLASS = 'vrview-fake-fullscreen';
+
+/**
+ * Entry point for the VR View JS API.
+ *
+ * Emits the following events:
+ *    ready: When the player is loaded.
+ *    modechange: When the viewing mode changes (normal, fullscreen, VR).
+ *    click (id): When a hotspot is clicked.
+ */
+function Player(selector, contentInfo) {
+  // Create a VR View iframe depending on the parameters.
+  var iframe = this.createIframe_(contentInfo);
+  this.iframe = iframe;
+
+  var parentEl = document.querySelector(selector);
+  parentEl.appendChild(iframe);
+
+  // Make a sender as well, for relying commands to the child IFrame.
+  this.sender = new IFrameMessageSender(iframe);
+
+  // Listen to messages from the IFrame.
+  window.addEventListener('message', this.onMessage_.bind(this), false);
+
+  // Expose a public .isPaused attribute.
+  this.isPaused = false;
+
+  // Expose a public .isMuted attribute.
+  this.isMuted = false;
+  if (typeof contentInfo.muted !== 'undefined') {
+    this.isMuted = contentInfo.muted;
+  }
+
+  // Other public attributes
+  this.currentTime = 0;
+  this.duration = 0;
+  this.volume = contentInfo.volume != undefined ? contentInfo.volume : 1;
+
+  if (Util.isIOS()) {
+    this.injectFullscreenStylesheet_();
+  }
+}
+Player.prototype = new EventEmitter();
+
+/**
+ * @param pitch {Number} The latitude of center, specified in degrees, between
+ * -90 and 90, with 0 at the horizon.
+ * @param yaw {Number} The longitude of center, specified in degrees, between
+ * -180 and 180, with 0 at the image center.
+ * @param radius {Number} The radius of the hotspot, specified in meters.
+ * @param distance {Number} The distance of the hotspot from camera, specified
+ * in meters.
+ * @param hotspotId {String} The ID of the hotspot.
+ */
+Player.prototype.addHotspot = function(hotspotId, params) {
+  // TODO: Add validation to params.
+  var data = {
+    pitch: params.pitch,
+    yaw: params.yaw,
+    radius: params.radius,
+    distance: params.distance,
+    id: hotspotId
+  };
+  this.sender.send({type: Message.ADD_HOTSPOT, data: data});
+};
+
+Player.prototype.play = function() {
+  this.sender.send({type: Message.PLAY});
+};
+
+Player.prototype.pause = function() {
+  this.sender.send({type: Message.PAUSE});
+};
+
+/**
+ * Equivalent of HTML5 setSrc().
+ * @param {String} contentInfo
+ */
+Player.prototype.setContent = function(contentInfo) {
+  this.absolutifyPaths_(contentInfo);
+  var data = {
+    contentInfo: contentInfo
+  };
+  this.sender.send({type: Message.SET_CONTENT, data: data});
+};
+
+/**
+ * Sets the software volume of the video. 0 is mute, 1 is max.
+ */
+Player.prototype.setVolume = function(volumeLevel) {
+  var data = {
+    volumeLevel: volumeLevel
+  };
+  this.sender.send({type: Message.SET_VOLUME, data: data});
+};
+
+Player.prototype.getVolume = function() {
+  return this.volume;
+};
+
+/**
+ * Sets the mute state of the video element. true is muted, false is unmuted.
+ */
+Player.prototype.mute = function(muteState) {
+  var data = {
+    muteState: muteState
+  };
+  this.sender.send({type: Message.MUTED, data: data});
+};
+
+/**
+ * Set the current time of the media being played
+ * @param {Number} time
+ */
+Player.prototype.setCurrentTime = function(time) {
+  var data = {
+    currentTime: time
+  };
+  this.sender.send({type: Message.SET_CURRENT_TIME, data: data});
+};
+
+Player.prototype.getCurrentTime = function() {
+  return this.currentTime;
+};
+
+Player.prototype.getDuration = function() {
+  return this.duration;
+};
+Player.prototype.setFullscreen = function() {
+  this.sender.send({type: Message.SET_FULLSCREEN});
+};
+
+/**
+ * Helper for creating an iframe.
+ *
+ * @return {IFrameElement} The iframe.
+ */
+Player.prototype.createIframe_ = function(contentInfo) {
+  this.absolutifyPaths_(contentInfo);
+
+  var iframe = document.createElement('iframe');
+  iframe.setAttribute('allowfullscreen', true);
+  iframe.setAttribute('scrolling', 'no');
+  iframe.style.border = 0;
+
+  // Handle iframe size if width and height are specified.
+  if (contentInfo.hasOwnProperty('width')) {
+    iframe.setAttribute('width', contentInfo.width);
+    delete contentInfo.width;
+  }
+  if (contentInfo.hasOwnProperty('height')) {
+    iframe.setAttribute('height', contentInfo.height);
+    delete contentInfo.height;
+  }
+
+  var url = this.getEmbedUrl_() + Util.createGetParams(contentInfo);
+  iframe.src = url;
+
+  return iframe;
+};
+
+Player.prototype.onMessage_ = function(event) {
+  var message = event.data;
+  if (!message || !message.type) {
+    console.warn('Received message with no type.');
+    return;
+  }
+  var type = message.type.toLowerCase();
+  var data = message.data;
+  switch (type) {
+    case 'ready':
+      if (data !== undefined && data.duration !== undefined) {
+        this.duration = data.duration;
+      }
+    case 'modechange':
+    case 'error':
+    case 'click':
+    case 'ended':
+    case 'getposition':
+      this.emit(type, data);
+      break;
+    case 'volumechange':
+      this.volume = data;
+      this.emit('volumechange', data);
+      break;
+    case 'muted':
+      this.isMuted = data;
+      this.emit('mute', data);
+      break;
+    case 'timeupdate':
+      this.currentTime = data;
+      this.emit('timeupdate', {
+        currentTime: this.currentTime,
+        duration: this.duration
+      });
+      break;
+    case 'play':
+    case 'paused':
+      this.isPaused = data;
+      if (this.isPaused) {
+        this.emit('pause', data);
+      } else {
+        this.emit('play', data);
+      }
+      break;
+    case 'enter-fullscreen':
+    case 'enter-vr':
+      this.setFakeFullscreen_(true);
+      break;
+    case 'exit-fullscreen':
+      this.setFakeFullscreen_(false);
+      break;
+    default:
+      console.warn('Got unknown message of type %s from %s', message.type, message.origin);
+  }
+};
+
+/**
+ * Note: iOS doesn't support the fullscreen API.
+ * In standalone <iframe> mode, VR View emulates fullscreen by redirecting to
+ * another page.
+ * In JS API mode, we stretch the iframe to cover the extent of the page using
+ * CSS. To do this cleanly, we also inject a stylesheet.
+ */
+Player.prototype.setFakeFullscreen_ = function(isFullscreen) {
+  if (isFullscreen) {
+    this.iframe.classList.add(FAKE_FULLSCREEN_CLASS);
+  } else {
+    this.iframe.classList.remove(FAKE_FULLSCREEN_CLASS);
+  }
+};
+
+Player.prototype.injectFullscreenStylesheet_ = function() {
+  var styleString = [
+    'iframe.' + FAKE_FULLSCREEN_CLASS,
+    '{',
+      'position: fixed !important;',
+      'display: block !important;',
+      'z-index: 9999999999 !important;',
+      'top: 0 !important;',
+      'left: 0 !important;',
+      'width: 100% !important;',
+      'height: 100% !important;',
+      'margin: 0 !important;',
+    '}',
+  ].join('\n');
+  var style = document.createElement('style');
+  style.innerHTML = styleString;
+  document.body.appendChild(style);
+};
+
+Player.prototype.getEmbedUrl_ = function() {
+  // Assume that the script is in $ROOT/build/something.js, and that the iframe
+  // HTML is in $ROOT/index.html.
+  //
+  // E.g: /vrview/2.0/build/vrview.min.js => /vrview/2.0/index.html.
+  var path = CURRENT_SCRIPT_SRC;
+  var split = path.split('/');
+  var rootSplit = split.slice(0, split.length - 2);
+  var rootPath = rootSplit.join('/');
+  return rootPath + '/index.html';
+};
+
+Player.prototype.getDirName_ = function() {
+  var path = window.location.pathname;
+  path = path.substring(0, path.lastIndexOf('/'));
+  return location.protocol + '//' + location.host + path;
+};
+
+/**
+ * Make all of the URLs inside contentInfo absolute instead of relative.
+ */
+Player.prototype.absolutifyPaths_ = function(contentInfo) {
+  var dirName = this.getDirName_();
+  var urlParams = ['image', 'preview', 'video'];
+
+  for (var i = 0; i < urlParams.length; i++) {
+    var name = urlParams[i];
+    var path = contentInfo[name];
+    if (path && Util.isPathAbsolute(path)) {
+      var absolute = Util.relativeToAbsolutePath(dirName, path);
+      contentInfo[name] = absolute;
+      //console.log('Converted to absolute: %s', absolute);
+    }
+  }
+};
+/**
+ * Get position YAW, PITCH
+ */
+Player.prototype.getPosition = function() {
+    this.sender.send({type: Message.GET_POSITION, data: {}});
+};
+
+module.exports = Player;

+ 147 - 0
app/Resources/public/assets/vrview/src/embed/adaptive-player.js

@@ -0,0 +1,147 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var EventEmitter = require('eventemitter3');
+var shaka = require('shaka-player');
+
+var Types = require('../video-type');
+var Util = require('../util');
+
+var DEFAULT_BITS_PER_SECOND = 1000000;
+
+/**
+ * Supports regular video URLs (eg. mp4), as well as adaptive manifests like
+ * DASH (.mpd) and soon HLS (.m3u8).
+ *
+ * Events:
+ *   load(video): When the video is loaded.
+ *   error(message): If an error occurs.
+ *
+ * To play/pause/seek/etc, please use the underlying video element.
+ */
+function AdaptivePlayer(params) {
+  this.video = document.createElement('video');
+  // Loop by default.
+  if (params.loop === true) {
+    this.video.setAttribute('loop', true);
+  }
+
+  if (params.volume !== undefined) {
+    // XXX: .setAttribute('volume', params.volume) doesn't work for some reason.
+    this.video.volume = params.volume;
+  }
+
+  // Not muted by default.
+  if (params.muted === true) {
+    this.video.muted = params.muted;
+  }
+
+  // For FF, make sure we enable preload.
+  this.video.setAttribute('preload', 'auto');
+  // Enable inline video playback in iOS 10+.
+  this.video.setAttribute('playsinline', true);
+  this.video.setAttribute('crossorigin', 'anonymous');
+}
+AdaptivePlayer.prototype = new EventEmitter();
+
+AdaptivePlayer.prototype.load = function(url) {
+  var self = this;
+  // TODO(smus): Investigate whether or not differentiation is best done by
+  // mimeType after all. Cursory research suggests that adaptive streaming
+  // manifest mime types aren't properly supported.
+  //
+  // For now, make determination based on extension.
+  var extension = Util.getExtension(url);
+  switch (extension) {
+    case 'm3u8': // HLS
+      this.type = Types.HLS;
+      if (Util.isSafari()) {
+        this.loadVideo_(url).then(function() {
+          self.emit('load', self.video, self.type);
+        }).catch(this.onError_.bind(this));
+      } else {
+        self.onError_('HLS is only supported on Safari.');
+      }
+      break;
+    case 'mpd': // MPEG-DASH
+      this.type = Types.DASH;
+      this.loadShakaVideo_(url).then(function() {
+        console.log('The video has now been loaded!');
+        self.emit('load', self.video, self.type);
+      }).catch(this.onError_.bind(this));
+      break;
+    default: // A regular video, not an adaptive manifest.
+      this.type = Types.VIDEO;
+      this.loadVideo_(url).then(function() {
+        self.emit('load', self.video, self.type);
+      }).catch(this.onError_.bind(this));
+      break;
+  }
+};
+
+AdaptivePlayer.prototype.destroy = function() {
+  this.video.pause();
+  this.video.src = '';
+  this.video = null;
+};
+
+/*** PRIVATE API ***/
+
+AdaptivePlayer.prototype.onError_ = function(e) {
+  console.error(e);
+  this.emit('error', e);
+};
+
+AdaptivePlayer.prototype.loadVideo_ = function(url) {
+  var self = this, video = self.video;
+  return new Promise(function(resolve, reject) {
+    video.src = url;
+    video.addEventListener('canplaythrough', resolve);
+    video.addEventListener('loadedmetadata', function() {
+      self.emit('timeupdate', {
+        currentTime: video.currentTime,
+        duration: video.duration
+      });
+    });
+    video.addEventListener('error', reject);
+    video.load();
+  });
+};
+
+AdaptivePlayer.prototype.initShaka_ = function() {
+  this.player = new shaka.Player(this.video);
+
+  this.player.configure({
+    abr: { defaultBandwidthEstimate: DEFAULT_BITS_PER_SECOND }
+  });
+
+  // Listen for error events.
+  this.player.addEventListener('error', this.onError_);
+};
+
+AdaptivePlayer.prototype.loadShakaVideo_ = function(url) {
+  // Install built-in polyfills to patch browser incompatibilities.
+  shaka.polyfill.installAll();
+
+  if (!shaka.Player.isBrowserSupported()) {
+    console.error('Shaka is not supported on this browser.');
+    return;
+  }
+
+  this.initShaka_();
+  return this.player.load(url);
+};
+
+module.exports = AdaptivePlayer;

+ 56 - 0
app/Resources/public/assets/vrview/src/embed/analytics.js

@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function Analytics() {
+  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+      m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+  ga('create', 'UA-35315454-8', 'auto');
+  ga('send', 'pageview');
+
+  this.lastModeChangeTime = window.performance.now();
+  this.lastModeLabel = Analytics.MODE_LABELS[0];
+}
+
+Analytics.MODE_LABELS = {
+  0: 'UNKNOWN',
+  1: 'NORMAL',
+  2: 'MAGIC_WINDOW',
+  3: 'VR'
+};
+
+
+Analytics.prototype.logModeChanged = function(mode) {
+  var modeLabel = Analytics.MODE_LABELS[mode];
+  var lastModeLabel = Analytics.MODE_LABELS[this.lastMode];
+
+  console.log('Analytics: going from mode %s to %s', lastModeLabel, modeLabel);
+
+  ga('send', 'screenview', {
+    appName: 'EmbedVR',
+    screenName: modeLabel
+  });
+
+  var now = window.performance.now();
+  var msSinceLastModeChange = Math.round(now - this.lastModeChangeTime);
+  ga('send', 'timing', 'Time spent in mode', lastModeLabel, msSinceLastModeChange);
+
+  this.lastModeChangeTime = now;
+  this.lastMode = mode;
+}
+
+window.analytics = new Analytics();

+ 20 - 0
app/Resources/public/assets/vrview/src/embed/eyes.js

@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var Eyes = {
+  LEFT: 1,
+  RIGHT: 2
+};
+
+module.exports = Eyes;

+ 403 - 0
app/Resources/public/assets/vrview/src/embed/hotspot-renderer.js

@@ -0,0 +1,403 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var EventEmitter = require('eventemitter3');
+var TWEEN = require('@tweenjs/tween.js');
+
+var Util = require('../util');
+
+// Constants for the focus/blur animation.
+var NORMAL_SCALE = new THREE.Vector3(1, 1, 1);
+var FOCUS_SCALE = new THREE.Vector3(1.2, 1.2, 1.2);
+var FOCUS_DURATION = 200;
+
+// Constants for the active/inactive animation.
+var INACTIVE_COLOR = new THREE.Color(1, 1, 1);
+var ACTIVE_COLOR = new THREE.Color(0.8, 0, 0);
+var ACTIVE_DURATION = 100;
+
+// Constants for opacity.
+var MAX_INNER_OPACITY = 0.8;
+var MAX_OUTER_OPACITY = 0.5;
+var FADE_START_ANGLE_DEG = 35;
+var FADE_END_ANGLE_DEG = 60;
+/**
+ * Responsible for rectangular hot spots that the user can interact with.
+ *
+ * Specific duties:
+ *   Adding and removing hotspots.
+ *   Rendering the hotspots (debug mode only).
+ *   Notifying when hotspots are interacted with.
+ *
+ * Emits the following events:
+ *   click (id): a hotspot is clicked.
+ *   focus (id): a hotspot is focused.
+ *   blur (id): a hotspot is no longer hovered over.
+ */
+function HotspotRenderer(worldRenderer) {
+  this.worldRenderer = worldRenderer;
+  this.scene = worldRenderer.scene;
+
+  // Note: this event must be added to document.body and not to window for it to
+  // work inside iOS iframes.
+  var body = document.body;
+  // Bind events for hotspot interaction.
+  if (!Util.isMobile()) {
+    // Only enable mouse events on desktop.
+    body.addEventListener('mousedown', this.onMouseDown_.bind(this), false);
+    body.addEventListener('mousemove', this.onMouseMove_.bind(this), false);
+    body.addEventListener('mouseup', this.onMouseUp_.bind(this), false);
+  }
+  body.addEventListener('touchstart', this.onTouchStart_.bind(this), false);
+  body.addEventListener('touchend', this.onTouchEnd_.bind(this), false);
+
+  // Add a placeholder for hotspots.
+  this.hotspotRoot = new THREE.Object3D();
+  // Align the center with the center of the camera too.
+  this.hotspotRoot.rotation.y = Math.PI / 2;
+  this.scene.add(this.hotspotRoot);
+
+  // All hotspot IDs.
+  this.hotspots = {};
+
+  // Currently selected hotspots.
+  this.selectedHotspots = {};
+
+  // Hotspots that the last touchstart / mousedown event happened for.
+  this.downHotspots = {};
+
+  // For raycasting. Initialize mouse to be off screen initially.
+  this.pointer = new THREE.Vector2(1, 1);
+  this.raycaster = new THREE.Raycaster();
+}
+HotspotRenderer.prototype = new EventEmitter();
+
+/**
+ * @param pitch {Number} The latitude of center, specified in degrees, between
+ * -90 and 90, with 0 at the horizon.
+ * @param yaw {Number} The longitude of center, specified in degrees, between
+ * -180 and 180, with 0 at the image center.
+ * @param radius {Number} The radius of the hotspot, specified in meters.
+ * @param distance {Number} The distance of the hotspot from camera, specified
+ * in meters.
+ * @param hotspotId {String} The ID of the hotspot.
+ */
+HotspotRenderer.prototype.add = function(pitch, yaw, radius, distance, id) {
+  // If a hotspot already exists with this ID, stop.
+  if (this.hotspots[id]) {
+    // TODO: Proper error reporting.
+    console.error('Attempt to add hotspot with existing id %s.', id);
+    return;
+  }
+  var hotspot = this.createHotspot_(radius, distance);
+  hotspot.name = id;
+
+  // Position the hotspot based on the pitch and yaw specified.
+  var quat = new THREE.Quaternion();
+  quat.setFromEuler(new THREE.Euler(THREE.Math.degToRad(pitch), THREE.Math.degToRad(yaw), 0, 'ZYX'));
+  hotspot.position.applyQuaternion(quat);
+  hotspot.lookAt(new THREE.Vector3());
+
+  this.hotspotRoot.add(hotspot);
+  this.hotspots[id] = hotspot;
+}
+
+/**
+ * Removes a hotspot based on the ID.
+ *
+ * @param ID {String} Identifier of the hotspot to be removed.
+ */
+HotspotRenderer.prototype.remove = function(id) {
+  // If there's no hotspot with this ID, fail.
+  if (!this.hotspots[id]) {
+    // TODO: Proper error reporting.
+    console.error('Attempt to remove non-existing hotspot with id %s.', id);
+    return;
+  }
+  // Remove the mesh from the scene.
+  this.hotspotRoot.remove(this.hotspots[id]);
+
+  // If this hotspot was selected, make sure it gets unselected.
+  delete this.selectedHotspots[id];
+  delete this.downHotspots[id];
+  delete this.hotspots[id];
+  this.emit('blur', id);
+};
+
+/**
+ * Clears all hotspots from the pano. Often called when changing panos.
+ */
+HotspotRenderer.prototype.clearAll = function() {
+  for (var id in this.hotspots) {
+    this.remove(id);
+  }
+};
+
+HotspotRenderer.prototype.getCount = function() {
+  var count = 0;
+  for (var id in this.hotspots) {
+    count += 1;
+  }
+  return count;
+};
+
+HotspotRenderer.prototype.update = function(camera) {
+  if (this.worldRenderer.isVRMode()) {
+    this.pointer.set(0, 0);
+  }
+  // Update the picking ray with the camera and mouse position.
+  this.raycaster.setFromCamera(this.pointer, camera);
+
+  // Fade hotspots out if they are really far from center to avoid overly
+  // distorted visuals.
+  this.fadeOffCenterHotspots_(camera);
+
+  var hotspots = this.hotspotRoot.children;
+
+  // Go through all hotspots to see if they are currently selected.
+  for (var i = 0; i < hotspots.length; i++) {
+    var hotspot = hotspots[i];
+    //hotspot.lookAt(camera.position);
+    var id = hotspot.name;
+    // Check if hotspot is intersected with the picking ray.
+    var intersects = this.raycaster.intersectObjects(hotspot.children);
+    var isIntersected = (intersects.length > 0);
+
+    // If newly selected, emit a focus event.
+    if (isIntersected && !this.selectedHotspots[id]) {
+      this.emit('focus', id);
+      this.focus_(id);
+    }
+    // If no longer selected, emit a blur event.
+    if (!isIntersected && this.selectedHotspots[id]) {
+      this.emit('blur', id);
+      this.blur_(id);
+    }
+    // Update the set of selected hotspots.
+    if (isIntersected) {
+      this.selectedHotspots[id] = true;
+    } else {
+      delete this.selectedHotspots[id];
+    }
+  }
+};
+
+/**
+ * Toggle whether or not hotspots are visible.
+ */
+HotspotRenderer.prototype.setVisibility = function(isVisible) {
+  this.hotspotRoot.visible = isVisible;
+};
+
+HotspotRenderer.prototype.onTouchStart_ = function(e) {
+  // In VR mode, don't touch the pointer position.
+  if (!this.worldRenderer.isVRMode()) {
+    this.updateTouch_(e);
+  }
+
+  // Force a camera update to see if any hotspots were selected.
+  this.update(this.worldRenderer.camera);
+
+  this.downHotspots = {};
+  for (var id in this.selectedHotspots) {
+    this.downHotspots[id] = true;
+    this.down_(id);
+  }
+  return false;
+};
+
+HotspotRenderer.prototype.onTouchEnd_ = function(e) {
+  // If no hotspots are pressed, emit an empty click event.
+  if (Util.isEmptyObject(this.downHotspots)) {
+    this.emit('click');
+    return;
+  }
+
+  // Only emit a click if the finger was down on the same hotspot before.
+  for (var id in this.downHotspots) {
+    this.emit('click', id);
+    this.up_(id);
+    e.preventDefault();
+  }
+};
+
+HotspotRenderer.prototype.updateTouch_ = function(e) {
+  var size = this.getSize_();
+  var touch = e.touches[0];
+	this.pointer.x = (touch.clientX / size.width) * 2 - 1;
+	this.pointer.y = - (touch.clientY / size.height) * 2 + 1;
+};
+
+HotspotRenderer.prototype.onMouseDown_ = function(e) {
+  this.updateMouse_(e);
+
+  this.downHotspots = {};
+  for (var id in this.selectedHotspots) {
+    this.downHotspots[id] = true;
+    this.down_(id);
+  }
+};
+
+HotspotRenderer.prototype.onMouseMove_ = function(e) {
+  this.updateMouse_(e);
+};
+
+HotspotRenderer.prototype.onMouseUp_ = function(e) {
+  this.updateMouse_(e);
+
+  // If no hotspots are pressed, emit an empty click event.
+  if (Util.isEmptyObject(this.downHotspots)) {
+    this.emit('click');
+    return;
+  }
+
+  // Only emit a click if the mouse was down on the same hotspot before.
+  for (var id in this.selectedHotspots) {
+    if (id in this.downHotspots) {
+      this.emit('click', id);
+      this.up_(id);
+    }
+  }
+};
+
+HotspotRenderer.prototype.updateMouse_ = function(e) {
+  var size = this.getSize_();
+	this.pointer.x = (e.clientX / size.width) * 2 - 1;
+	this.pointer.y = - (e.clientY / size.height) * 2 + 1;
+};
+
+HotspotRenderer.prototype.getSize_ = function() {
+  var canvas = this.worldRenderer.renderer.domElement;
+  return this.worldRenderer.renderer.getSize();
+};
+
+HotspotRenderer.prototype.createHotspot_ = function(radius, distance) {
+  var innerGeometry = new THREE.CircleGeometry(radius, 32);
+
+  var innerMaterial = new THREE.MeshBasicMaterial({
+    color: 0xffffff, side: THREE.DoubleSide, transparent: true,
+    opacity: MAX_INNER_OPACITY, depthTest: false
+  });
+
+  var inner = new THREE.Mesh(innerGeometry, innerMaterial);
+  inner.name = 'inner';
+
+  var outerMaterial = new THREE.MeshBasicMaterial({
+    color: 0xffffff, side: THREE.DoubleSide, transparent: true,
+    opacity: MAX_OUTER_OPACITY, depthTest: false
+  });
+  var outerGeometry = new THREE.RingGeometry(radius * 0.85, radius, 32);
+  var outer = new THREE.Mesh(outerGeometry, outerMaterial);
+  outer.name = 'outer';
+
+  // Position at the extreme end of the sphere.
+  var hotspot = new THREE.Object3D();
+  hotspot.position.z = -distance;
+  hotspot.scale.copy(NORMAL_SCALE);
+
+  hotspot.add(inner);
+  hotspot.add(outer);
+
+  return hotspot;
+};
+
+/**
+ * Large aspect ratios tend to cause visually jarring distortions on the sides.
+ * Here we fade hotspots out to avoid them.
+ */
+HotspotRenderer.prototype.fadeOffCenterHotspots_ = function(camera) {
+  var lookAt = new THREE.Vector3(1, 0, 0);
+  lookAt.applyQuaternion(camera.quaternion);
+  // Take into account the camera parent too.
+  lookAt.applyQuaternion(camera.parent.quaternion);
+
+  // Go through each hotspot. Calculate how far off center it is.
+  for (var id in this.hotspots) {
+    var hotspot = this.hotspots[id];
+    var angle = hotspot.position.angleTo(lookAt);
+    var angleDeg = THREE.Math.radToDeg(angle);
+    var isVisible = angleDeg < 45;
+    var opacity;
+    if (angleDeg < FADE_START_ANGLE_DEG) {
+      opacity = 1;
+    } else if (angleDeg > FADE_END_ANGLE_DEG) {
+      opacity = 0;
+    } else {
+      // We are in the case START < angle < END. Linearly interpolate.
+      var range = FADE_END_ANGLE_DEG - FADE_START_ANGLE_DEG;
+      var value = FADE_END_ANGLE_DEG - angleDeg;
+      opacity = value / range;
+    }
+
+    // Opacity a function of angle. If angle is large, opacity is zero. At some
+    // point, ramp opacity down.
+    this.setOpacity_(id, opacity);
+  }
+};
+
+HotspotRenderer.prototype.focus_ = function(id) {
+  var hotspot = this.hotspots[id];
+
+  // Tween scale of hotspot.
+  this.tween = new TWEEN.Tween(hotspot.scale).to(FOCUS_SCALE, FOCUS_DURATION)
+      .easing(TWEEN.Easing.Quadratic.InOut)
+      .start();
+  
+  if (this.worldRenderer.isVRMode()) {
+    this.timeForHospotClick = setTimeout(function () {
+      this.emit('click', id);
+    }, 1200 )
+  }
+};
+
+HotspotRenderer.prototype.blur_ = function(id) {
+  var hotspot = this.hotspots[id];
+
+  this.tween = new TWEEN.Tween(hotspot.scale).to(NORMAL_SCALE, FOCUS_DURATION)
+      .easing(TWEEN.Easing.Quadratic.InOut)
+      .start();
+  
+  if (this.timeForHospotClick) {
+    clearTimeout( this.timeForHospotClick );
+  }
+};
+
+HotspotRenderer.prototype.down_ = function(id) {
+  // Become active.
+  var hotspot = this.hotspots[id];
+  var outer = hotspot.getObjectByName('inner');
+
+  this.tween = new TWEEN.Tween(outer.material.color).to(ACTIVE_COLOR, ACTIVE_DURATION)
+      .start();
+};
+
+HotspotRenderer.prototype.up_ = function(id) {
+  // Become inactive.
+  var hotspot = this.hotspots[id];
+  var outer = hotspot.getObjectByName('inner');
+
+  this.tween = new TWEEN.Tween(outer.material.color).to(INACTIVE_COLOR, ACTIVE_DURATION)
+      .start();
+};
+
+HotspotRenderer.prototype.setOpacity_ = function(id, opacity) {
+  var hotspot = this.hotspots[id];
+  var outer = hotspot.getObjectByName('outer');
+  var inner = hotspot.getObjectByName('inner');
+
+  outer.material.opacity = opacity * MAX_OUTER_OPACITY;
+  inner.material.opacity = opacity * MAX_INNER_OPACITY;
+};
+
+module.exports = HotspotRenderer;

+ 68 - 0
app/Resources/public/assets/vrview/src/embed/iframe-message-receiver.js

@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var EventEmitter = require('eventemitter3');
+var Message = require('../message');
+var Util = require('../util');
+
+
+/**
+ * Sits in an embedded iframe, receiving messages from a containing
+ * iFrame. This facilitates an API which provides the following features:
+ *
+ *    Playing and pausing content.
+ *    Adding hotspots.
+ *    Sending messages back to the containing iframe when hotspot is clicked
+ *    Sending analytics events to containing iframe.
+ *
+ * Note: this script used to also respond to synthetic devicemotion events, but
+ * no longer does so. This is because as of iOS 9.2, Safari disallows listening
+ * for devicemotion events within cross-device iframes. To work around this, the
+ * webvr-polyfill responds to the postMessage event containing devicemotion
+ * information (sent by the iframe-message-sender in the VR View API).
+ */
+function IFrameMessageReceiver() {
+  window.addEventListener('message', this.onMessage_.bind(this), false);
+}
+IFrameMessageReceiver.prototype = new EventEmitter();
+
+IFrameMessageReceiver.prototype.onMessage_ = function(event) {
+  if (Util.isDebug()) {
+    console.log('onMessage_', event);
+  }
+
+  var message = event.data;
+  var type = message.type.toLowerCase();
+  var data = message.data;
+
+  switch (type) {
+    case Message.SET_CONTENT:
+    case Message.SET_VOLUME:
+    case Message.MUTED:
+    case Message.ADD_HOTSPOT:
+    case Message.PLAY:
+    case Message.PAUSE:
+    case Message.SET_CURRENT_TIME:
+    case Message.GET_POSITION:
+    case Message.SET_FULLSCREEN:
+      this.emit(type, data);
+      break;
+    default:
+      if (Util.isDebug()) {
+        console.warn('Got unknown message of type %s from %s', message.type, message.origin);
+      }
+  }
+};
+
+module.exports = IFrameMessageReceiver;

+ 54 - 0
app/Resources/public/assets/vrview/src/embed/loading-indicator.js

@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Shows a 2D loading indicator while various pieces of EmbedVR load.
+ */
+function LoadingIndicator() {
+  this.el = this.build_();
+  document.body.appendChild(this.el);
+  this.show();
+}
+
+LoadingIndicator.prototype.build_ = function() {
+  var overlay = document.createElement('div');
+  var s = overlay.style;
+  s.position = 'fixed';
+  s.top = 0;
+  s.left = 0;
+  s.width = '100%';
+  s.height = '100%';
+  s.background = '#eee';
+  var img = document.createElement('img');
+  img.src = 'images/loading.gif';
+  var s = img.style;
+  s.position = 'absolute';
+  s.top = '50%';
+  s.left = '50%';
+  s.transform = 'translate(-50%, -50%)';
+
+  overlay.appendChild(img);
+  return overlay;
+};
+
+LoadingIndicator.prototype.hide = function() {
+  this.el.style.display = 'none';
+};
+
+LoadingIndicator.prototype.show = function() {
+  this.el.style.display = 'block';
+};
+
+module.exports = LoadingIndicator;

+ 369 - 0
app/Resources/public/assets/vrview/src/embed/main.js

@@ -0,0 +1,369 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Initialize the loading indicator as quickly as possible to give the user
+// immediate feedback.
+var LoadingIndicator = require('./loading-indicator');
+var loadIndicator = new LoadingIndicator();
+
+var ES6Promise = require('es6-promise');
+// Polyfill ES6 promises for IE.
+ES6Promise.polyfill();
+
+var IFrameMessageReceiver = require('./iframe-message-receiver');
+var Message = require('../message');
+var SceneInfo = require('./scene-info');
+var Stats = require('../../node_modules/stats-js/build/stats.min');
+var Util = require('../util');
+var WebVRPolyfill = require('webvr-polyfill');
+var WorldRenderer = require('./world-renderer');
+
+var receiver = new IFrameMessageReceiver();
+receiver.on(Message.PLAY, onPlayRequest);
+receiver.on(Message.PAUSE, onPauseRequest);
+receiver.on(Message.ADD_HOTSPOT, onAddHotspot);
+receiver.on(Message.SET_CONTENT, onSetContent);
+receiver.on(Message.SET_VOLUME, onSetVolume);
+receiver.on(Message.MUTED, onMuted);
+receiver.on(Message.SET_CURRENT_TIME, onUpdateCurrentTime);
+receiver.on(Message.GET_POSITION, onGetPosition);
+receiver.on(Message.SET_FULLSCREEN, onSetFullscreen);
+
+window.addEventListener('load', onLoad);
+
+var stats = new Stats();
+var scene = SceneInfo.loadFromGetParams();
+
+var worldRenderer = new WorldRenderer(scene);
+worldRenderer.on('error', onRenderError);
+worldRenderer.on('load', onRenderLoad);
+worldRenderer.on('modechange', onModeChange);
+worldRenderer.on('ended', onEnded);
+worldRenderer.on('play', onPlay);
+worldRenderer.hotspotRenderer.on('click', onHotspotClick);
+
+window.worldRenderer = worldRenderer;
+
+var isReadySent = false;
+var volume = 0;
+
+function onLoad() {
+  if (!Util.isWebGLEnabled()) {
+    showError('WebGL not supported.');
+    return;
+  }
+
+  // Load the scene.
+  worldRenderer.setScene(scene);
+
+  if (scene.isDebug) {
+    // Show stats.
+    showStats();
+  }
+
+  if (scene.isYawOnly) {
+    WebVRConfig = window.WebVRConfig || {};
+    WebVRConfig.YAW_ONLY = true;
+  }
+
+  requestAnimationFrame(loop);
+}
+
+
+function onVideoTap() {
+  worldRenderer.videoProxy.play();
+  hidePlayButton();
+
+  // Prevent multiple play() calls on the video element.
+  document.body.removeEventListener('touchend', onVideoTap);
+}
+
+function onRenderLoad(event) {
+  if (event.videoElement) {
+
+    var scene = SceneInfo.loadFromGetParams();
+
+    // On mobile, tell the user they need to tap to start. Otherwise, autoplay.
+    if (Util.isMobile()) {
+      // Tell user to tap to start.
+      showPlayButton();
+      document.body.addEventListener('touchend', onVideoTap);
+    } else {
+      event.videoElement.play();
+    }
+
+    // Attach to pause and play events, to notify the API.
+    event.videoElement.addEventListener('pause', onPause);
+    event.videoElement.addEventListener('play', onPlay);
+    event.videoElement.addEventListener('timeupdate', onGetCurrentTime);
+    event.videoElement.addEventListener('ended', onEnded);
+  }
+  // Hide loading indicator.
+  loadIndicator.hide();
+
+  // Autopan only on desktop, for photos only, and only if autopan is enabled.
+  if (!Util.isMobile() && !worldRenderer.sceneInfo.video && !worldRenderer.sceneInfo.isAutopanOff) {
+    worldRenderer.autopan();
+  }
+
+  // Notify the API that we are ready, but only do this once.
+  if (!isReadySent) {
+    if (event.videoElement) {
+      Util.sendParentMessage({
+        type: 'ready',
+        data: {
+          duration: event.videoElement.duration
+        }
+      });
+    } else {
+      Util.sendParentMessage({
+        type: 'ready'
+      });
+    }
+
+    isReadySent = true;
+  }
+}
+
+function onPlayRequest() {
+  if (!worldRenderer.videoProxy) {
+    onApiError('Attempt to pause, but no video found.');
+    return;
+  }
+  worldRenderer.videoProxy.play();
+}
+
+function onPauseRequest() {
+  if (!worldRenderer.videoProxy) {
+    onApiError('Attempt to pause, but no video found.');
+    return;
+  }
+  worldRenderer.videoProxy.pause();
+}
+
+function onAddHotspot(e) {
+  if (Util.isDebug()) {
+    console.log('onAddHotspot', e);
+  }
+  // TODO: Implement some validation?
+
+  var pitch = parseFloat(e.pitch);
+  var yaw = parseFloat(e.yaw);
+  var radius = parseFloat(e.radius);
+  var distance = parseFloat(e.distance);
+  var id = e.id;
+  worldRenderer.hotspotRenderer.add(pitch, yaw, radius, distance, id);
+}
+
+function onSetContent(e) {
+  if (Util.isDebug()) {
+    console.log('onSetContent', e);
+  }
+  // Remove all of the hotspots.
+  worldRenderer.hotspotRenderer.clearAll();
+  // Fade to black.
+  worldRenderer.sphereRenderer.setOpacity(0, 500).then(function() {
+    // Then load the new scene.
+    var scene = SceneInfo.loadFromAPIParams(e.contentInfo);
+    worldRenderer.destroy();
+
+    // Update the URL to reflect the new scene. This is important particularily
+    // on iOS where we use a fake fullscreen mode.
+    var url = scene.getCurrentUrl();
+    //console.log('Updating url to be %s', url);
+    window.history.pushState(null, 'VR View', url);
+
+    // And set the new scene.
+    return worldRenderer.setScene(scene);
+  }).then(function() {
+    // Then fade the scene back in.
+    worldRenderer.sphereRenderer.setOpacity(1, 500);
+  });
+}
+
+function onSetVolume(e) {
+  // Only work for video. If there's no video, send back an error.
+  if (!worldRenderer.videoProxy) {
+    onApiError('Attempt to set volume, but no video found.');
+    return;
+  }
+
+  worldRenderer.videoProxy.setVolume(e.volumeLevel);
+  volume = e.volumeLevel;
+  Util.sendParentMessage({
+    type: 'volumechange',
+    data: e.volumeLevel
+  });
+}
+
+function onMuted(e) {
+  // Only work for video. If there's no video, send back an error.
+  if (!worldRenderer.videoProxy) {
+    onApiError('Attempt to mute, but no video found.');
+    return;
+  }
+
+  worldRenderer.videoProxy.mute(e.muteState);
+
+  Util.sendParentMessage({
+    type: 'muted',
+    data: e.muteState
+  });
+}
+
+function onUpdateCurrentTime(time) {
+  if (!worldRenderer.videoProxy) {
+    onApiError('Attempt to pause, but no video found.');
+    return;
+  }
+
+  worldRenderer.videoProxy.setCurrentTime(time);
+  onGetCurrentTime();
+}
+
+function onGetCurrentTime() {
+  var time = worldRenderer.videoProxy.getCurrentTime();
+  Util.sendParentMessage({
+    type: 'timeupdate',
+    data: time
+  });
+}
+
+function onSetFullscreen() {
+  if (!worldRenderer.videoProxy) {
+    onApiError('Attempt to set fullscreen, but no video found.');
+    return;
+  }
+  worldRenderer.manager.onFSClick_();
+}
+
+function onApiError(message) {
+  console.error(message);
+  Util.sendParentMessage({
+    type: 'error',
+    data: {message: message}
+  });
+}
+
+function onModeChange(mode) {
+  Util.sendParentMessage({
+    type: 'modechange',
+    data: {mode: mode}
+  });
+}
+
+function onHotspotClick(id) {
+  Util.sendParentMessage({
+    type: 'click',
+    data: {id: id}
+  });
+}
+
+function onPlay() {
+  Util.sendParentMessage({
+    type: 'paused',
+    data: false
+  });
+}
+
+function onPause() {
+  Util.sendParentMessage({
+    type: 'paused',
+    data: true
+  });
+}
+
+function onEnded() {
+    Util.sendParentMessage({
+      type: 'ended',
+      data: true
+    });
+}
+
+function onSceneError(message) {
+  showError('Loader: ' + message);
+}
+
+function onRenderError(message) {
+  showError('Render: ' + message);
+}
+
+function showError(message) {
+  // Hide loading indicator.
+  loadIndicator.hide();
+
+  // Sanitize `message` as it could contain user supplied
+  // values. Re-add the space character as to not modify the
+  // error messages used throughout the codebase.
+  message = encodeURI(message).replace(/%20/g, ' ');
+
+  var error = document.querySelector('#error');
+  error.classList.add('visible');
+  error.querySelector('.message').innerHTML = message;
+
+  error.querySelector('.title').innerHTML = 'Error';
+}
+
+function hideError() {
+  var error = document.querySelector('#error');
+  error.classList.remove('visible');
+}
+
+function showPlayButton() {
+  var playButton = document.querySelector('#play-overlay');
+  playButton.classList.add('visible');
+}
+
+function hidePlayButton() {
+  var playButton = document.querySelector('#play-overlay');
+  playButton.classList.remove('visible');
+}
+
+function showStats() {
+  stats.setMode(0); // 0: fps, 1: ms
+
+  // Align bottom-left.
+  stats.domElement.style.position = 'absolute';
+  stats.domElement.style.left = '0px';
+  stats.domElement.style.bottom = '0px';
+  document.body.appendChild(stats.domElement);
+}
+
+function loop(time) {
+  // Use the VRDisplay RAF if it is present.
+  if (worldRenderer.vrDisplay) {
+    worldRenderer.vrDisplay.requestAnimationFrame(loop);
+  } else {
+    requestAnimationFrame(loop);
+  }
+
+  stats.begin();
+  // Update the video if needed.
+  if (worldRenderer.videoProxy) {
+    worldRenderer.videoProxy.update(time);
+  }
+  worldRenderer.render(time);
+  worldRenderer.submitFrame();
+  stats.end();
+}
+function onGetPosition() {
+    Util.sendParentMessage({
+        type: 'getposition',
+        data: {
+            Yaw: worldRenderer.camera.rotation.y * 180 / Math.PI,
+            Pitch: worldRenderer.camera.rotation.x * 180 / Math.PI
+        }
+    });
+}

+ 41 - 0
app/Resources/public/assets/vrview/src/embed/reticle-renderer.js

@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function ReticleRenderer(camera) {
+  this.camera = camera;
+
+  this.reticle = this.createReticle_();
+  // In front of the hotspot itself, which is at r=0.99.
+  this.reticle.position.z = -0.97;
+  camera.add(this.reticle);
+
+  this.setVisibility(false);
+}
+
+ReticleRenderer.prototype.setVisibility = function(isVisible) {
+  // TODO: Tween the transition.
+  this.reticle.visible = isVisible;
+};
+
+ReticleRenderer.prototype.createReticle_ = function() {
+  // Make a torus.
+  var geometry = new THREE.TorusGeometry(0.02, 0.005, 10, 20);
+  var material = new THREE.MeshBasicMaterial({color: 0x000000});
+  var torus = new THREE.Mesh(geometry, material);
+
+  return torus;
+};
+
+module.exports = ReticleRenderer;

+ 125 - 0
app/Resources/public/assets/vrview/src/embed/scene-info.js

@@ -0,0 +1,125 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var Util = require('../util');
+
+var CAMEL_TO_UNDERSCORE = {
+  video: 'video',
+  image: 'image',
+  preview: 'preview',
+  loop: 'loop',
+  volume: 'volume',
+  muted: 'muted',
+  isStereo: 'is_stereo',
+  defaultYaw: 'default_yaw',
+  isYawOnly: 'is_yaw_only',
+  isDebug: 'is_debug',
+  isVROff: 'is_vr_off',
+  isAutopanOff: 'is_autopan_off',
+  hideFullscreenButton: 'hide_fullscreen_button'
+};
+
+/**
+ * Contains all information about a given scene.
+ */
+function SceneInfo(opt_params) {
+  var params = opt_params || {};
+  params.player = {
+    loop: opt_params.loop,
+    volume: opt_params.volume,
+    muted: opt_params.muted
+  };
+
+  this.image = params.image !== undefined ? encodeURI(params.image) : undefined;
+  this.preview = params.preview !== undefined ? encodeURI(params.preview) : undefined;
+  this.video = params.video !== undefined ? encodeURI(params.video) : undefined;
+  this.defaultYaw = THREE.Math.degToRad(params.defaultYaw || 0);
+
+  this.isStereo = Util.parseBoolean(params.isStereo);
+  this.isYawOnly = Util.parseBoolean(params.isYawOnly);
+  this.isDebug = Util.parseBoolean(params.isDebug);
+  this.isVROff = Util.parseBoolean(params.isVROff);
+  this.isAutopanOff = Util.parseBoolean(params.isAutopanOff);
+  this.loop = Util.parseBoolean(params.player.loop);
+  this.volume = parseFloat(
+      params.player.volume ? params.player.volume : '1');
+  this.muted = Util.parseBoolean(params.player.muted);
+  this.hideFullscreenButton = Util.parseBoolean(params.hideFullscreenButton);
+}
+
+SceneInfo.loadFromGetParams = function() {
+  var params = {};
+  for (var camelCase in CAMEL_TO_UNDERSCORE) {
+    var underscore = CAMEL_TO_UNDERSCORE[camelCase];
+    params[camelCase] = Util.getQueryParameter(underscore)
+                        || ((window.WebVRConfig && window.WebVRConfig.PLAYER) ? window.WebVRConfig.PLAYER[underscore] : "");
+  }
+  var scene = new SceneInfo(params);
+  if (!scene.isValid()) {
+    console.warn('Invalid scene: %s', scene.errorMessage);
+  }
+  return scene;
+};
+
+SceneInfo.loadFromAPIParams = function(underscoreParams) {
+  var params = {};
+  for (var camelCase in CAMEL_TO_UNDERSCORE) {
+    var underscore = CAMEL_TO_UNDERSCORE[camelCase];
+    if (underscoreParams[underscore]) {
+      params[camelCase] = underscoreParams[underscore];
+    }
+  }
+  var scene = new SceneInfo(params);
+  if (!scene.isValid()) {
+    console.warn('Invalid scene: %s', scene.errorMessage);
+  }
+  return scene;
+};
+
+SceneInfo.prototype.isValid = function() {
+  // Either it's an image or a video.
+  if (!this.image && !this.video) {
+    this.errorMessage = 'Either image or video URL must be specified.';
+    return false;
+  }
+  if (this.image && !this.isValidImage_(this.image)) {
+    this.errorMessage = 'Invalid image URL: ' + this.image;
+    return false;
+  }
+  this.errorMessage = null;
+  return true;
+};
+
+/**
+ * Generates a URL to reflect this scene.
+ */
+SceneInfo.prototype.getCurrentUrl = function() {
+  var url = location.protocol + '//' + location.host + location.pathname + '?';
+  for (var camelCase in CAMEL_TO_UNDERSCORE) {
+    var underscore = CAMEL_TO_UNDERSCORE[camelCase];
+    var value = this[camelCase];
+    if (value !== undefined) {
+      url += underscore + '=' + value + '&';
+    }
+  }
+  // Chop off the trailing ampersand.
+  return url.substring(0, url.length - 1);
+};
+
+SceneInfo.prototype.isValidImage_ = function(imageUrl) {
+  return true;
+};
+
+module.exports = SceneInfo;

+ 205 - 0
app/Resources/public/assets/vrview/src/embed/sphere-renderer.js

@@ -0,0 +1,205 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var Eyes = require('./eyes');
+var TWEEN = require('@tweenjs/tween.js');
+var Util = require('../util');
+var VideoType = require('../video-type');
+
+function SphereRenderer(scene) {
+  this.scene = scene;
+
+  // Create a transparent mask.
+  this.createOpacityMask_();
+}
+
+/**
+ * Sets the photosphere based on the image in the source. Supports stereo and
+ * mono photospheres.
+ *
+ * @return {Promise}
+ */
+SphereRenderer.prototype.setPhotosphere = function(src, opt_params) {
+  return new Promise(function(resolve, reject) {
+    this.resolve = resolve;
+    this.reject = reject;
+
+    var params = opt_params || {};
+
+    this.isStereo = !!params.isStereo;
+    this.src = src;
+
+    // Load texture.
+    var loader = new THREE.TextureLoader();
+    loader.crossOrigin = 'anonymous';
+    loader.load(src, this.onTextureLoaded_.bind(this), undefined,
+                this.onTextureError_.bind(this));
+  }.bind(this));
+};
+
+/**
+ * @return {Promise} Yeah.
+ */
+SphereRenderer.prototype.set360Video = function (videoElement, videoType, opt_params) {
+  return new Promise(function(resolve, reject) {
+    this.resolve = resolve;
+    this.reject = reject;
+
+    var params = opt_params || {};
+
+    this.isStereo = !!params.isStereo;
+
+    // Load the video texture.
+    var videoTexture = new THREE.VideoTexture(videoElement);
+    videoTexture.minFilter = THREE.LinearFilter;
+    videoTexture.magFilter = THREE.LinearFilter;
+    videoTexture.generateMipmaps = false;
+
+    if (Util.isSafari() && videoType === VideoType.HLS) {
+      // fix black screen issue on safari
+      videoTexture.format = THREE.RGBAFormat;
+      videoTexture.flipY = false;
+    } else {
+      videoTexture.format = THREE.RGBFormat;
+    }
+
+    videoTexture.needsUpdate = true;
+
+    this.onTextureLoaded_(videoTexture);
+  }.bind(this));
+};
+
+/**
+ * Set the opacity of the panorama.
+ *
+ * @param {Number} opacity How opaque we want the panorama to be. 0 means black,
+ * 1 means full color.
+ * @param {Number} duration Number of milliseconds the transition should take.
+ *
+ * @return {Promise} When the opacity change is complete.
+ */
+SphereRenderer.prototype.setOpacity = function(opacity, duration) {
+  var scene = this.scene;
+  // If we want the opacity
+  var overlayOpacity = 1 - opacity;
+  return new Promise(function(resolve, reject) {
+    var mask = scene.getObjectByName('opacityMask');
+    var tween = new TWEEN.Tween({opacity: mask.material.opacity})
+        .to({opacity: overlayOpacity}, duration)
+        .easing(TWEEN.Easing.Quadratic.InOut);
+    tween.onUpdate(function(e) {
+      mask.material.opacity = this.opacity;
+    });
+    tween.onComplete(resolve).start();
+  });
+};
+
+SphereRenderer.prototype.onTextureLoaded_ = function(texture) {
+  var sphereLeft;
+  var sphereRight;
+  if (this.isStereo) {
+    sphereLeft = this.createPhotosphere_(texture, {offsetY: 0.5, scaleY: 0.5});
+    sphereRight = this.createPhotosphere_(texture, {offsetY: 0, scaleY: 0.5});
+  } else {
+    sphereLeft = this.createPhotosphere_(texture);
+    sphereRight = this.createPhotosphere_(texture);
+  }
+
+  // Display in left and right eye respectively.
+  sphereLeft.layers.set(Eyes.LEFT);
+  sphereLeft.eye = Eyes.LEFT;
+  sphereLeft.name = 'eyeLeft';
+  sphereRight.layers.set(Eyes.RIGHT);
+  sphereRight.eye = Eyes.RIGHT;
+  sphereRight.name = 'eyeRight';
+
+
+    this.scene.getObjectByName('photo').children = [sphereLeft, sphereRight];
+
+  this.resolve();
+};
+
+SphereRenderer.prototype.onTextureError_ = function(error) {
+  this.reject('Unable to load texture from "' + this.src + '"');
+};
+
+
+SphereRenderer.prototype.createPhotosphere_ = function(texture, opt_params) {
+  var p = opt_params || {};
+  p.scaleX = p.scaleX || 1;
+  p.scaleY = p.scaleY || 1;
+  p.offsetX = p.offsetX || 0;
+  p.offsetY = p.offsetY || 0;
+  p.phiStart = p.phiStart || 0;
+  p.phiLength = p.phiLength || Math.PI * 2;
+  p.thetaStart = p.thetaStart || 0;
+  p.thetaLength = p.thetaLength || Math.PI;
+
+  var geometry = new THREE.SphereGeometry(1, 48, 48,
+      p.phiStart, p.phiLength, p.thetaStart, p.thetaLength);
+  geometry.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1));
+  var uvs = geometry.faceVertexUvs[0];
+  for (var i = 0; i < uvs.length; i ++) {
+    for (var j = 0; j < 3; j ++) {
+      uvs[i][j].x *= p.scaleX;
+      uvs[i][j].x += p.offsetX;
+      uvs[i][j].y *= p.scaleY;
+      uvs[i][j].y += p.offsetY;
+    }
+  }
+
+  var material;
+  if (texture.format === THREE.RGBAFormat && texture.flipY === false) {
+    material = new THREE.ShaderMaterial({
+      uniforms: {
+        texture: { value: texture }
+      },
+      vertexShader: [
+        "varying vec2 vUV;",
+        "void main() {",
+        "	vUV = vec2( uv.x, 1.0 - uv.y );",
+        "	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+        "}"
+      ].join("\n"),
+      fragmentShader: [
+        "uniform sampler2D texture;",
+        "varying vec2 vUV;",
+        "void main() {",
+        " gl_FragColor = texture2D( texture, vUV  )" + (Util.isIOS() ? ".bgra" : "") + ";",
+        "}"
+      ].join("\n")
+    });
+  } else {
+    material = new THREE.MeshBasicMaterial({ map: texture });
+  }
+  var out = new THREE.Mesh(geometry, material);
+  //out.visible = false;
+  out.renderOrder = -1;
+  return out;
+};
+
+SphereRenderer.prototype.createOpacityMask_ = function() {
+  var geometry = new THREE.SphereGeometry(0.49, 48, 48);
+  var material = new THREE.MeshBasicMaterial({
+    color: 0x000000, side: THREE.DoubleSide, opacity: 0, transparent: true});
+  var opacityMask = new THREE.Mesh(geometry, material);
+  opacityMask.name = 'opacityMask';
+  opacityMask.renderOrder = 1;
+
+  this.scene.add(opacityMask);
+  return opacityMask;
+};
+
+module.exports = SphereRenderer;

+ 130 - 0
app/Resources/public/assets/vrview/src/embed/video-proxy.js

@@ -0,0 +1,130 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var Util = require('../util');
+
+/**
+ * A proxy class for working around the fact that as soon as a video is play()ed
+ * on iOS, Safari auto-fullscreens the video.
+ *
+ * TODO(smus): The entire raison d'etre for this class is to work around this
+ * issue. Once Safari implements some way to suppress this fullscreen player, we
+ * can remove this code.
+ */
+function VideoProxy(videoElement) {
+  this.videoElement = videoElement;
+  // True if we're currently manually advancing the playhead (only on iOS).
+  this.isFakePlayback = false;
+
+  // When the video started playing.
+  this.startTime = null;
+}
+
+VideoProxy.prototype.play = function() {
+  if (Util.isIOS9OrLess()) {
+    this.startTime = performance.now();
+    this.isFakePlayback = true;
+
+    // Make an audio element to playback just the audio part.
+    this.audioElement = new Audio();
+    this.audioElement.src = this.videoElement.src;
+    this.audioElement.play();
+  } else {
+    this.videoElement.play().then(function(e) {
+      console.log('Playing video.', e);
+    });
+  }
+};
+
+VideoProxy.prototype.pause = function() {
+  if (Util.isIOS9OrLess() && this.isFakePlayback) {
+    this.isFakePlayback = true;
+
+    this.audioElement.pause();
+  } else {
+    this.videoElement.pause();
+  }
+};
+
+VideoProxy.prototype.setVolume = function(volumeLevel) {
+  if (this.videoElement) {
+    // On iOS 10, the VideoElement.volume property is read-only. So we special
+    // case muting and unmuting.
+    if (Util.isIOS()) {
+      this.videoElement.muted = (volumeLevel === 0);
+    } else {
+      this.videoElement.volume = volumeLevel;
+    }
+  }
+  if (this.audioElement) {
+    this.audioElement.volume = volumeLevel;
+  }
+};
+
+/**
+ * Set the attribute mute of the elements according with the muteState param.
+ *
+ * @param bool muteState
+ */
+VideoProxy.prototype.mute = function(muteState) {
+  if (this.videoElement) {
+    this.videoElement.muted = muteState;
+  }
+  if (this.audioElement) {
+    this.audioElement.muted = muteState;
+  }
+};
+
+VideoProxy.prototype.getCurrentTime = function() {
+  return Util.isIOS9OrLess() ? this.audioElement.currentTime : this.videoElement.currentTime;
+};
+
+/**
+ *
+ * @param {Object} time
+ */
+VideoProxy.prototype.setCurrentTime = function(time) {
+  if (this.videoElement) {
+    this.videoElement.currentTime = time.currentTime;
+  }
+  if (this.audioElement) {
+    this.audioElement.currentTime = time.currentTime;
+  }
+};
+
+/**
+ * Called on RAF to progress playback.
+ */
+VideoProxy.prototype.update = function() {
+  // Fakes playback for iOS only.
+  if (!this.isFakePlayback) {
+    return;
+  }
+  var duration = this.videoElement.duration;
+  var now = performance.now();
+  var delta = now - this.startTime;
+  var deltaS = delta / 1000;
+  this.videoElement.currentTime = deltaS;
+
+  // Loop through the video
+  if (deltaS > duration) {
+    this.startTime = now;
+    this.videoElement.currentTime = 0;
+    // Also restart the audio.
+    this.audioElement.currentTime = 0;
+  }
+};
+
+module.exports = VideoProxy;

+ 20 - 0
app/Resources/public/assets/vrview/src/embed/with-analytics.js

@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Load EmbedVR.
+require('./main');
+
+// Load Analytics for EmbedVR.
+require('./analytics');

+ 372 - 0
app/Resources/public/assets/vrview/src/embed/world-renderer.js

@@ -0,0 +1,372 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var AdaptivePlayer = require('./adaptive-player');
+var EventEmitter = require('eventemitter3');
+var Eyes = require('./eyes');
+var HotspotRenderer = require('./hotspot-renderer');
+var ReticleRenderer = require('./reticle-renderer');
+var SphereRenderer = require('./sphere-renderer');
+var TWEEN = require('@tweenjs/tween.js');
+var Util = require('../util');
+var VideoProxy = require('./video-proxy');
+var WebVRManager = require('webvr-boilerplate');
+
+var AUTOPAN_DURATION = 3000;
+var AUTOPAN_ANGLE = 0.4;
+
+/**
+ * The main WebGL rendering entry point. Manages the scene, camera, VR-related
+ * rendering updates. Interacts with the WebVRManager.
+ *
+ * Coordinates the other renderers: SphereRenderer, HotspotRenderer,
+ * ReticleRenderer.
+ *
+ * Also manages the AdaptivePlayer and VideoProxy.
+ *
+ * Emits the following events:
+ *   load: when the scene is loaded.
+ *   error: if there is an error loading the scene.
+ *   modechange(Boolean isVR): if the mode (eg. VR, fullscreen, etc) changes.
+ */
+function WorldRenderer(params) {
+  this.init_(params.hideFullscreenButton);
+
+  this.sphereRenderer = new SphereRenderer(this.scene);
+  this.hotspotRenderer = new HotspotRenderer(this);
+  this.hotspotRenderer.on('focus', this.onHotspotFocus_.bind(this));
+  this.hotspotRenderer.on('blur', this.onHotspotBlur_.bind(this));
+  this.reticleRenderer = new ReticleRenderer(this.camera);
+
+  // Get the VR Display as soon as we initialize.
+  navigator.getVRDisplays().then(function(displays) {
+    if (displays.length > 0) {
+      this.vrDisplay = displays[0];
+    }
+  }.bind(this));
+
+}
+WorldRenderer.prototype = new EventEmitter();
+
+WorldRenderer.prototype.render = function(time) {
+  this.controls.update();
+  TWEEN.update(time);
+  this.effect.render(this.scene, this.camera);
+  this.hotspotRenderer.update(this.camera);
+};
+
+/**
+ * @return {Promise} When the scene is fully loaded.
+ */
+WorldRenderer.prototype.setScene = function(scene) {
+  var self = this;
+  var promise = new Promise(function(resolve, reject) {
+    self.sceneResolve = resolve;
+    self.sceneReject = reject;
+  });
+
+  if (!scene || !scene.isValid()) {
+    this.didLoadFail_(scene.errorMessage);
+    return;
+  }
+
+  var params = {
+    isStereo: scene.isStereo,
+    loop: scene.loop,
+    volume: scene.volume,
+    muted: scene.muted
+  };
+
+  this.setDefaultYaw_(scene.defaultYaw || 0);
+
+  // Disable VR mode if explicitly disabled, or if we're loading a video on iOS
+  // 9 or earlier.
+  if (scene.isVROff || (scene.video && Util.isIOS9OrLess())) {
+    this.manager.setVRCompatibleOverride(false);
+  }
+
+  // Set various callback overrides in iOS.
+  if (Util.isIOS()) {
+    this.manager.setFullscreenCallback(function() {
+      Util.sendParentMessage({type: 'enter-fullscreen'});
+    });
+    this.manager.setExitFullscreenCallback(function() {
+      Util.sendParentMessage({type: 'exit-fullscreen'});
+    });
+    this.manager.setVRCallback(function() {
+      Util.sendParentMessage({type: 'enter-vr'});
+    });
+  }
+
+  // If we're dealing with an image, and not a video.
+  if (scene.image && !scene.video) {
+    if (scene.preview) {
+      // First load the preview.
+      this.sphereRenderer.setPhotosphere(scene.preview, params).then(function() {
+        // As soon as something is loaded, emit the load event to hide the
+        // loading progress bar.
+        self.didLoad_();
+        // Then load the full resolution image.
+        self.sphereRenderer.setPhotosphere(scene.image, params);
+      }).catch(self.didLoadFail_.bind(self));
+    } else {
+      // No preview -- go straight to rendering the full image.
+      this.sphereRenderer.setPhotosphere(scene.image, params).then(function() {
+        self.didLoad_();
+      }).catch(self.didLoadFail_.bind(self));
+    }
+  } else if (scene.video) {
+    if (Util.isIE11()) {
+      // On IE 11, if an 'image' param is provided, load it instead of showing
+      // an error.
+      //
+      // TODO(smus): Once video textures are supported, remove this fallback.
+      if (scene.image) {
+        this.sphereRenderer.setPhotosphere(scene.image, params).then(function() {
+          self.didLoad_();
+        }).catch(self.didLoadFail_.bind(self));
+      } else {
+        this.didLoadFail_('Video is not supported on IE11.');
+      }
+    } else {
+      this.player = new AdaptivePlayer(params);
+      this.player.on('load', function(videoElement, videoType) {
+        self.sphereRenderer.set360Video(videoElement, videoType, params).then(function() {
+          self.didLoad_({videoElement: videoElement});
+        }).catch(self.didLoadFail_.bind(self));
+      });
+      this.player.on('error', function(error) {
+        self.didLoadFail_('Video load error: ' + error);
+      });
+      this.player.load(scene.video);
+
+      this.videoProxy = new VideoProxy(this.player.video);
+    }
+  }
+
+  this.sceneInfo = scene;
+  if (Util.isDebug()) {
+    console.log('Loaded scene', scene);
+  }
+
+  return promise;
+};
+
+WorldRenderer.prototype.isVRMode = function() {
+  return !!this.vrDisplay && this.vrDisplay.isPresenting;
+};
+
+WorldRenderer.prototype.submitFrame = function() {
+  if (this.isVRMode()) {
+    this.vrDisplay.submitFrame();
+  }
+};
+
+WorldRenderer.prototype.disposeEye_ = function(eye) {
+  if (eye) {
+    if (eye.material.map) {
+      eye.material.map.dispose();
+    }
+    eye.material.dispose();
+    eye.geometry.dispose();
+  }
+};
+
+WorldRenderer.prototype.dispose = function() {
+  var eyeLeft = this.scene.getObjectByName('eyeLeft');
+  this.disposeEye_(eyeLeft);
+  var eyeRight = this.scene.getObjectByName('eyeRight');
+  this.disposeEye_(eyeRight);
+};
+
+WorldRenderer.prototype.destroy = function() {
+  if (this.player) {
+    this.player.removeAllListeners();
+    this.player.destroy();
+    this.player = null;
+  }
+  var photo = this.scene.getObjectByName('photo');
+  var eyeLeft = this.scene.getObjectByName('eyeLeft');
+  var eyeRight = this.scene.getObjectByName('eyeRight');
+
+  if (eyeLeft) {
+    this.disposeEye_(eyeLeft);
+    photo.remove(eyeLeft);
+    this.scene.remove(eyeLeft);
+  }
+
+  if (eyeRight) {
+    this.disposeEye_(eyeRight);
+    photo.remove(eyeRight);
+    this.scene.remove(eyeRight);
+  }
+};
+
+WorldRenderer.prototype.didLoad_ = function(opt_event) {
+  var event = opt_event || {};
+  this.emit('load', event);
+  if (this.sceneResolve) {
+    this.sceneResolve();
+  }
+};
+
+WorldRenderer.prototype.didLoadFail_ = function(message) {
+  this.emit('error', message);
+  if (this.sceneReject) {
+    this.sceneReject(message);
+  }
+};
+
+/**
+ * Sets the default yaw.
+ * @param {Number} angleRad The yaw in radians.
+ */
+WorldRenderer.prototype.setDefaultYaw_ = function(angleRad) {
+  // Rotate the camera parent to take into account the scene's rotation.
+  // By default, it should be at the center of the image.
+  var display = this.controls.getVRDisplay();
+  // For desktop, we subtract the current display Y axis
+  var theta = display.theta_ || 0;
+  // For devices with orientation we make the current view center
+  if (display.poseSensor_) {
+    display.poseSensor_.resetPose();
+  }
+  this.camera.parent.rotation.y = (Math.PI / 2.0) + angleRad - theta;
+};
+
+/**
+ * Do the initial camera tween to rotate the camera, giving an indication that
+ * there is live content there (on desktop only).
+ */
+WorldRenderer.prototype.autopan = function(duration) {
+  var targetY = this.camera.parent.rotation.y - AUTOPAN_ANGLE;
+  var tween = new TWEEN.Tween(this.camera.parent.rotation)
+      .to({y: targetY}, AUTOPAN_DURATION)
+      .easing(TWEEN.Easing.Quadratic.Out)
+      .start();
+};
+
+WorldRenderer.prototype.init_ = function(hideFullscreenButton) {
+  var container = document.querySelector('body');
+  var aspect = window.innerWidth / window.innerHeight;
+  var camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 100);
+  camera.layers.enable(1);
+
+  var cameraDummy = new THREE.Object3D();
+  cameraDummy.add(camera);
+
+  // Antialiasing disabled to improve performance.
+  var renderer = new THREE.WebGLRenderer({antialias: false});
+  renderer.setClearColor(0x000000, 0);
+  renderer.setSize(window.innerWidth, window.innerHeight);
+  renderer.setPixelRatio(window.devicePixelRatio);
+
+  container.appendChild(renderer.domElement);
+
+  var controls = new THREE.VRControls(camera);
+  var effect = new THREE.VREffect(renderer);
+
+  // Disable eye separation.
+  effect.scale = 0;
+  effect.setSize(window.innerWidth, window.innerHeight);
+
+  // Present submission of frames automatically. This is done manually in
+  // submitFrame().
+  effect.autoSubmitFrame = false;
+
+  this.camera = camera;
+  this.renderer = renderer;
+  this.effect = effect;
+  this.controls = controls;
+  this.manager = new WebVRManager(renderer, effect, {predistorted: false, hideButton: hideFullscreenButton});
+
+  this.scene = this.createScene_();
+  this.scene.add(this.camera.parent);
+
+
+  // Watch the resize event.
+  window.addEventListener('resize', this.onResize_.bind(this));
+
+  // Prevent context menu.
+  window.addEventListener('contextmenu', this.onContextMenu_.bind(this));
+
+  window.addEventListener('vrdisplaypresentchange',
+                          this.onVRDisplayPresentChange_.bind(this));
+};
+
+WorldRenderer.prototype.onResize_ = function() {
+  this.effect.setSize(window.innerWidth, window.innerHeight);
+  this.camera.aspect = window.innerWidth / window.innerHeight;
+  this.camera.updateProjectionMatrix();
+};
+
+WorldRenderer.prototype.onVRDisplayPresentChange_ = function(e) {
+  if (Util.isDebug()) {
+    console.log('onVRDisplayPresentChange_');
+  }
+  var isVR = this.isVRMode();
+
+  // If the mode changed to VR and there is at least one hotspot, show reticle.
+  var isReticleVisible = isVR && this.hotspotRenderer.getCount() > 0;
+  this.reticleRenderer.setVisibility(isReticleVisible);
+
+  // Resize the renderer for good measure.
+  this.onResize_();
+
+  // Analytics.
+  if (window.analytics) {
+    analytics.logModeChanged(isVR);
+  }
+
+  // When exiting VR mode from iOS, make sure we emit back an exit-fullscreen event.
+  if (!isVR && Util.isIOS()) {
+    Util.sendParentMessage({type: 'exit-fullscreen'});
+  }
+
+  // Emit a mode change event back to any listeners.
+  this.emit('modechange', isVR);
+};
+
+WorldRenderer.prototype.createScene_ = function(opt_params) {
+  var scene = new THREE.Scene();
+
+  // Add a group for the photosphere.
+  var photoGroup = new THREE.Object3D();
+  photoGroup.name = 'photo';
+  scene.add(photoGroup);
+
+  return scene;
+};
+
+WorldRenderer.prototype.onHotspotFocus_ = function(id) {
+  // Set the default cursor to be a pointer.
+  this.setCursor_('pointer');
+};
+
+WorldRenderer.prototype.onHotspotBlur_ = function(id) {
+  // Reset the default cursor to be the default one.
+  this.setCursor_('');
+};
+
+WorldRenderer.prototype.setCursor_ = function(cursor) {
+  this.renderer.domElement.style.cursor = cursor;
+};
+
+WorldRenderer.prototype.onContextMenu_ = function(e) {
+  e.preventDefault();
+  e.stopPropagation();
+  return false;
+};
+
+module.exports = WorldRenderer;

+ 33 - 0
app/Resources/public/assets/vrview/src/message.js

@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Messages from the API to the embed.
+ */
+var Message = {
+  PLAY: 'play',
+  PAUSE: 'pause',
+  TIMEUPDATE: 'timeupdate',
+  ADD_HOTSPOT: 'addhotspot',
+  SET_CONTENT: 'setimage',
+  SET_VOLUME: 'setvolume',
+  MUTED: 'muted',
+  SET_CURRENT_TIME: 'setcurrenttime',
+  DEVICE_MOTION: 'devicemotion',
+  GET_POSITION: 'getposition',
+  SET_FULLSCREEN: 'setfullscreen',
+};
+
+module.exports = Message;

+ 29 - 0
app/Resources/public/assets/vrview/src/third_party/three/Three.js

@@ -0,0 +1,29 @@
+import '../../../node_modules/three/src/polyfills.js';
+
+export { WebGLRenderer } from '../../../node_modules/three/src/renderers/WebGLRenderer.js';
+export { Scene } from '../../../node_modules/three/src/scenes/Scene.js';
+export { Mesh } from '../../../node_modules/three/src/objects/Mesh.js';
+export { VideoTexture } from '../../../node_modules/three/src/textures/VideoTexture.js';
+export { MeshBasicMaterial } from '../../../node_modules/three/src/materials/MeshBasicMaterial.js';
+export { ShaderMaterial } from '../../../node_modules/three/src/materials/ShaderMaterial.js';
+export { TextureLoader } from '../../../node_modules/three/src/loaders/TextureLoader.js';
+export { PerspectiveCamera } from '../../../node_modules/three/src/cameras/PerspectiveCamera.js';
+export { Object3D } from '../../../node_modules/three/src/core/Object3D.js';
+export { Raycaster } from '../../../node_modules/three/src/core/Raycaster.js';
+export { _Math as Math } from '../../../node_modules/three/src/math/Math.js';
+export { Quaternion } from '../../../node_modules/three/src/math/Quaternion.js';
+export { Euler } from '../../../node_modules/three/src/math/Euler.js';
+export { Matrix4 } from '../../../node_modules/three/src/math/Matrix4.js';
+export { Matrix3 } from '../../../node_modules/three/src/math/Matrix3.js';
+export { Vector4 } from '../../../node_modules/three/src/math/Vector4.js';
+export { Vector3 } from '../../../node_modules/three/src/math/Vector3.js';
+export { Vector2 } from '../../../node_modules/three/src/math/Vector2.js';
+export { Color } from '../../../node_modules/three/src/math/Color.js';
+export { TorusGeometry } from '../../../node_modules/three/src/geometries/TorusGeometry.js';
+export { SphereGeometry } from '../../../node_modules/three/src/geometries/SphereGeometry.js';
+export { CircleGeometry } from '../../../node_modules/three/src/geometries/CircleGeometry.js';
+export { RingGeometry } from '../../../node_modules/three/src/geometries/RingGeometry.js';
+export * from '../../../node_modules/three/src/constants.js';
+
+import '../../../node_modules/three/examples/js/controls/VRControls.js';
+import '../../../node_modules/three/examples/js/effects/VREffect.js';

BIN
app/Resources/public/assets/vrview/src/third_party/three/closure-compiler-v20160713.jar


+ 10 - 0
app/Resources/public/assets/vrview/src/third_party/three/externs.js

@@ -0,0 +1,10 @@
+var THREE;
+var define;
+var module;
+var exports;
+var performance;
+var WebGL2RenderingContext;
+var VRDisplay;
+var PositionSensorVRDevice;
+var HMDVRDevice;
+var VRFrameData;

+ 34 - 0
app/Resources/public/assets/vrview/src/third_party/three/rollup.config.js

@@ -0,0 +1,34 @@
+import * as fs from 'fs';
+
+var outro = `
+Object.defineProperty( exports, 'AudioContext', {
+	get: function () {
+		return exports.getAudioContext();
+	}
+});`;
+
+function glsl () {
+	return {
+		transform ( code, id ) {
+			if ( !/\.glsl$/.test( id ) ) return;
+
+			return 'export default ' + JSON.stringify(
+				code
+					.replace( /[ \t]*\/\/.*\n/g, '' )
+					.replace( /[ \t]*\/\*[\s\S]*?\*\//g, '' )
+					.replace( /\n{2,}/g, '\n' )
+			) + ';';
+		}
+	};
+}
+
+export default {
+	entry: 'src/third_party/three/Three.js',
+	dest: 'build/three.js',
+	moduleName: 'THREE',
+	format: 'umd',
+	plugins: [
+		glsl()
+	],
+	outro: outro
+};

Dosya farkı çok büyük olduğundan ihmal edildi
+ 33 - 0
app/Resources/public/assets/vrview/src/util.js


+ 25 - 0
app/Resources/public/assets/vrview/src/video-type.js

@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Video Types
+ */
+var VideoTypes = {
+  HLS: 1,
+  DASH: 2,
+  VIDEO: 3
+};
+
+module.exports = VideoTypes;

+ 100 - 0
app/Resources/public/assets/vrview/style.css

@@ -0,0 +1,100 @@
+html, body {
+  background-color: #000;
+  color: #eee;
+  margin: 0px;
+  padding: 0px;
+  position: fixed;
+  overflow: hidden;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  right: 0;
+
+  /* Prevent user selection. */
+  user-select: none;
+  touch-callout: none;
+  -webkit-touch-callout: none;
+  -webkit-user-select: none;
+}
+.dialog {
+  display: none;
+  align-items: center;
+  justify-content: center;
+  font-family: sans-serif;
+  font-size: 170%;
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  background: rgba(255, 255, 255, 0.2);
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  user-select: none;
+}
+.dialog.visible {
+  display: flex;
+}
+.dialog .wrap {
+  padding: 30px 60px;
+  margin: 20px auto;
+  width: 60%;
+  background: rgba(0, 0, 0, 0.8);
+  border-radius: 5px;
+}
+.dialog h1 {
+  margin: 0;
+}
+
+a, a:visited {
+  color: skyblue;
+}
+
+#watermark img {
+  position: fixed;
+  overflow: hidden;
+  left: 0;
+  bottom: 0;
+  opacity: 0.3;
+  width: 24px;
+  height: 24px;
+  padding: 12px;
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  user-select: none;
+}
+#watermark img:hover {
+  opacity: 1;
+  -webkit-filter: drop-shadow(white 0 0 5px);
+}
+
+
+canvas {
+  cursor: -webkit-grab;
+}
+canvas:active {
+  cursor: -webkit-grabbing;
+}
+
+#play-overlay {
+  position: fixed;
+  width: 100%;
+  height: 100%;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: none;
+	align-items: center;
+  justify-content: center;
+}
+#play-overlay.visible {
+	display: flex;
+}
+#play-overlay img {
+  width: 30%;
+  height: 30%;
+}
+
+#error .message {
+  font-family: monospace;
+}

+ 3 - 2
main/template/default/layout/main.js.tpl

@@ -258,10 +258,11 @@ $(function() {
     if ( {{ show_media_element }} == 1) {
         $('video:not(.skip), audio:not(.skip)').mediaelementplayer({
             pluginPath: _p.web + 'web/assets/mediaelement/build/',
-            renderers: ['html5', 'flash_video', 'native_flv'],
+            //renderers: ['html5', 'flash_video', 'native_flv'],
             features: ['{{ video_features }}'],
             success: function(mediaElement, originalNode, instance) {
-            }
+            },
+            vrPath: _p.web + 'web/assets/vrview/build/vrview.js'
         });
     }
 

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor