text: (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.WebVRManager = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
  /*
   * Copyright 2015 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 Emitter = _dereq_('./emitter.js');
  var Modes = _dereq_('./modes.js');
  var Util = _dereq_('./util.js');
  
  /**
   * Everything having to do with the WebVR button.
   * Emits a 'click' event when it's clicked.
   */
  function ButtonManager(opt_root) {
    var root = opt_root || document.body;
    this.loadIcons_();
  
    // Make the fullscreen button.
    var fsButton = this.createButton();
    fsButton.src = this.ICONS.fullscreen;
    fsButton.title = 'Fullscreen mode';
    var s = fsButton.style;
    s.top = 0;
    s.right = 0;
    fsButton.addEventListener('click', this.createClickHandler_('fs'));
    root.appendChild(fsButton);
    this.fsButton = fsButton;
  
    // Make the VR button.
    var vrButton = this.createButton();
    vrButton.src = this.ICONS.cardboard;
    vrButton.title = 'Virtual reality mode';
    var s = vrButton.style;
    s.top = 0;
    s.right = '48px';
    vrButton.addEventListener('click', this.createClickHandler_('vr'));
    root.appendChild(vrButton);
    this.vrButton = vrButton;
  
    this.isVisible = true;
  
  }
  ButtonManager.prototype = new Emitter();
  
  ButtonManager.prototype.createButton = function() {
    var button = document.createElement('img');
    button.className = 'webvr-button';
    var s = button.style;
    s.position = 'absolute';
    s.width = '24px'
    s.height = '24px';
    s.backgroundSize = 'cover';
    s.backgroundColor = 'transparent';
    s.border = 0;
    s.userSelect = 'none';
    s.webkitUserSelect = 'none';
    s.MozUserSelect = 'none';
    s.cursor = 'pointer';
    s.padding = '12px';
    s.zIndex = 1;
    s.display = 'none';
    s.boxSizing = 'content-box';
  
    // Prevent button from being selected and dragged.
    button.draggable = false;
    button.addEventListener('dragstart', function(e) {
      e.preventDefault();
    });
  
    // Style it on hover.
    button.addEventListener('mouseenter', function(e) {
      s.filter = s.webkitFilter = 'drop-shadow(0 0 5px rgba(255,255,255,1))';
    });
    button.addEventListener('mouseleave', function(e) {
      s.filter = s.webkitFilter = '';
    });
    return button;
  };
  
  ButtonManager.prototype.setMode = function(mode, isVRCompatible) {
    isVRCompatible = isVRCompatible || WebVRConfig.FORCE_ENABLE_VR;
    if (!this.isVisible) {
      return;
    }
    switch (mode) {
      case Modes.NORMAL:
        this.fsButton.style.display = 'block';
        this.fsButton.src = this.ICONS.fullscreen;
        this.vrButton.style.display = (isVRCompatible ? 'block' : 'none');
        break;
      case Modes.MAGIC_WINDOW:
        this.fsButton.style.display = 'block';
        this.fsButton.src = this.ICONS.exitFullscreen;
        this.vrButton.style.display = 'none';
        break;
      case Modes.VR:
        this.fsButton.style.display = 'none';
        this.vrButton.style.display = 'none';
        break;
    }
  
    // Hack for Safari Mac/iOS to force relayout (svg-specific issue)
    // http://goo.gl/hjgR6r
    var oldValue = this.fsButton.style.display;
    this.fsButton.style.display = 'inline-block';
    this.fsButton.offsetHeight;
    this.fsButton.style.display = oldValue;
  };
  
  ButtonManager.prototype.setVisibility = function(isVisible) {
    this.isVisible = isVisible;
    this.fsButton.style.display = isVisible ? 'block' : 'none';
    this.vrButton.style.display = isVisible ? 'block' : 'none';
  };
  
  ButtonManager.prototype.createClickHandler_ = function(eventName) {
    return function(e) {
      e.stopPropagation();
      e.preventDefault();
      this.emit(eventName);
    }.bind(this);
  };
  
  ButtonManager.prototype.loadIcons_ = function() {
    // Preload some hard-coded SVG.
    this.ICONS = {};
    this.ICONS.cardboard = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMjAuNzQgNkgzLjIxQzIuNTUgNiAyIDYuNTcgMiA3LjI4djEwLjQ0YzAgLjcuNTUgMS4yOCAxLjIzIDEuMjhoNC43OWMuNTIgMCAuOTYtLjMzIDEuMTQtLjc5bDEuNC0zLjQ4Yy4yMy0uNTkuNzktMS4wMSAxLjQ0LTEuMDFzMS4yMS40MiAxLjQ1IDEuMDFsMS4zOSAzLjQ4Yy4xOS40Ni42My43OSAxLjExLjc5aDQuNzljLjcxIDAgMS4yNi0uNTcgMS4yNi0xLjI4VjcuMjhjMC0uNy0uNTUtMS4yOC0xLjI2LTEuMjh6TTcuNSAxNC42MmMtMS4xNyAwLTIuMTMtLjk1LTIuMTMtMi4xMiAwLTEuMTcuOTYtMi4xMyAyLjEzLTIuMTMgMS4xOCAwIDIuMTIuOTYgMi4xMiAyLjEzcy0uOTUgMi4xMi0yLjEyIDIuMTJ6bTkgMGMtMS4xNyAwLTIuMTMtLjk1LTIuMTMtMi4xMiAwLTEuMTcuOTYtMi4xMyAyLjEzLTIuMTNzMi4xMi45NiAyLjEyIDIuMTMtLjk1IDIuMTItMi4xMiAyLjEyeiIvPgogICAgPHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgyNHYyNEgwVjB6Ii8+Cjwvc3ZnPgo=');
    this.ICONS.fullscreen = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNNyAxNEg1djVoNXYtMkg3di0zem0tMi00aDJWN2gzVjVINXY1em0xMiA3aC0zdjJoNXYtNWgtMnYzek0xNCA1djJoM3YzaDJWNWgtNXoiLz4KPC9zdmc+Cg==');
    this.ICONS.exitFullscreen = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNNSAxNmgzdjNoMnYtNUg1djJ6bTMtOEg1djJoNVY1SDh2M3ptNiAxMWgydi0zaDN2LTJoLTV2NXptMi0xMVY1aC0ydjVoNVY4aC0zeiIvPgo8L3N2Zz4K');
    this.ICONS.settings = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNMTkuNDMgMTIuOThjLjA0LS4zMi4wNy0uNjQuMDctLjk4cy0uMDMtLjY2LS4wNy0uOThsMi4xMS0xLjY1Yy4xOS0uMTUuMjQtLjQyLjEyLS42NGwtMi0zLjQ2Yy0uMTItLjIyLS4zOS0uMy0uNjEtLjIybC0yLjQ5IDFjLS41Mi0uNC0xLjA4LS43My0xLjY5LS45OGwtLjM4LTIuNjVDMTQuNDYgMi4xOCAxNC4yNSAyIDE0IDJoLTRjLS4yNSAwLS40Ni4xOC0uNDkuNDJsLS4zOCAyLjY1Yy0uNjEuMjUtMS4xNy41OS0xLjY5Ljk4bC0yLjQ5LTFjLS4yMy0uMDktLjQ5IDAtLjYxLjIybC0yIDMuNDZjLS4xMy4yMi0uMDcuNDkuMTIuNjRsMi4xMSAxLjY1Yy0uMDQuMzItLjA3LjY1LS4wNy45OHMuMDMuNjYuMDcuOThsLTIuMTEgMS42NWMtLjE5LjE1LS4yNC40Mi0uMTIuNjRsMiAzLjQ2Yy4xMi4yMi4zOS4zLjYxLjIybDIuNDktMWMuNTIuNCAxLjA4LjczIDEuNjkuOThsLjM4IDIuNjVjLjAzLjI0LjI0LjQyLjQ5LjQyaDRjLjI1IDAgLjQ2LS4xOC40OS0uNDJsLjM4LTIuNjVjLjYxLS4yNSAxLjE3LS41OSAxLjY5LS45OGwyLjQ5IDFjLjIzLjA5LjQ5IDAgLjYxLS4yMmwyLTMuNDZjLjEyLS4yMi4wNy0uNDktLjEyLS42NGwtMi4xMS0xLjY1ek0xMiAxNS41Yy0xLjkzIDAtMy41LTEuNTctMy41LTMuNXMxLjU3LTMuNSAzLjUtMy41IDMuNSAxLjU3IDMuNSAzLjUtMS41NyAzLjUtMy41IDMuNXoiLz4KPC9zdmc+Cg==');
  };
  
  module.exports = ButtonManager;
  
  },{"./emitter.js":2,"./modes.js":3,"./util.js":4}],2:[function(_dereq_,module,exports){
  /*
   * Copyright 2015 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 Emitter() {
    this.callbacks = {};
  }
  
  Emitter.prototype.emit = function(eventName) {
    var callbacks = this.callbacks[eventName];
    if (!callbacks) {
      //console.log('No valid callback specified.');
      return;
    }
    var args = [].slice.call(arguments);
    // Eliminate the first param (the callback).
    args.shift();
    for (var i = 0; i < callbacks.length; i++) {
      callbacks[i].apply(this, args);
    }
  };
  
  Emitter.prototype.on = function(eventName, callback) {
    if (eventName in this.callbacks) {
      this.callbacks[eventName].push(callback);
    } else {
      this.callbacks[eventName] = [callback];
    }
  };
  
  module.exports = Emitter;
  
  },{}],3:[function(_dereq_,module,exports){
  /*
   * Copyright 2015 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 Modes = {
    UNKNOWN: 0,
    // Not fullscreen, just tracking.
    NORMAL: 1,
    // Magic window immersive mode.
    MAGIC_WINDOW: 2,
    // Full screen split screen VR mode.
    VR: 3,
  };
  
  module.exports = Modes;
  
  },{}],4:[function(_dereq_,module,exports){
  /*
   * Copyright 2015 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 = {};
  
  Util.base64 = function(mimeType, base64) {
    return 'data:' + mimeType + ';base64,' + base64;
  };
  
  Util.isMobile = function() {
    var check = false;
    (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
    return check;
  };
  
  Util.isFirefox = function() {
    return /firefox/i.test(navigator.userAgent);
  };
  
  Util.isIOS = function() {
    return /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
  };
  
  Util.isIFrame = function() {
    try {
      return window.self !== window.top;
    } catch (e) {
      return true;
    }
  };
  
  Util.appendQueryParameter = function(url, key, value) {
    // Determine delimiter based on if the URL already GET parameters in it.
    var delimiter = (url.indexOf('?') < 0 ? '?' : '&');
    url += delimiter + key + '=' + value;
    return url;
  };
  
  // From http://goo.gl/4WX3tg
  Util.getQueryParameter = function(name) {
    var name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
        results = regex.exec(location.search);
    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
  };
  
  Util.isLandscapeMode = function() {
    return (window.orientation == 90 || window.orientation == -90);
  };
  
  Util.getScreenWidth = function() {
    return Math.max(window.screen.width, window.screen.height) *
        window.devicePixelRatio;
  };
  
  Util.getScreenHeight = function() {
    return Math.min(window.screen.width, window.screen.height) *
        window.devicePixelRatio;
  };
  
  module.exports = Util;
  
  },{}],5:[function(_dereq_,module,exports){
  /*
   * Copyright 2015 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 ButtonManager = _dereq_('./button-manager.js');
  var Emitter = _dereq_('./emitter.js');
  var Modes = _dereq_('./modes.js');
  var Util = _dereq_('./util.js');
  
  /**
   * Helper for getting in and out of VR mode.
   */
  function WebVRManager(renderer, effect, params) {
    this.params = params || {};
  
    this.mode = Modes.UNKNOWN;
  
    // Set option to hide the button.
    this.hideButton = this.params.hideButton || false;
    // Whether or not the FOV should be distorted or un-distorted. By default, it
    // should be distorted, but in the case of vertex shader based distortion,
    // ensure that we use undistorted parameters.
    this.predistorted = !!this.params.predistorted;
  
    // Save the THREE.js renderer and effect for later.
    this.renderer = renderer;
    this.effect = effect;
    var polyfillWrapper = document.querySelector('.webvr-polyfill-fullscreen-wrapper');
    this.button = new ButtonManager(polyfillWrapper);
  
    this.isFullscreenDisabled = !!Util.getQueryParameter('no_fullscreen');
    this.startMode = Modes.NORMAL;
    var startModeParam = parseInt(Util.getQueryParameter('start_mode'));
    if (!isNaN(startModeParam)) {
      this.startMode = startModeParam;
    }
  
    if (this.hideButton) {
      this.button.setVisibility(false);
    }
  
    // Check if the browser is compatible with WebVR.
    this.getDeviceByType_(VRDisplay).then(function(hmd) {
      this.hmd = hmd;
  
      // Only enable VR mode if there's a VR device attached or we are running the
      // polyfill on mobile.
      if (!this.isVRCompatibleOverride) {
        this.isVRCompatible =  !hmd.isPolyfilled || Util.isMobile();
      }
  
      switch (this.startMode) {
        case Modes.MAGIC_WINDOW:
          this.setMode_(Modes.MAGIC_WINDOW);
          break;
        case Modes.VR:
          this.enterVRMode_();
          this.setMode_(Modes.VR);
          break;
        default:
          this.setMode_(Modes.NORMAL);
      }
  
      this.emit('initialized');
    }.bind(this));
  
    // Hook up button listeners.
    this.button.on('fs', this.onFSClick_.bind(this));
    this.button.on('vr', this.onVRClick_.bind(this));
  
    // Bind to fullscreen events.
    document.addEventListener('webkitfullscreenchange',
        this.onFullscreenChange_.bind(this));
    document.addEventListener('mozfullscreenchange',
        this.onFullscreenChange_.bind(this));
    document.addEventListener('msfullscreenchange',
        this.onFullscreenChange_.bind(this));
  
    // Bind to VR* specific events.
    window.addEventListener('vrdisplaypresentchange',
        this.onVRDisplayPresentChange_.bind(this));
    window.addEventListener('vrdisplaydeviceparamschange',
        this.onVRDisplayDeviceParamsChange_.bind(this));
  }
  
  WebVRManager.prototype = new Emitter();
  
  // Expose these values externally.
  WebVRManager.Modes = Modes;
  
  WebVRManager.prototype.render = function(scene, camera, timestamp) {
    // Scene may be an array of two scenes, one for each eye.
    if (scene instanceof Array) {
      this.effect.render(scene[0], camera);
    } else {
      this.effect.render(scene, camera);
    }
  };
  
  WebVRManager.prototype.setVRCompatibleOverride = function(isVRCompatible) {
    this.isVRCompatible = isVRCompatible;
    this.isVRCompatibleOverride = true;
  
    // Don't actually change modes, just update the buttons.
    this.button.setMode(this.mode, this.isVRCompatible);
  };
  
  WebVRManager.prototype.setFullscreenCallback = function(callback) {
    this.fullscreenCallback = callback;
  };
  
  WebVRManager.prototype.setVRCallback = function(callback) {
    this.vrCallback = callback;
  };
  
  WebVRManager.prototype.setExitFullscreenCallback = function(callback) {
    this.exitFullscreenCallback = callback;
  }
  
  /**
   * Promise returns true if there is at least one HMD device available.
   */
  WebVRManager.prototype.getDeviceByType_ = function(type) {
    return new Promise(function(resolve, reject) {
      navigator.getVRDisplays().then(function(displays) {
        // Promise succeeds, but check if there are any displays actually.
        for (var i = 0; i < displays.length; i++) {
          if (displays[i] instanceof type) {
            resolve(displays[i]);
            break;
          }
        }
        resolve(null);
      }, function() {
        // No displays are found.
        resolve(null);
      });
    });
  };
  
  /**
   * Helper for entering VR mode.
   */
  WebVRManager.prototype.enterVRMode_ = function() {
    this.hmd.requestPresent([{
      source: this.renderer.domElement,
      predistorted: this.predistorted
    }]);
  };
  
  WebVRManager.prototype.setMode_ = function(mode) {
    var oldMode = this.mode;
    if (mode == this.mode) {
      console.warn('Not changing modes, already in %s', mode);
      return;
    }
    // console.log('Mode change: %s => %s', this.mode, mode);
    this.mode = mode;
    this.button.setMode(mode, this.isVRCompatible);
  
    // Emit an event indicating the mode changed.
    this.emit('modechange', mode, oldMode);
  };
  
  /**
   * Main button was clicked.
   */
  WebVRManager.prototype.onFSClick_ = function() {
    switch (this.mode) {
      case Modes.NORMAL:
        // TODO: Remove this hack if/when iOS gets real fullscreen mode.
        // If this is an iframe on iOS, break out and open in no_fullscreen mode.
        if (Util.isIOS() && Util.isIFrame()) {
          if (this.fullscreenCallback) {
            this.fullscreenCallback();
          } else {
            var url = window.location.href;
            url = Util.appendQueryParameter(url, 'no_fullscreen', 'true');
            url = Util.appendQueryParameter(url, 'start_mode', Modes.MAGIC_WINDOW);
            top.location.href = url;
            return;
          }
        }
        this.setMode_(Modes.MAGIC_WINDOW);
        this.requestFullscreen_();
        break;
      case Modes.MAGIC_WINDOW:
        if (this.isFullscreenDisabled) {
          window.history.back();
          return;
        }
        if (this.exitFullscreenCallback) {
          this.exitFullscreenCallback();
        }
        this.setMode_(Modes.NORMAL);
        this.exitFullscreen_();
        break;
    }
  };
  
  /**
   * The VR button was clicked.
   */
  WebVRManager.prototype.onVRClick_ = function() {
    // TODO: Remove this hack when iOS has fullscreen mode.
    // If this is an iframe on iOS, break out and open in no_fullscreen mode.
    if (this.mode == Modes.NORMAL && Util.isIOS() && Util.isIFrame()) {
      if (this.vrCallback) {
        this.vrCallback();
      } else {
        var url = window.location.href;
        url = Util.appendQueryParameter(url, 'no_fullscreen', 'true');
        url = Util.appendQueryParameter(url, 'start_mode', Modes.VR);
        top.location.href = url;
        return;
      }
    }
    this.enterVRMode_();
  };
  
  WebVRManager.prototype.requestFullscreen_ = function() {
    var canvas = document.body;
    //var canvas = this.renderer.domElement;
    if (canvas.requestFullscreen) {
      canvas.requestFullscreen();
    } else if (canvas.mozRequestFullScreen) {
      canvas.mozRequestFullScreen();
    } else if (canvas.webkitRequestFullscreen) {
      canvas.webkitRequestFullscreen();
    } else if (canvas.msRequestFullscreen) {
      canvas.msRequestFullscreen();
    }
  };
  
  WebVRManager.prototype.exitFullscreen_ = function() {
    if (document.exitFullscreen) {
      document.exitFullscreen();
    } else if (document.mozCancelFullScreen) {
      document.mozCancelFullScreen();
    } else if (document.webkitExitFullscreen) {
      document.webkitExitFullscreen();
    } else if (document.msExitFullscreen) {
      document.msExitFullscreen();
    }
  };
  
  WebVRManager.prototype.onVRDisplayPresentChange_ = function(e) {
    console.log('onVRDisplayPresentChange_', e);
    if (this.hmd.isPresenting) {
      this.setMode_(Modes.VR);
    } else {
      this.setMode_(Modes.NORMAL);
    }
  };
  
  WebVRManager.prototype.onVRDisplayDeviceParamsChange_ = function(e) {
    console.log('onVRDisplayDeviceParamsChange_', e);
  };
  
  WebVRManager.prototype.onFullscreenChange_ = function(e) {
    // If we leave full-screen, go back to normal mode.
    if (document.webkitFullscreenElement === null ||
        document.mozFullScreenElement === null) {
      this.setMode_(Modes.NORMAL);
    }
  };
  
  module.exports = WebVRManager;
  
  },{"./button-manager.js":1,"./emitter.js":2,"./modes.js":3,"./util.js":4}]},{},[5])(5)
  });