summaryrefslogtreecommitdiff
path: root/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js')
-rw-r--r--chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js6196
1 files changed, 6196 insertions, 0 deletions
diff --git a/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js
new file mode 100644
index 00000000000..047e689bd52
--- /dev/null
+++ b/chromium/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js
@@ -0,0 +1,6196 @@
+/**
+ * @license
+ * webxr-polyfill
+ * Copyright (c) 2017 Google
+ * 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.
+ */
+
+/**
+ * @license
+ * cardboard-vr-display
+ * Copyright (c) 2015-2017 Google
+ * 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.
+ */
+
+/**
+ * @license
+ * webvr-polyfill-dpdb
+ * Copyright (c) 2017 Google
+ * 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.
+ */
+
+/**
+ * @license
+ * wglu-preserve-state
+ * Copyright (c) 2016, Brandon Jones.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * @license
+ * nosleep.js
+ * Copyright (c) 2017, Rich Tibbett
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+ typeof define === 'function' && define.amd ? define(factory) :
+ (global.WebXRPolyfill = factory());
+}(this, (function () { 'use strict';
+
+var _global = typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : {};
+
+var classCallCheck = function (instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+};
+
+var createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+}();
+
+
+
+
+
+
+
+
+
+var inherits = function (subClass, superClass) {
+ if (typeof superClass !== "function" && superClass !== null) {
+ throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+ }
+
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
+ constructor: {
+ value: subClass,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+};
+
+
+
+
+
+
+
+
+
+
+
+var possibleConstructorReturn = function (self, call) {
+ if (!self) {
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ }
+
+ return call && (typeof call === "object" || typeof call === "function") ? call : self;
+};
+
+var PRIVATE = Symbol('@@webxr-polyfill/EventTarget');
+var EventTarget = function () {
+ function EventTarget() {
+ classCallCheck(this, EventTarget);
+ this[PRIVATE] = {
+ listeners: new Map()
+ };
+ }
+ createClass(EventTarget, [{
+ key: 'addEventListener',
+ value: function addEventListener(type, listener) {
+ if (typeof type !== 'string') {
+ throw new Error('`type` must be a string');
+ }
+ if (typeof listener !== 'function') {
+ throw new Error('`listener` must be a function');
+ }
+ var typedListeners = this[PRIVATE].listeners.get(type) || [];
+ typedListeners.push(listener);
+ this[PRIVATE].listeners.set(type, typedListeners);
+ }
+ }, {
+ key: 'removeEventListener',
+ value: function removeEventListener(type, listener) {
+ if (typeof type !== 'string') {
+ throw new Error('`type` must be a string');
+ }
+ if (typeof listener !== 'function') {
+ throw new Error('`listener` must be a function');
+ }
+ var typedListeners = this[PRIVATE].listeners.get(type) || [];
+ for (var i = typedListeners.length; i >= 0; i--) {
+ if (typedListeners[i] === listener) {
+ typedListeners.pop();
+ }
+ }
+ }
+ }, {
+ key: 'dispatchEvent',
+ value: function dispatchEvent(type, event) {
+ var typedListeners = this[PRIVATE].listeners.get(type) || [];
+ var queue = [];
+ for (var i = 0; i < typedListeners.length; i++) {
+ queue[i] = typedListeners[i];
+ }
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+ try {
+ for (var _iterator = queue[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var listener = _step.value;
+ listener(event);
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+ if (typeof this['on' + type] === 'function') {
+ this['on' + type](event);
+ }
+ }
+ }]);
+ return EventTarget;
+}();
+
+var PRIVATE$1 = Symbol('@@webxr-polyfill/XR');
+var XR = function (_EventTarget) {
+ inherits(XR, _EventTarget);
+ function XR(device) {
+ classCallCheck(this, XR);
+ var _this = possibleConstructorReturn(this, (XR.__proto__ || Object.getPrototypeOf(XR)).call(this));
+ _this[PRIVATE$1] = {
+ device: device
+ };
+ return _this;
+ }
+ createClass(XR, [{
+ key: 'requestDevice',
+ value: function requestDevice() {
+ return new Promise(function ($return, $error) {
+ var device;
+ return Promise.resolve(this[PRIVATE$1].device).then(function ($await_1) {
+ try {
+ device = $await_1;
+ if (device) {
+ return $return(device);
+ }
+ return $error(new Error('NotFoundError'));
+ } catch ($boundEx) {
+ return $error($boundEx);
+ }
+ }.bind(this), $error);
+ }.bind(this));
+ }
+ }]);
+ return XR;
+}(EventTarget);
+
+var now = void 0;
+if ('performance' in _global === false) {
+ var startTime = Date.now();
+ now = function now() {
+ return Date.now() - startTime;
+ };
+} else {
+ now = function now() {
+ return performance.now();
+ };
+}
+var now$1 = now;
+
+var PRIVATE$2 = Symbol('@@webxr-polyfill/XRPresentationContext');
+var XRPresentationContext = function () {
+ function XRPresentationContext(canvas, ctx, glAttribs) {
+ classCallCheck(this, XRPresentationContext);
+ this[PRIVATE$2] = { canvas: canvas, ctx: ctx, glAttribs: glAttribs };
+ Object.assign(this, ctx);
+ }
+ createClass(XRPresentationContext, [{
+ key: 'canvas',
+ get: function get$$1() {
+ return this[PRIVATE$2].canvas;
+ }
+ }]);
+ return XRPresentationContext;
+}();
+
+var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
+
+
+var degree = Math.PI / 180;
+
+function create() {
+ var out = new ARRAY_TYPE(16);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+}
+
+function copy(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+}
+
+
+function identity(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+}
+
+function invert(out, a) {
+ var a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3];
+ var a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7];
+ var a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+ var a30 = a[12],
+ a31 = a[13],
+ a32 = a[14],
+ a33 = a[15];
+ var b00 = a00 * a11 - a01 * a10;
+ var b01 = a00 * a12 - a02 * a10;
+ var b02 = a00 * a13 - a03 * a10;
+ var b03 = a01 * a12 - a02 * a11;
+ var b04 = a01 * a13 - a03 * a11;
+ var b05 = a02 * a13 - a03 * a12;
+ var b06 = a20 * a31 - a21 * a30;
+ var b07 = a20 * a32 - a22 * a30;
+ var b08 = a20 * a33 - a23 * a30;
+ var b09 = a21 * a32 - a22 * a31;
+ var b10 = a21 * a33 - a23 * a31;
+ var b11 = a22 * a33 - a23 * a32;
+ var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+ out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+ out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+ out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+ out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+ out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+ out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+ out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+ out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+ out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+ return out;
+}
+
+
+function multiply(out, a, b) {
+ var a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3];
+ var a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7];
+ var a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+ var a30 = a[12],
+ a31 = a[13],
+ a32 = a[14],
+ a33 = a[15];
+ var b0 = b[0],
+ b1 = b[1],
+ b2 = b[2],
+ b3 = b[3];
+ out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+ out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+ out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+ out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+ b0 = b[4];b1 = b[5];b2 = b[6];b3 = b[7];
+ out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+ out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+ out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+ out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+ b0 = b[8];b1 = b[9];b2 = b[10];b3 = b[11];
+ out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+ out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+ out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+ out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+ b0 = b[12];b1 = b[13];b2 = b[14];b3 = b[15];
+ out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
+ out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
+ out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
+ out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
+ return out;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+function fromRotationTranslation(out, q, v) {
+ var x = q[0],
+ y = q[1],
+ z = q[2],
+ w = q[3];
+ var x2 = x + x;
+ var y2 = y + y;
+ var z2 = z + z;
+ var xx = x * x2;
+ var xy = x * y2;
+ var xz = x * z2;
+ var yy = y * y2;
+ var yz = y * z2;
+ var zz = z * z2;
+ var wx = w * x2;
+ var wy = w * y2;
+ var wz = w * z2;
+ out[0] = 1 - (yy + zz);
+ out[1] = xy + wz;
+ out[2] = xz - wy;
+ out[3] = 0;
+ out[4] = xy - wz;
+ out[5] = 1 - (xx + zz);
+ out[6] = yz + wx;
+ out[7] = 0;
+ out[8] = xz + wy;
+ out[9] = yz - wx;
+ out[10] = 1 - (xx + yy);
+ out[11] = 0;
+ out[12] = v[0];
+ out[13] = v[1];
+ out[14] = v[2];
+ out[15] = 1;
+ return out;
+}
+
+function getTranslation(out, mat) {
+ out[0] = mat[12];
+ out[1] = mat[13];
+ out[2] = mat[14];
+ return out;
+}
+
+function getRotation(out, mat) {
+ var trace = mat[0] + mat[5] + mat[10];
+ var S = 0;
+ if (trace > 0) {
+ S = Math.sqrt(trace + 1.0) * 2;
+ out[3] = 0.25 * S;
+ out[0] = (mat[6] - mat[9]) / S;
+ out[1] = (mat[8] - mat[2]) / S;
+ out[2] = (mat[1] - mat[4]) / S;
+ } else if (mat[0] > mat[5] && mat[0] > mat[10]) {
+ S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2;
+ out[3] = (mat[6] - mat[9]) / S;
+ out[0] = 0.25 * S;
+ out[1] = (mat[1] + mat[4]) / S;
+ out[2] = (mat[8] + mat[2]) / S;
+ } else if (mat[5] > mat[10]) {
+ S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2;
+ out[3] = (mat[8] - mat[2]) / S;
+ out[0] = (mat[1] + mat[4]) / S;
+ out[1] = 0.25 * S;
+ out[2] = (mat[6] + mat[9]) / S;
+ } else {
+ S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2;
+ out[3] = (mat[1] - mat[4]) / S;
+ out[0] = (mat[8] + mat[2]) / S;
+ out[1] = (mat[6] + mat[9]) / S;
+ out[2] = 0.25 * S;
+ }
+ return out;
+}
+
+
+
+
+function perspective(out, fovy, aspect, near, far) {
+ var f = 1.0 / Math.tan(fovy / 2);
+ var nf = 1 / (near - far);
+ out[0] = f / aspect;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = f;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 2 * far * near * nf;
+ out[15] = 0;
+ return out;
+}
+
+var PRIVATE$3 = Symbol('@@webxr-polyfill/XRDevicePose');
+var XRDevicePose = function () {
+ function XRDevicePose(polyfill) {
+ classCallCheck(this, XRDevicePose);
+ this[PRIVATE$3] = {
+ polyfill: polyfill,
+ leftViewMatrix: identity(new Float32Array(16)),
+ rightViewMatrix: identity(new Float32Array(16)),
+ poseModelMatrix: identity(new Float32Array(16))
+ };
+ }
+ createClass(XRDevicePose, [{
+ key: 'getViewMatrix',
+ value: function getViewMatrix(view) {
+ switch (view.eye) {
+ case 'left':
+ return this[PRIVATE$3].leftViewMatrix;
+ case 'right':
+ return this[PRIVATE$3].rightViewMatrix;
+ }
+ throw new Error('view is not a valid XREye');
+ }
+ }, {
+ key: 'updateFromFrameOfReference',
+ value: function updateFromFrameOfReference(frameOfRef) {
+ var pose = this[PRIVATE$3].polyfill.getBasePoseMatrix();
+ var leftViewMatrix = this[PRIVATE$3].polyfill.getBaseViewMatrix('left');
+ var rightViewMatrix = this[PRIVATE$3].polyfill.getBaseViewMatrix('right');
+ if (pose) {
+ frameOfRef.transformBasePoseMatrix(this[PRIVATE$3].poseModelMatrix, pose);
+ }
+ if (leftViewMatrix && rightViewMatrix) {
+ frameOfRef.transformBaseViewMatrix(this[PRIVATE$3].leftViewMatrix, leftViewMatrix, this[PRIVATE$3].poseModelMatrix);
+ frameOfRef.transformBaseViewMatrix(this[PRIVATE$3].rightViewMatrix, rightViewMatrix, this[PRIVATE$3].poseModelMatrix);
+ }
+ }
+ }, {
+ key: 'poseModelMatrix',
+ get: function get$$1() {
+ return this[PRIVATE$3].poseModelMatrix;
+ }
+ }]);
+ return XRDevicePose;
+}();
+
+var PRIVATE$4 = Symbol('@@webxr-polyfill/XRViewport');
+var XRViewport = function () {
+ function XRViewport(target) {
+ classCallCheck(this, XRViewport);
+ this[PRIVATE$4] = { target: target };
+ }
+ createClass(XRViewport, [{
+ key: 'x',
+ get: function get$$1() {
+ return this[PRIVATE$4].target.x;
+ }
+ }, {
+ key: 'y',
+ get: function get$$1() {
+ return this[PRIVATE$4].target.y;
+ }
+ }, {
+ key: 'width',
+ get: function get$$1() {
+ return this[PRIVATE$4].target.width;
+ }
+ }, {
+ key: 'height',
+ get: function get$$1() {
+ return this[PRIVATE$4].target.height;
+ }
+ }]);
+ return XRViewport;
+}();
+
+var XREyes = ['left', 'right'];
+var PRIVATE$5 = Symbol('@@webxr-polyfill/XRView');
+var XRView = function () {
+ function XRView(polyfill, eye, sessionId) {
+ classCallCheck(this, XRView);
+ if (!XREyes.includes(eye)) {
+ throw new Error('XREye must be one of: ' + XREyes);
+ }
+ var temp = Object.create(null);
+ var viewport = new XRViewport(temp);
+ this[PRIVATE$5] = {
+ polyfill: polyfill,
+ eye: eye,
+ viewport: viewport,
+ temp: temp,
+ sessionId: sessionId
+ };
+ }
+ createClass(XRView, [{
+ key: '_getViewport',
+ value: function _getViewport(layer) {
+ var viewport = this[PRIVATE$5].viewport;
+ if (this[PRIVATE$5].polyfill.getViewport(this[PRIVATE$5].sessionId, this.eye, layer, this[PRIVATE$5].temp)) {
+ return this[PRIVATE$5].viewport;
+ }
+ return undefined;
+ }
+ }, {
+ key: 'eye',
+ get: function get$$1() {
+ return this[PRIVATE$5].eye;
+ }
+ }, {
+ key: 'projectionMatrix',
+ get: function get$$1() {
+ return this[PRIVATE$5].polyfill.getProjectionMatrix(this.eye);
+ }
+ }]);
+ return XRView;
+}();
+
+var PRIVATE$6 = Symbol('@@webxr-polyfill/XRFrame');
+var XRFrame = function () {
+ function XRFrame(polyfill, session, sessionId) {
+ classCallCheck(this, XRFrame);
+ var devicePose = new XRDevicePose(polyfill);
+ var views = [new XRView(polyfill, 'left', sessionId)];
+ if (session.immersive) {
+ views.push(new XRView(polyfill, 'right', sessionId));
+ }
+ this[PRIVATE$6] = {
+ polyfill: polyfill,
+ devicePose: devicePose,
+ views: views,
+ session: session
+ };
+ }
+ createClass(XRFrame, [{
+ key: 'getDevicePose',
+ value: function getDevicePose(coordinateSystem) {
+ this[PRIVATE$6].devicePose.updateFromFrameOfReference(coordinateSystem);
+ return this[PRIVATE$6].devicePose;
+ }
+ }, {
+ key: 'getInputPose',
+ value: function getInputPose(inputSource, coordinateSystem) {
+ return this[PRIVATE$6].polyfill.getInputPose(inputSource, coordinateSystem);
+ }
+ }, {
+ key: 'session',
+ get: function get$$1() {
+ return this[PRIVATE$6].session;
+ }
+ }, {
+ key: 'views',
+ get: function get$$1() {
+ return this[PRIVATE$6].views;
+ }
+ }]);
+ return XRFrame;
+}();
+
+var PRIVATE$7 = Symbol('@@webxr-polyfill/XRStageBoundsPoint');
+var XRStageBoundsPoint = function () {
+ function XRStageBoundsPoint(x, z) {
+ classCallCheck(this, XRStageBoundsPoint);
+ this[PRIVATE$7] = { x: x, z: z };
+ }
+ createClass(XRStageBoundsPoint, [{
+ key: 'x',
+ get: function get$$1() {
+ return this[PRIVATE$7].x;
+ }
+ }, {
+ key: 'z',
+ get: function get$$1() {
+ return this[PRIVATE$7].z;
+ }
+ }]);
+ return XRStageBoundsPoint;
+}();
+
+var PRIVATE$8 = Symbol('@@webxr-polyfill/XRStageBounds');
+var XRStageBounds = function () {
+ function XRStageBounds(boundsData) {
+ classCallCheck(this, XRStageBounds);
+ var geometry = [];
+ for (var i = 0; i < boundsData.length; i += 2) {
+ geometry.push(new XRStageBoundsPoint(boundsData[i], boundsData[i + 1]));
+ }
+ this[PRIVATE$8] = { geometry: geometry };
+ }
+ createClass(XRStageBounds, [{
+ key: 'geometry',
+ get: function get$$1() {
+ return this[PRIVATE$8].geometry;
+ }
+ }]);
+ return XRStageBounds;
+}();
+
+var XRCoordinateSystem = function () {
+ function XRCoordinateSystem() {
+ classCallCheck(this, XRCoordinateSystem);
+ }
+ createClass(XRCoordinateSystem, [{
+ key: 'getTransformTo',
+ value: function getTransformTo(other) {
+ throw new Error('Not yet supported');
+ }
+ }]);
+ return XRCoordinateSystem;
+}();
+
+var DEFAULT_EMULATION_HEIGHT = 1.6;
+var PRIVATE$9 = Symbol('@@webxr-polyfill/XRFrameOfReference');
+var XRFrameOfReferenceTypes = ['head-model', 'eye-level', 'stage'];
+var XRFrameOfReferenceOptions = Object.freeze({
+ disableStageEmulation: false,
+ stageEmulationHeight: 0
+});
+var XRFrameOfReference = function (_XRCoordinateSystem) {
+ inherits(XRFrameOfReference, _XRCoordinateSystem);
+ function XRFrameOfReference(polyfill, type, options, transform, bounds) {
+ classCallCheck(this, XRFrameOfReference);
+ options = Object.assign({}, XRFrameOfReferenceOptions, options);
+ if (!XRFrameOfReferenceTypes.includes(type)) {
+ throw new Error('XRFrameOfReferenceType must be one of ' + XRFrameOfReferenceTypes);
+ }
+ var _this = possibleConstructorReturn(this, (XRFrameOfReference.__proto__ || Object.getPrototypeOf(XRFrameOfReference)).call(this));
+ if (type === 'stage' && options.disableStageEmulation && !transform) {
+ throw new Error('XRFrameOfReference cannot use \'stage\' type, if disabling emulation and platform does not provide');
+ }
+ var _options = options,
+ disableStageEmulation = _options.disableStageEmulation,
+ stageEmulationHeight = _options.stageEmulationHeight;
+ var emulatedHeight = 0;
+ if (type === 'stage' && !transform) {
+ emulatedHeight = stageEmulationHeight !== 0 ? stageEmulationHeight : DEFAULT_EMULATION_HEIGHT;
+ }
+ if (type === 'stage' && !transform) {
+ transform = identity(new Float32Array(16));
+ transform[13] = emulatedHeight;
+ }
+ _this[PRIVATE$9] = {
+ disableStageEmulation: disableStageEmulation,
+ stageEmulationHeight: stageEmulationHeight,
+ emulatedHeight: emulatedHeight,
+ type: type,
+ transform: transform,
+ polyfill: polyfill,
+ bounds: bounds
+ };
+ _this.onboundschange = undefined;
+ return _this;
+ }
+ createClass(XRFrameOfReference, [{
+ key: 'transformBasePoseMatrix',
+ value: function transformBasePoseMatrix(out, pose) {
+ if (this[PRIVATE$9].transform) {
+ multiply(out, this[PRIVATE$9].transform, pose);
+ return;
+ }
+ switch (this.type) {
+ case 'head-model':
+ if (out !== pose) {
+ copy(out, pose);
+ }
+ out[12] = out[13] = out[14] = 0;
+ return;
+ case 'eye-level':
+ if (out !== pose) {
+ copy(out, pose);
+ }
+ return;
+ }
+ }
+ }, {
+ key: 'transformBaseViewMatrix',
+ value: function transformBaseViewMatrix(out, view) {
+ var frameOfRef = this[PRIVATE$9].transform;
+ if (frameOfRef) {
+ invert(out, frameOfRef);
+ multiply(out, view, out);
+ }
+ else if (this.type === 'head-model') {
+ invert(out, view);
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ invert(out, out);
+ return out;
+ }
+ else {
+ copy(out, view);
+ }
+ return out;
+ }
+ }, {
+ key: 'bounds',
+ get: function get$$1() {
+ return this[PRIVATE$9].bounds;
+ }
+ }, {
+ key: 'emulatedHeight',
+ get: function get$$1() {
+ return this[PRIVATE$9].emulatedHeight;
+ }
+ }, {
+ key: 'type',
+ get: function get$$1() {
+ return this[PRIVATE$9].type;
+ }
+ }]);
+ return XRFrameOfReference;
+}(XRCoordinateSystem);
+
+var PRIVATE$10 = Symbol('@@webxr-polyfill/XRSession');
+var XRSessionCreationOptions = Object.freeze({
+ immersive: false,
+ outputContext: undefined
+});
+var validateSessionOptions = function validateSessionOptions(options) {
+ var immersive = options.immersive,
+ outputContext = options.outputContext;
+ if (!immersive && !outputContext) {
+ return false;
+ }
+ if (outputContext !== undefined && !(outputContext instanceof XRPresentationContext)) {
+ return false;
+ }
+ return true;
+};
+var XRSession = function (_EventTarget) {
+ inherits(XRSession, _EventTarget);
+ function XRSession(polyfill, device, sessionOptions, id) {
+ classCallCheck(this, XRSession);
+ sessionOptions = Object.assign({}, XRSessionCreationOptions, sessionOptions);
+ var _this = possibleConstructorReturn(this, (XRSession.__proto__ || Object.getPrototypeOf(XRSession)).call(this));
+ var _sessionOptions = sessionOptions,
+ immersive = _sessionOptions.immersive,
+ outputContext = _sessionOptions.outputContext;
+ _this[PRIVATE$10] = {
+ polyfill: polyfill,
+ device: device,
+ immersive: immersive,
+ outputContext: outputContext,
+ ended: false,
+ suspended: false,
+ suspendedCallback: null,
+ id: id
+ };
+ var frame = new XRFrame(polyfill, _this, _this[PRIVATE$10].id);
+ _this[PRIVATE$10].frame = frame;
+ _this[PRIVATE$10].onPresentationEnd = function (sessionId) {
+ if (sessionId !== _this[PRIVATE$10].id) {
+ _this[PRIVATE$10].suspended = false;
+ _this.dispatchEvent('focus', { session: _this });
+ var suspendedCallback = _this[PRIVATE$10].suspendedCallback;
+ _this[PRIVATE$10].suspendedCallback = null;
+ if (suspendedCallback) {
+ _this.requestAnimationFrame(suspendedCallback);
+ }
+ return;
+ }
+ _this[PRIVATE$10].ended = true;
+ polyfill.removeEventListener('@webvr-polyfill/vr-present-end', _this[PRIVATE$10].onPresentationEnd);
+ polyfill.removeEventListener('@webvr-polyfill/vr-present-start', _this[PRIVATE$10].onPresentationStart);
+ polyfill.removeEventListener('@@webvr-polyfill/input-select-start', _this[PRIVATE$10].onSelectStart);
+ polyfill.removeEventListener('@@webvr-polyfill/input-select-end', _this[PRIVATE$10].onSelectEnd);
+ _this.dispatchEvent('end', { session: _this });
+ };
+ polyfill.addEventListener('@@webxr-polyfill/vr-present-end', _this[PRIVATE$10].onPresentationEnd);
+ _this[PRIVATE$10].onPresentationStart = function (sessionId) {
+ if (sessionId === _this[PRIVATE$10].id) {
+ return;
+ }
+ _this[PRIVATE$10].suspended = true;
+ _this.dispatchEvent('blur', { session: _this });
+ };
+ polyfill.addEventListener('@@webxr-polyfill/vr-present-start', _this[PRIVATE$10].onPresentationStart);
+ _this[PRIVATE$10].onSelectStart = function (evt) {
+ if (evt.sessionId !== _this[PRIVATE$10].id) {
+ return;
+ }
+ _this.dispatchEvent('selectstart', {
+ frame: _this[PRIVATE$10].frame,
+ inputSource: evt.inputSource
+ });
+ };
+ polyfill.addEventListener('@@webxr-polyfill/input-select-start', _this[PRIVATE$10].onSelectStart);
+ _this[PRIVATE$10].onSelectEnd = function (evt) {
+ if (evt.sessionId !== _this[PRIVATE$10].id) {
+ return;
+ }
+ _this.dispatchEvent('selectend', {
+ frame: _this[PRIVATE$10].frame,
+ inputSource: evt.inputSource
+ });
+ _this.dispatchEvent('select', {
+ frame: _this[PRIVATE$10].frame,
+ inputSource: evt.inputSource
+ });
+ };
+ polyfill.addEventListener('@@webxr-polyfill/input-select-end', _this[PRIVATE$10].onSelectEnd);
+ _this.onblur = undefined;
+ _this.onfocus = undefined;
+ _this.onresetpose = undefined;
+ _this.onend = undefined;
+ _this.onselect = undefined;
+ _this.onselectstart = undefined;
+ _this.onselectend = undefined;
+ return _this;
+ }
+ createClass(XRSession, [{
+ key: 'requestFrameOfReference',
+ value: function requestFrameOfReference(type) {
+ var $args = arguments;return new Promise(function ($return, $error) {
+ var options, transform, bounds;
+ options = $args.length > 1 && $args[1] !== undefined ? $args[1] : {};
+ if (this[PRIVATE$10].ended) {
+ return $return();
+ }
+ options = Object.assign({}, XRFrameOfReferenceOptions, options);
+ if (!XRFrameOfReferenceTypes.includes(type)) {
+ return $error(new TypeError('XRFrameOfReferenceType must be one of ' + XRFrameOfReferenceTypes));
+ }
+ transform = null;
+ bounds = null;
+ var $Try_1_Post = function () {
+ try {
+ if (type === 'stage' && transform) {
+ bounds = this[PRIVATE$10].polyfill.requestStageBounds();
+ if (bounds) {
+ bounds = new XRStageBounds(bounds);
+ }
+ }
+ return $return(new XRFrameOfReference(this[PRIVATE$10].polyfill, type, options, transform, bounds));
+ } catch ($boundEx) {
+ return $error($boundEx);
+ }
+ }.bind(this);var $Try_1_Catch = function (e) {
+ try {
+ if (type !== 'stage' || options.disableStageEmulation) {
+ throw e;
+ }
+ return $Try_1_Post();
+ } catch ($boundEx) {
+ return $error($boundEx);
+ }
+ }.bind(this);
+ try {
+ return Promise.resolve(this[PRIVATE$10].polyfill.requestFrameOfReferenceTransform(type, options)).then(function ($await_2) {
+ try {
+ transform = $await_2;
+ return $Try_1_Post();
+ } catch ($boundEx) {
+ return $Try_1_Catch($boundEx);
+ }
+ }.bind(this), $Try_1_Catch);
+ } catch (e) {
+ $Try_1_Catch(e);
+ }
+ }.bind(this));
+ }
+ }, {
+ key: 'requestAnimationFrame',
+ value: function requestAnimationFrame(callback) {
+ var _this2 = this;
+ if (this[PRIVATE$10].ended) {
+ return;
+ }
+ if (this[PRIVATE$10].suspended && this[PRIVATE$10].suspendedCallback) {
+ return;
+ }
+ if (this[PRIVATE$10].suspended && !this[PRIVATE$10].suspendedCallback) {
+ this[PRIVATE$10].suspendedCallback = callback;
+ }
+ return this[PRIVATE$10].polyfill.requestAnimationFrame(function () {
+ _this2[PRIVATE$10].polyfill.onFrameStart(_this2[PRIVATE$10].id);
+ callback(now$1(), _this2[PRIVATE$10].frame);
+ _this2[PRIVATE$10].polyfill.onFrameEnd(_this2[PRIVATE$10].id);
+ });
+ }
+ }, {
+ key: 'cancelAnimationFrame',
+ value: function cancelAnimationFrame(handle) {
+ if (this[PRIVATE$10].ended) {
+ return;
+ }
+ this[PRIVATE$10].polyfill.cancelAnimationFrame(handle);
+ }
+ }, {
+ key: 'getInputSources',
+ value: function getInputSources() {
+ return this[PRIVATE$10].polyfill.getInputSources();
+ }
+ }, {
+ key: 'end',
+ value: function end() {
+ return new Promise(function ($return, $error) {
+ if (this[PRIVATE$10].ended) {
+ return $return();
+ }
+ if (!this.immersive) {
+ this[PRIVATE$10].ended = true;
+ this[PRIVATE$10].polyfill.removeEventListener('@@webvr-polyfill/vr-present-start', this[PRIVATE$10].onPresentationStart);
+ this[PRIVATE$10].polyfill.removeEventListener('@@webvr-polyfill/vr-present-end', this[PRIVATE$10].onPresentationEnd);
+ this[PRIVATE$10].polyfill.removeEventListener('@@webvr-polyfill/input-select-start', this[PRIVATE$10].onSelectStart);
+ this[PRIVATE$10].polyfill.removeEventListener('@@webvr-polyfill/input-select-end', this[PRIVATE$10].onSelectEnd);
+ this.dispatchEvent('end', { session: this });
+ }
+ return $return(this[PRIVATE$10].polyfill.endSession(this[PRIVATE$10].id));
+ }.bind(this));
+ }
+ }, {
+ key: 'device',
+ get: function get$$1() {
+ return this[PRIVATE$10].device;
+ }
+ }, {
+ key: 'immersive',
+ get: function get$$1() {
+ return this[PRIVATE$10].immersive;
+ }
+ }, {
+ key: 'outputContext',
+ get: function get$$1() {
+ return this[PRIVATE$10].outputContext;
+ }
+ }, {
+ key: 'depthNear',
+ get: function get$$1() {
+ return this[PRIVATE$10].polyfill.depthNear;
+ }
+ ,
+ set: function set$$1(value) {
+ this[PRIVATE$10].polyfill.depthNear = value;
+ }
+ }, {
+ key: 'depthFar',
+ get: function get$$1() {
+ return this[PRIVATE$10].polyfill.depthFar;
+ }
+ ,
+ set: function set$$1(value) {
+ this[PRIVATE$10].polyfill.depthFar = value;
+ }
+ }, {
+ key: 'environmentBlendMode',
+ get: function get$$1() {
+ return this[PRIVATE$10].polyfill.environmentBlendMode || 'opaque';
+ }
+ }, {
+ key: 'baseLayer',
+ get: function get$$1() {
+ return this[PRIVATE$10].baseLayer;
+ }
+ ,
+ set: function set$$1(value) {
+ if (this[PRIVATE$10].ended) {
+ return;
+ }
+ this[PRIVATE$10].baseLayer = value;
+ this[PRIVATE$10].polyfill.onBaseLayerSet(this[PRIVATE$10].id, value);
+ }
+ }]);
+ return XRSession;
+}(EventTarget);
+
+var PRIVATE$11 = Symbol('@@webxr-polyfill/XRDevice');
+var XRDevice = function (_EventTarget) {
+ inherits(XRDevice, _EventTarget);
+ function XRDevice(polyfill) {
+ classCallCheck(this, XRDevice);
+ if (!polyfill) {
+ throw new Error('XRDevice must receive a PolyfilledXRDevice.');
+ }
+ var _this = possibleConstructorReturn(this, (XRDevice.__proto__ || Object.getPrototypeOf(XRDevice)).call(this));
+ _this[PRIVATE$11] = {
+ polyfill: polyfill,
+ immersiveSession: null,
+ nonImmersiveSessions: new Set()
+ };
+ _this.ondeactive = undefined;
+ return _this;
+ }
+ createClass(XRDevice, [{
+ key: 'supportsSession',
+ value: function supportsSession() {
+ var $args = arguments;return new Promise(function ($return, $error) {
+ var sessionOptions = $args.length > 0 && $args[0] !== undefined ? $args[0] : {};
+ sessionOptions = Object.assign({}, XRSessionCreationOptions, sessionOptions);
+ if (!validateSessionOptions(sessionOptions)) {
+ return $return(Promise.reject(null));
+ }
+ if (!this[PRIVATE$11].polyfill.supportsSession(sessionOptions)) {
+ return $return(Promise.reject(null));
+ }
+ return $return(null);
+ }.bind(this));
+ }
+ }, {
+ key: 'requestSession',
+ value: function requestSession(sessionOptions) {
+ return new Promise(function ($return, $error) {
+ var _this2, sessionId, session, onSessionEnd;
+ _this2 = this;
+ sessionOptions = Object.assign({}, XRSessionCreationOptions, sessionOptions);
+ if (!validateSessionOptions(sessionOptions)) {
+ return $error(new Error('NotSupportedError'));
+ }
+ if (this[PRIVATE$11].immersiveSession && sessionOptions.immersive) {
+ return $error(new Error('InvalidStateError'));
+ }
+ return Promise.resolve(this[PRIVATE$11].polyfill.requestSession(sessionOptions)).then(function ($await_1) {
+ try {
+ sessionId = $await_1;
+ session = new XRSession(this[PRIVATE$11].polyfill, this, sessionOptions, sessionId);
+ if (sessionOptions.immersive) {
+ this[PRIVATE$11].immersiveSession = session;
+ } else {
+ this[PRIVATE$11].nonImmersiveSessions.add(session);
+ }
+ onSessionEnd = function onSessionEnd() {
+ if (session.immersive) {
+ _this2[PRIVATE$11].immersiveSession = null;
+ } else {
+ _this2[PRIVATE$11].nonImmersiveSessions.delete(session);
+ }
+ session.removeEventListener('end', onSessionEnd);
+ };
+ session.addEventListener('end', onSessionEnd);
+ return $return(session);
+ } catch ($boundEx) {
+ return $error($boundEx);
+ }
+ }.bind(this), $error);
+ }.bind(this));
+ }
+ }]);
+ return XRDevice;
+}(EventTarget);
+
+var domPointROExport = 'DOMPointReadOnly' in _global ? DOMPointReadOnly : null;
+if (!domPointROExport) {
+ var PRIVATE$12 = Symbol('@@webxr-polyfill/DOMPointReadOnly');
+ domPointROExport = function () {
+ function DOMPointReadOnly(x, y, z, w) {
+ classCallCheck(this, DOMPointReadOnly);
+ if (arguments.length === 1) {
+ this[PRIVATE$12] = {
+ x: x.x,
+ y: x.y,
+ z: x.z,
+ w: x.w
+ };
+ } else if (arguments.length === 4) {
+ this[PRIVATE$12] = {
+ x: x,
+ y: y,
+ z: z,
+ w: w
+ };
+ } else {
+ throw new TypeError('Must supply either 1 or 4 arguments');
+ }
+ }
+ createClass(DOMPointReadOnly, [{
+ key: 'x',
+ get: function get$$1() {
+ return this[PRIVATE$12].x;
+ }
+ }, {
+ key: 'y',
+ get: function get$$1() {
+ return this[PRIVATE$12].y;
+ }
+ }, {
+ key: 'z',
+ get: function get$$1() {
+ return this[PRIVATE$12].z;
+ }
+ }, {
+ key: 'w',
+ get: function get$$1() {
+ return this[PRIVATE$12].w;
+ }
+ }]);
+ return DOMPointReadOnly;
+ }();
+}
+var DOMPointReadOnly$1 = domPointROExport;
+
+var XRRay =
+function XRRay() {
+ var origin = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new DOMPointReadOnly$1(0, 0, 0, 1);
+ var direction = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new DOMPointReadOnly$1(0, 0, -1, 0);
+ var transformMatrix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new Float32Array(16);
+ classCallCheck(this, XRRay);
+ if (!(origin instanceof DOMPointReadOnly$1)) {
+ throw new Error('origin must be a DOMPointReadOnly');
+ }
+ if (!(direction instanceof DOMPointReadOnly$1)) {
+ throw new Error('direction must be a DOMPointReadOnly');
+ }
+ if (!(transformMatrix instanceof Float32Array)) {
+ throw new Error('transformMatrix must be a Float32Array');
+ }
+ Object.defineProperties(this, {
+ origin: {
+ value: origin,
+ writable: false
+ },
+ direction: {
+ value: direction,
+ writable: false
+ },
+ transformMatrix: {
+ value: transformMatrix,
+ writable: false
+ }
+ });
+};
+
+var PRIVATE$13 = Symbol('@@webxr-polyfill/XRInputPose');
+var XRInputPose = function () {
+ function XRInputPose(inputSourceImpl, hasGripMatrix) {
+ classCallCheck(this, XRInputPose);
+ this[PRIVATE$13] = {
+ inputSourceImpl: inputSourceImpl,
+ targetRay: new XRRay(),
+ gripMatrix: hasGripMatrix ? create() : null
+ };
+ }
+ createClass(XRInputPose, [{
+ key: 'targetRay',
+ get: function get$$1() {
+ return this[PRIVATE$13].targetRay;
+ }
+ ,
+ set: function set$$1(value) {
+ this[PRIVATE$13].targetRay = value;
+ }
+ }, {
+ key: 'emulatedPosition',
+ get: function get$$1() {
+ return this[PRIVATE$13].inputSourceImpl.emulatedPosition;
+ }
+ }, {
+ key: 'gripMatrix',
+ get: function get$$1() {
+ return this[PRIVATE$13].gripMatrix;
+ }
+ }]);
+ return XRInputPose;
+}();
+
+var PRIVATE$14 = Symbol('@@webxr-polyfill/XRInputSource');
+var XRInputSource = function () {
+ function XRInputSource(impl) {
+ classCallCheck(this, XRInputSource);
+ this[PRIVATE$14] = {
+ impl: impl
+ };
+ }
+ createClass(XRInputSource, [{
+ key: 'handedness',
+ get: function get$$1() {
+ return this[PRIVATE$14].impl.handedness;
+ }
+ }, {
+ key: 'targetRayMode',
+ get: function get$$1() {
+ return this[PRIVATE$14].impl.targetRayMode;
+ }
+ }]);
+ return XRInputSource;
+}();
+
+var XRLayer = function () {
+ function XRLayer() {
+ classCallCheck(this, XRLayer);
+ }
+ createClass(XRLayer, [{
+ key: "getViewport",
+ value: function getViewport(view) {
+ return view._getViewport(this);
+ }
+ }]);
+ return XRLayer;
+}();
+
+var POLYFILLED_COMPATIBLE_XR_DEVICE = Symbol('@@webxr-polyfill/polyfilled-compatible-xr-device');
+var COMPATIBLE_XR_DEVICE = Symbol('@@webxr-polyfill/compatible-xr-device');
+
+var PRIVATE$15 = Symbol('@@webxr-polyfill/XRWebGLLayer');
+var XRWebGLLayerInit = Object.freeze({
+ antialias: true,
+ depth: false,
+ stencil: false,
+ alpha: true,
+ multiview: false,
+ framebufferScaleFactor: 0
+});
+var XRWebGLLayer = function (_XRLayer) {
+ inherits(XRWebGLLayer, _XRLayer);
+ function XRWebGLLayer(session, context) {
+ var layerInit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
+ classCallCheck(this, XRWebGLLayer);
+ var config = Object.assign({}, XRWebGLLayerInit, layerInit);
+ if (!(session instanceof XRSession)) {
+ throw new Error('session must be a XRSession');
+ }
+ if (session.ended) {
+ throw new Error('InvalidStateError');
+ }
+ if (context[POLYFILLED_COMPATIBLE_XR_DEVICE]) {
+ if (context[COMPATIBLE_XR_DEVICE] !== session.device) {
+ throw new Error('InvalidStateError');
+ }
+ }
+ var framebuffer = context.getParameter(context.FRAMEBUFFER_BINDING);
+ var _this = possibleConstructorReturn(this, (XRWebGLLayer.__proto__ || Object.getPrototypeOf(XRWebGLLayer)).call(this));
+ _this[PRIVATE$15] = {
+ context: context,
+ config: config,
+ framebuffer: framebuffer
+ };
+ return _this;
+ }
+ createClass(XRWebGLLayer, [{
+ key: 'requestViewportScaling',
+ value: function requestViewportScaling(viewportScaleFactor) {
+ console.warn('requestViewportScaling is not yet implemented');
+ }
+ }, {
+ key: 'context',
+ get: function get$$1() {
+ return this[PRIVATE$15].context;
+ }
+ }, {
+ key: 'antialias',
+ get: function get$$1() {
+ return this[PRIVATE$15].config.antialias;
+ }
+ }, {
+ key: 'depth',
+ get: function get$$1() {
+ return this[PRIVATE$15].config.depth;
+ }
+ }, {
+ key: 'stencil',
+ get: function get$$1() {
+ return this[PRIVATE$15].config.stencil;
+ }
+ }, {
+ key: 'alpha',
+ get: function get$$1() {
+ return this[PRIVATE$15].config.alpha;
+ }
+ }, {
+ key: 'multiview',
+ get: function get$$1() {
+ return false;
+ }
+ }, {
+ key: 'framebuffer',
+ get: function get$$1() {
+ return this[PRIVATE$15].framebuffer;
+ }
+ }, {
+ key: 'framebufferWidth',
+ get: function get$$1() {
+ return this[PRIVATE$15].context.drawingBufferWidth;
+ }
+ }, {
+ key: 'framebufferHeight',
+ get: function get$$1() {
+ return this[PRIVATE$15].context.drawingBufferHeight;
+ }
+ }]);
+ return XRWebGLLayer;
+}(XRLayer);
+
+var API = {
+ XR: XR,
+ XRDevice: XRDevice,
+ XRSession: XRSession,
+ XRFrame: XRFrame,
+ XRView: XRView,
+ XRViewport: XRViewport,
+ XRDevicePose: XRDevicePose,
+ XRLayer: XRLayer,
+ XRWebGLLayer: XRWebGLLayer,
+ XRPresentationContext: XRPresentationContext,
+ XRCoordinateSystem: XRCoordinateSystem,
+ XRFrameOfReference: XRFrameOfReference,
+ XRStageBounds: XRStageBounds,
+ XRStageBoundsPoint: XRStageBoundsPoint,
+ XRInputPose: XRInputPose,
+ XRInputSource: XRInputSource,
+ XRRay: XRRay
+};
+
+var extendContextCompatibleXRDevice = function extendContextCompatibleXRDevice(Context) {
+ if (typeof Context.prototype.setCompatibleXRDevice === 'function') {
+ return false;
+ }
+ Context.prototype.setCompatibleXRDevice = function (xrDevice) {
+ var _this = this;
+ return new Promise(function (resolve, reject) {
+ if (xrDevice && typeof xrDevice.requestSession === 'function') {
+ resolve();
+ } else {
+ reject();
+ }
+ }).then(function () {
+ return _this[COMPATIBLE_XR_DEVICE] = xrDevice;
+ });
+ };
+ return true;
+};
+var extendGetContext = function extendGetContext(Canvas) {
+ var getContext = HTMLCanvasElement.prototype.getContext;
+ HTMLCanvasElement.prototype.getContext = function (contextType, glAttribs) {
+ if (contextType === 'xrpresent') {
+ var _ctx = getContext.call(this, '2d', glAttribs);
+ return new XRPresentationContext(this, _ctx, glAttribs);
+ }
+ var ctx = getContext.call(this, contextType, glAttribs);
+ ctx[POLYFILLED_COMPATIBLE_XR_DEVICE] = true;
+ if (glAttribs && 'compatibleXRDevice' in glAttribs) {
+ ctx[COMPATIBLE_XR_DEVICE] = glAttribs.compatibleXRDevice;
+ }
+ return ctx;
+ };
+};
+
+function create$1() {
+ var out = new ARRAY_TYPE(3);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ return out;
+}
+function clone$1(a) {
+ var out = new ARRAY_TYPE(3);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+}
+function length(a) {
+ var x = a[0];
+ var y = a[1];
+ var z = a[2];
+ return Math.sqrt(x * x + y * y + z * z);
+}
+function fromValues$1(x, y, z) {
+ var out = new ARRAY_TYPE(3);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+}
+function copy$1(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+}
+function set$2(out, x, y, z) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+}
+function add$1(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ return out;
+}
+function subtract$1(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ return out;
+}
+
+
+
+
+
+
+
+function scale$1(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ return out;
+}
+
+
+
+
+
+
+function normalize(out, a) {
+ var x = a[0];
+ var y = a[1];
+ var z = a[2];
+ var len = x * x + y * y + z * z;
+ if (len > 0) {
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ }
+ return out;
+}
+function dot(a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+}
+function cross(out, a, b) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2];
+ var bx = b[0],
+ by = b[1],
+ bz = b[2];
+ out[0] = ay * bz - az * by;
+ out[1] = az * bx - ax * bz;
+ out[2] = ax * by - ay * bx;
+ return out;
+}
+
+
+
+
+function transformMat4(out, a, m) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ var w = m[3] * x + m[7] * y + m[11] * z + m[15];
+ w = w || 1.0;
+ out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
+ out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
+ out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
+ return out;
+}
+
+function transformQuat(out, a, q) {
+ var qx = q[0],
+ qy = q[1],
+ qz = q[2],
+ qw = q[3];
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ var uvx = qy * z - qz * y,
+ uvy = qz * x - qx * z,
+ uvz = qx * y - qy * x;
+ var uuvx = qy * uvz - qz * uvy,
+ uuvy = qz * uvx - qx * uvz,
+ uuvz = qx * uvy - qy * uvx;
+ var w2 = qw * 2;
+ uvx *= w2;
+ uvy *= w2;
+ uvz *= w2;
+ uuvx *= 2;
+ uuvy *= 2;
+ uuvz *= 2;
+ out[0] = x + uvx + uuvx;
+ out[1] = y + uvy + uuvy;
+ out[2] = z + uvz + uuvz;
+ return out;
+}
+
+
+
+function angle(a, b) {
+ var tempA = fromValues$1(a[0], a[1], a[2]);
+ var tempB = fromValues$1(b[0], b[1], b[2]);
+ normalize(tempA, tempA);
+ normalize(tempB, tempB);
+ var cosine = dot(tempA, tempB);
+ if (cosine > 1.0) {
+ return 0;
+ } else if (cosine < -1.0) {
+ return Math.PI;
+ } else {
+ return Math.acos(cosine);
+ }
+}
+
+
+
+var sub$1 = subtract$1;
+
+
+
+
+var len = length;
+
+var forEach = function () {
+ var vec = create$1();
+ return function (a, stride, offset, count, fn, arg) {
+ var i = void 0,
+ l = void 0;
+ if (!stride) {
+ stride = 3;
+ }
+ if (!offset) {
+ offset = 0;
+ }
+ if (count) {
+ l = Math.min(count * stride + offset, a.length);
+ } else {
+ l = a.length;
+ }
+ for (i = offset; i < l; i += stride) {
+ vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2];
+ fn(vec, vec, arg);
+ a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2];
+ }
+ return a;
+ };
+}();
+
+var poseMatrixToXRRay = function poseMatrixToXRRay(poseMatrix) {
+ var rayOrigin = [];
+ var rayDirection = [];
+ set$2(rayOrigin, 0, 0, 0);
+ transformMat4(rayOrigin, rayOrigin, poseMatrix);
+ set$2(rayDirection, 0, 0, -1);
+ transformMat4(rayDirection, rayDirection, poseMatrix);
+ sub$1(rayDirection, rayDirection, rayOrigin);
+ normalize(rayDirection, rayDirection);
+ return new XRRay(new DOMPointReadOnly$1(rayOrigin[0], rayOrigin[1], rayOrigin[2], 1.0), new DOMPointReadOnly$1(rayDirection[0], rayDirection[1], rayDirection[2], 0.0), poseMatrix);
+};
+var isMobile = function isMobile(global) {
+ 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;
+ })(global.navigator.userAgent || global.navigator.vendor || global.opera);
+ return check;
+};
+var applyCanvasStylesForMinimalRendering = function applyCanvasStylesForMinimalRendering(canvas) {
+ canvas.style.display = 'block';
+ canvas.style.position = 'absolute';
+ canvas.style.width = canvas.style.height = '1px';
+ canvas.style.top = canvas.style.left = '0px';
+};
+
+var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
+
+
+
+function unwrapExports (x) {
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
+}
+
+function createCommonjsModule(fn, module) {
+ return module = { exports: {} }, fn(module, module.exports), module.exports;
+}
+
+var cardboardVrDisplay = createCommonjsModule(function (module, exports) {
+(function (global, factory) {
+ module.exports = factory();
+}(commonjsGlobal, (function () { var classCallCheck = function (instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+};
+var createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+}();
+var slicedToArray = function () {
+ function sliceIterator(arr, i) {
+ var _arr = [];
+ var _n = true;
+ var _d = false;
+ var _e = undefined;
+ try {
+ for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
+ _arr.push(_s.value);
+ if (i && _arr.length === i) break;
+ }
+ } catch (err) {
+ _d = true;
+ _e = err;
+ } finally {
+ try {
+ if (!_n && _i["return"]) _i["return"]();
+ } finally {
+ if (_d) throw _e;
+ }
+ }
+ return _arr;
+ }
+ return function (arr, i) {
+ if (Array.isArray(arr)) {
+ return arr;
+ } else if (Symbol.iterator in Object(arr)) {
+ return sliceIterator(arr, i);
+ } else {
+ throw new TypeError("Invalid attempt to destructure non-iterable instance");
+ }
+ };
+}();
+var MIN_TIMESTEP = 0.001;
+var MAX_TIMESTEP = 1;
+var base64 = function base64(mimeType, _base) {
+ return 'data:' + mimeType + ';base64,' + _base;
+};
+var lerp = function lerp(a, b, t) {
+ return a + (b - a) * t;
+};
+var isIOS = function () {
+ var isIOS = /iPad|iPhone|iPod/.test(navigator.platform);
+ return function () {
+ return isIOS;
+ };
+}();
+var isWebViewAndroid = function () {
+ var isWebViewAndroid = navigator.userAgent.indexOf('Version') !== -1 && navigator.userAgent.indexOf('Android') !== -1 && navigator.userAgent.indexOf('Chrome') !== -1;
+ return function () {
+ return isWebViewAndroid;
+ };
+}();
+var isSafari = function () {
+ var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
+ return function () {
+ return isSafari;
+ };
+}();
+var isFirefoxAndroid = function () {
+ var isFirefoxAndroid = navigator.userAgent.indexOf('Firefox') !== -1 && navigator.userAgent.indexOf('Android') !== -1;
+ return function () {
+ return isFirefoxAndroid;
+ };
+}();
+var getChromeVersion = function () {
+ var match = navigator.userAgent.match(/.*Chrome\/([0-9]+)/);
+ var value = match ? parseInt(match[1], 10) : null;
+ return function () {
+ return value;
+ };
+}();
+var isChromeWithoutDeviceMotion = function () {
+ var value = false;
+ if (getChromeVersion() === 65) {
+ var match = navigator.userAgent.match(/.*Chrome\/([0-9\.]*)/);
+ if (match) {
+ var _match$1$split = match[1].split('.'),
+ _match$1$split2 = slicedToArray(_match$1$split, 4),
+ major = _match$1$split2[0],
+ minor = _match$1$split2[1],
+ branch = _match$1$split2[2],
+ build = _match$1$split2[3];
+ value = parseInt(branch, 10) === 3325 && parseInt(build, 10) < 148;
+ }
+ }
+ return function () {
+ return value;
+ };
+}();
+var isR7 = function () {
+ var isR7 = navigator.userAgent.indexOf('R7 Build') !== -1;
+ return function () {
+ return isR7;
+ };
+}();
+var isLandscapeMode = function isLandscapeMode() {
+ var rtn = window.orientation == 90 || window.orientation == -90;
+ return isR7() ? !rtn : rtn;
+};
+var isTimestampDeltaValid = function isTimestampDeltaValid(timestampDeltaS) {
+ if (isNaN(timestampDeltaS)) {
+ return false;
+ }
+ if (timestampDeltaS <= MIN_TIMESTEP) {
+ return false;
+ }
+ if (timestampDeltaS > MAX_TIMESTEP) {
+ return false;
+ }
+ return true;
+};
+var getScreenWidth = function getScreenWidth() {
+ return Math.max(window.screen.width, window.screen.height) * window.devicePixelRatio;
+};
+var getScreenHeight = function getScreenHeight() {
+ return Math.min(window.screen.width, window.screen.height) * window.devicePixelRatio;
+};
+var requestFullscreen = function requestFullscreen(element) {
+ if (isWebViewAndroid()) {
+ return false;
+ }
+ if (element.requestFullscreen) {
+ element.requestFullscreen();
+ } else if (element.webkitRequestFullscreen) {
+ element.webkitRequestFullscreen();
+ } else if (element.mozRequestFullScreen) {
+ element.mozRequestFullScreen();
+ } else if (element.msRequestFullscreen) {
+ element.msRequestFullscreen();
+ } else {
+ return false;
+ }
+ return true;
+};
+var exitFullscreen = function exitFullscreen() {
+ if (document.exitFullscreen) {
+ document.exitFullscreen();
+ } else if (document.webkitExitFullscreen) {
+ document.webkitExitFullscreen();
+ } else if (document.mozCancelFullScreen) {
+ document.mozCancelFullScreen();
+ } else if (document.msExitFullscreen) {
+ document.msExitFullscreen();
+ } else {
+ return false;
+ }
+ return true;
+};
+var getFullscreenElement = function getFullscreenElement() {
+ return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
+};
+var linkProgram = function linkProgram(gl, vertexSource, fragmentSource, attribLocationMap) {
+ var vertexShader = gl.createShader(gl.VERTEX_SHADER);
+ gl.shaderSource(vertexShader, vertexSource);
+ gl.compileShader(vertexShader);
+ var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+ gl.shaderSource(fragmentShader, fragmentSource);
+ gl.compileShader(fragmentShader);
+ var program = gl.createProgram();
+ gl.attachShader(program, vertexShader);
+ gl.attachShader(program, fragmentShader);
+ for (var attribName in attribLocationMap) {
+ gl.bindAttribLocation(program, attribLocationMap[attribName], attribName);
+ }gl.linkProgram(program);
+ gl.deleteShader(vertexShader);
+ gl.deleteShader(fragmentShader);
+ return program;
+};
+var getProgramUniforms = function getProgramUniforms(gl, program) {
+ var uniforms = {};
+ var uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
+ var uniformName = '';
+ for (var i = 0; i < uniformCount; i++) {
+ var uniformInfo = gl.getActiveUniform(program, i);
+ uniformName = uniformInfo.name.replace('[0]', '');
+ uniforms[uniformName] = gl.getUniformLocation(program, uniformName);
+ }
+ return uniforms;
+};
+var orthoMatrix = function orthoMatrix(out, left, right, bottom, top, near, far) {
+ var lr = 1 / (left - right),
+ bt = 1 / (bottom - top),
+ nf = 1 / (near - far);
+ out[0] = -2 * lr;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = -2 * bt;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 2 * nf;
+ out[11] = 0;
+ out[12] = (left + right) * lr;
+ out[13] = (top + bottom) * bt;
+ out[14] = (far + near) * nf;
+ out[15] = 1;
+ return out;
+};
+var isMobile = function isMobile() {
+ 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;
+};
+var extend = function extend(dest, src) {
+ for (var key in src) {
+ if (src.hasOwnProperty(key)) {
+ dest[key] = src[key];
+ }
+ }
+ return dest;
+};
+var safariCssSizeWorkaround = function safariCssSizeWorkaround(canvas) {
+ if (isIOS()) {
+ var width = canvas.style.width;
+ var height = canvas.style.height;
+ canvas.style.width = parseInt(width) + 1 + 'px';
+ canvas.style.height = parseInt(height) + 'px';
+ setTimeout(function () {
+ canvas.style.width = width;
+ canvas.style.height = height;
+ }, 100);
+ }
+ window.canvas = canvas;
+};
+var frameDataFromPose = function () {
+ var piOver180 = Math.PI / 180.0;
+ var rad45 = Math.PI * 0.25;
+ function mat4_perspectiveFromFieldOfView(out, fov, near, far) {
+ var upTan = Math.tan(fov ? fov.upDegrees * piOver180 : rad45),
+ downTan = Math.tan(fov ? fov.downDegrees * piOver180 : rad45),
+ leftTan = Math.tan(fov ? fov.leftDegrees * piOver180 : rad45),
+ rightTan = Math.tan(fov ? fov.rightDegrees * piOver180 : rad45),
+ xScale = 2.0 / (leftTan + rightTan),
+ yScale = 2.0 / (upTan + downTan);
+ out[0] = xScale;
+ out[1] = 0.0;
+ out[2] = 0.0;
+ out[3] = 0.0;
+ out[4] = 0.0;
+ out[5] = yScale;
+ out[6] = 0.0;
+ out[7] = 0.0;
+ out[8] = -((leftTan - rightTan) * xScale * 0.5);
+ out[9] = (upTan - downTan) * yScale * 0.5;
+ out[10] = far / (near - far);
+ out[11] = -1.0;
+ out[12] = 0.0;
+ out[13] = 0.0;
+ out[14] = far * near / (near - far);
+ out[15] = 0.0;
+ return out;
+ }
+ function mat4_fromRotationTranslation(out, q, v) {
+ var x = q[0],
+ y = q[1],
+ z = q[2],
+ w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+ xx = x * x2,
+ xy = x * y2,
+ xz = x * z2,
+ yy = y * y2,
+ yz = y * z2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+ out[0] = 1 - (yy + zz);
+ out[1] = xy + wz;
+ out[2] = xz - wy;
+ out[3] = 0;
+ out[4] = xy - wz;
+ out[5] = 1 - (xx + zz);
+ out[6] = yz + wx;
+ out[7] = 0;
+ out[8] = xz + wy;
+ out[9] = yz - wx;
+ out[10] = 1 - (xx + yy);
+ out[11] = 0;
+ out[12] = v[0];
+ out[13] = v[1];
+ out[14] = v[2];
+ out[15] = 1;
+ return out;
+ }
+ function mat4_translate(out, a, v) {
+ var x = v[0],
+ y = v[1],
+ z = v[2],
+ a00,
+ a01,
+ a02,
+ a03,
+ a10,
+ a11,
+ a12,
+ a13,
+ a20,
+ a21,
+ a22,
+ a23;
+ if (a === out) {
+ out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
+ out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
+ out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
+ out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
+ } else {
+ a00 = a[0];a01 = a[1];a02 = a[2];a03 = a[3];
+ a10 = a[4];a11 = a[5];a12 = a[6];a13 = a[7];
+ a20 = a[8];a21 = a[9];a22 = a[10];a23 = a[11];
+ out[0] = a00;out[1] = a01;out[2] = a02;out[3] = a03;
+ out[4] = a10;out[5] = a11;out[6] = a12;out[7] = a13;
+ out[8] = a20;out[9] = a21;out[10] = a22;out[11] = a23;
+ out[12] = a00 * x + a10 * y + a20 * z + a[12];
+ out[13] = a01 * x + a11 * y + a21 * z + a[13];
+ out[14] = a02 * x + a12 * y + a22 * z + a[14];
+ out[15] = a03 * x + a13 * y + a23 * z + a[15];
+ }
+ return out;
+ }
+ function mat4_invert(out, a) {
+ var a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11],
+ a30 = a[12],
+ a31 = a[13],
+ a32 = a[14],
+ a33 = a[15],
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+ out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+ out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+ out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+ out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+ out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+ out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+ out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+ out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+ out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+ return out;
+ }
+ var defaultOrientation = new Float32Array([0, 0, 0, 1]);
+ var defaultPosition = new Float32Array([0, 0, 0]);
+ function updateEyeMatrices(projection, view, pose, fov, offset, vrDisplay) {
+ mat4_perspectiveFromFieldOfView(projection, fov || null, vrDisplay.depthNear, vrDisplay.depthFar);
+ var orientation = pose.orientation || defaultOrientation;
+ var position = pose.position || defaultPosition;
+ mat4_fromRotationTranslation(view, orientation, position);
+ if (offset) mat4_translate(view, view, offset);
+ mat4_invert(view, view);
+ }
+ return function (frameData, pose, vrDisplay) {
+ if (!frameData || !pose) return false;
+ frameData.pose = pose;
+ frameData.timestamp = pose.timestamp;
+ updateEyeMatrices(frameData.leftProjectionMatrix, frameData.leftViewMatrix, pose, vrDisplay._getFieldOfView("left"), vrDisplay._getEyeOffset("left"), vrDisplay);
+ updateEyeMatrices(frameData.rightProjectionMatrix, frameData.rightViewMatrix, pose, vrDisplay._getFieldOfView("right"), vrDisplay._getEyeOffset("right"), vrDisplay);
+ return true;
+ };
+}();
+var isInsideCrossOriginIFrame = function isInsideCrossOriginIFrame() {
+ var isFramed = window.self !== window.top;
+ var refOrigin = getOriginFromUrl(document.referrer);
+ var thisOrigin = getOriginFromUrl(window.location.href);
+ return isFramed && refOrigin !== thisOrigin;
+};
+var getOriginFromUrl = function getOriginFromUrl(url) {
+ var domainIdx;
+ var protoSepIdx = url.indexOf("://");
+ if (protoSepIdx !== -1) {
+ domainIdx = protoSepIdx + 3;
+ } else {
+ domainIdx = 0;
+ }
+ var domainEndIdx = url.indexOf('/', domainIdx);
+ if (domainEndIdx === -1) {
+ domainEndIdx = url.length;
+ }
+ return url.substring(0, domainEndIdx);
+};
+var getQuaternionAngle = function getQuaternionAngle(quat) {
+ if (quat.w > 1) {
+ console.warn('getQuaternionAngle: w > 1');
+ return 0;
+ }
+ var angle = 2 * Math.acos(quat.w);
+ return angle;
+};
+var warnOnce = function () {
+ var observedWarnings = {};
+ return function (key, message) {
+ if (observedWarnings[key] === undefined) {
+ console.warn('webvr-polyfill: ' + message);
+ observedWarnings[key] = true;
+ }
+ };
+}();
+var deprecateWarning = function deprecateWarning(deprecated, suggested) {
+ var alternative = suggested ? 'Please use ' + suggested + ' instead.' : '';
+ warnOnce(deprecated, deprecated + ' has been deprecated. ' + 'This may not work on native WebVR displays. ' + alternative);
+};
+function WGLUPreserveGLState(gl, bindings, callback) {
+ if (!bindings) {
+ callback(gl);
+ return;
+ }
+ var boundValues = [];
+ var activeTexture = null;
+ for (var i = 0; i < bindings.length; ++i) {
+ var binding = bindings[i];
+ switch (binding) {
+ case gl.TEXTURE_BINDING_2D:
+ case gl.TEXTURE_BINDING_CUBE_MAP:
+ var textureUnit = bindings[++i];
+ if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) {
+ console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit");
+ boundValues.push(null, null);
+ break;
+ }
+ if (!activeTexture) {
+ activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
+ }
+ gl.activeTexture(textureUnit);
+ boundValues.push(gl.getParameter(binding), null);
+ break;
+ case gl.ACTIVE_TEXTURE:
+ activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
+ boundValues.push(null);
+ break;
+ default:
+ boundValues.push(gl.getParameter(binding));
+ break;
+ }
+ }
+ callback(gl);
+ for (var i = 0; i < bindings.length; ++i) {
+ var binding = bindings[i];
+ var boundValue = boundValues[i];
+ switch (binding) {
+ case gl.ACTIVE_TEXTURE:
+ break;
+ case gl.ARRAY_BUFFER_BINDING:
+ gl.bindBuffer(gl.ARRAY_BUFFER, boundValue);
+ break;
+ case gl.COLOR_CLEAR_VALUE:
+ gl.clearColor(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
+ break;
+ case gl.COLOR_WRITEMASK:
+ gl.colorMask(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
+ break;
+ case gl.CURRENT_PROGRAM:
+ gl.useProgram(boundValue);
+ break;
+ case gl.ELEMENT_ARRAY_BUFFER_BINDING:
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boundValue);
+ break;
+ case gl.FRAMEBUFFER_BINDING:
+ gl.bindFramebuffer(gl.FRAMEBUFFER, boundValue);
+ break;
+ case gl.RENDERBUFFER_BINDING:
+ gl.bindRenderbuffer(gl.RENDERBUFFER, boundValue);
+ break;
+ case gl.TEXTURE_BINDING_2D:
+ var textureUnit = bindings[++i];
+ if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31)
+ break;
+ gl.activeTexture(textureUnit);
+ gl.bindTexture(gl.TEXTURE_2D, boundValue);
+ break;
+ case gl.TEXTURE_BINDING_CUBE_MAP:
+ var textureUnit = bindings[++i];
+ if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31)
+ break;
+ gl.activeTexture(textureUnit);
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, boundValue);
+ break;
+ case gl.VIEWPORT:
+ gl.viewport(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
+ break;
+ case gl.BLEND:
+ case gl.CULL_FACE:
+ case gl.DEPTH_TEST:
+ case gl.SCISSOR_TEST:
+ case gl.STENCIL_TEST:
+ if (boundValue) {
+ gl.enable(binding);
+ } else {
+ gl.disable(binding);
+ }
+ break;
+ default:
+ console.log("No GL restore behavior for 0x" + binding.toString(16));
+ break;
+ }
+ if (activeTexture) {
+ gl.activeTexture(activeTexture);
+ }
+ }
+}
+var glPreserveState = WGLUPreserveGLState;
+var distortionVS = ['attribute vec2 position;', 'attribute vec3 texCoord;', 'varying vec2 vTexCoord;', 'uniform vec4 viewportOffsetScale[2];', 'void main() {', ' vec4 viewport = viewportOffsetScale[int(texCoord.z)];', ' vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;', ' gl_Position = vec4( position, 1.0, 1.0 );', '}'].join('\n');
+var distortionFS = ['precision mediump float;', 'uniform sampler2D diffuse;', 'varying vec2 vTexCoord;', 'void main() {', ' gl_FragColor = texture2D(diffuse, vTexCoord);', '}'].join('\n');
+function CardboardDistorter(gl, cardboardUI, bufferScale, dirtySubmitFrameBindings) {
+ this.gl = gl;
+ this.cardboardUI = cardboardUI;
+ this.bufferScale = bufferScale;
+ this.dirtySubmitFrameBindings = dirtySubmitFrameBindings;
+ this.ctxAttribs = gl.getContextAttributes();
+ this.meshWidth = 20;
+ this.meshHeight = 20;
+ this.bufferWidth = gl.drawingBufferWidth;
+ this.bufferHeight = gl.drawingBufferHeight;
+ this.realBindFramebuffer = gl.bindFramebuffer;
+ this.realEnable = gl.enable;
+ this.realDisable = gl.disable;
+ this.realColorMask = gl.colorMask;
+ this.realClearColor = gl.clearColor;
+ this.realViewport = gl.viewport;
+ if (!isIOS()) {
+ this.realCanvasWidth = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'width');
+ this.realCanvasHeight = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'height');
+ }
+ this.isPatched = false;
+ this.lastBoundFramebuffer = null;
+ this.cullFace = false;
+ this.depthTest = false;
+ this.blend = false;
+ this.scissorTest = false;
+ this.stencilTest = false;
+ this.viewport = [0, 0, 0, 0];
+ this.colorMask = [true, true, true, true];
+ this.clearColor = [0, 0, 0, 0];
+ this.attribs = {
+ position: 0,
+ texCoord: 1
+ };
+ this.program = linkProgram(gl, distortionVS, distortionFS, this.attribs);
+ this.uniforms = getProgramUniforms(gl, this.program);
+ this.viewportOffsetScale = new Float32Array(8);
+ this.setTextureBounds();
+ this.vertexBuffer = gl.createBuffer();
+ this.indexBuffer = gl.createBuffer();
+ this.indexCount = 0;
+ this.renderTarget = gl.createTexture();
+ this.framebuffer = gl.createFramebuffer();
+ this.depthStencilBuffer = null;
+ this.depthBuffer = null;
+ this.stencilBuffer = null;
+ if (this.ctxAttribs.depth && this.ctxAttribs.stencil) {
+ this.depthStencilBuffer = gl.createRenderbuffer();
+ } else if (this.ctxAttribs.depth) {
+ this.depthBuffer = gl.createRenderbuffer();
+ } else if (this.ctxAttribs.stencil) {
+ this.stencilBuffer = gl.createRenderbuffer();
+ }
+ this.patch();
+ this.onResize();
+}
+CardboardDistorter.prototype.destroy = function () {
+ var gl = this.gl;
+ this.unpatch();
+ gl.deleteProgram(this.program);
+ gl.deleteBuffer(this.vertexBuffer);
+ gl.deleteBuffer(this.indexBuffer);
+ gl.deleteTexture(this.renderTarget);
+ gl.deleteFramebuffer(this.framebuffer);
+ if (this.depthStencilBuffer) {
+ gl.deleteRenderbuffer(this.depthStencilBuffer);
+ }
+ if (this.depthBuffer) {
+ gl.deleteRenderbuffer(this.depthBuffer);
+ }
+ if (this.stencilBuffer) {
+ gl.deleteRenderbuffer(this.stencilBuffer);
+ }
+ if (this.cardboardUI) {
+ this.cardboardUI.destroy();
+ }
+};
+CardboardDistorter.prototype.onResize = function () {
+ var gl = this.gl;
+ var self = this;
+ var glState = [gl.RENDERBUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0];
+ glPreserveState(gl, glState, function (gl) {
+ self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);
+ if (self.scissorTest) {
+ self.realDisable.call(gl, gl.SCISSOR_TEST);
+ }
+ self.realColorMask.call(gl, true, true, true, true);
+ self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ self.realClearColor.call(gl, 0, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.framebuffer);
+ gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);
+ gl.texImage2D(gl.TEXTURE_2D, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, self.bufferWidth, self.bufferHeight, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, gl.UNSIGNED_BYTE, null);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, self.renderTarget, 0);
+ if (self.ctxAttribs.depth && self.ctxAttribs.stencil) {
+ gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthStencilBuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, self.bufferWidth, self.bufferHeight);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.depthStencilBuffer);
+ } else if (self.ctxAttribs.depth) {
+ gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthBuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, self.bufferWidth, self.bufferHeight);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, self.depthBuffer);
+ } else if (self.ctxAttribs.stencil) {
+ gl.bindRenderbuffer(gl.RENDERBUFFER, self.stencilBuffer);
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, self.bufferWidth, self.bufferHeight);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.stencilBuffer);
+ }
+ if (!gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) {
+ console.error('Framebuffer incomplete!');
+ }
+ self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);
+ if (self.scissorTest) {
+ self.realEnable.call(gl, gl.SCISSOR_TEST);
+ }
+ self.realColorMask.apply(gl, self.colorMask);
+ self.realViewport.apply(gl, self.viewport);
+ self.realClearColor.apply(gl, self.clearColor);
+ });
+ if (this.cardboardUI) {
+ this.cardboardUI.onResize();
+ }
+};
+CardboardDistorter.prototype.patch = function () {
+ if (this.isPatched) {
+ return;
+ }
+ var self = this;
+ var canvas = this.gl.canvas;
+ var gl = this.gl;
+ if (!isIOS()) {
+ canvas.width = getScreenWidth() * this.bufferScale;
+ canvas.height = getScreenHeight() * this.bufferScale;
+ Object.defineProperty(canvas, 'width', {
+ configurable: true,
+ enumerable: true,
+ get: function get() {
+ return self.bufferWidth;
+ },
+ set: function set(value) {
+ self.bufferWidth = value;
+ self.realCanvasWidth.set.call(canvas, value);
+ self.onResize();
+ }
+ });
+ Object.defineProperty(canvas, 'height', {
+ configurable: true,
+ enumerable: true,
+ get: function get() {
+ return self.bufferHeight;
+ },
+ set: function set(value) {
+ self.bufferHeight = value;
+ self.realCanvasHeight.set.call(canvas, value);
+ self.onResize();
+ }
+ });
+ }
+ this.lastBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
+ if (this.lastBoundFramebuffer == null) {
+ this.lastBoundFramebuffer = this.framebuffer;
+ this.gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
+ }
+ this.gl.bindFramebuffer = function (target, framebuffer) {
+ self.lastBoundFramebuffer = framebuffer ? framebuffer : self.framebuffer;
+ self.realBindFramebuffer.call(gl, target, self.lastBoundFramebuffer);
+ };
+ this.cullFace = gl.getParameter(gl.CULL_FACE);
+ this.depthTest = gl.getParameter(gl.DEPTH_TEST);
+ this.blend = gl.getParameter(gl.BLEND);
+ this.scissorTest = gl.getParameter(gl.SCISSOR_TEST);
+ this.stencilTest = gl.getParameter(gl.STENCIL_TEST);
+ gl.enable = function (pname) {
+ switch (pname) {
+ case gl.CULL_FACE:
+ self.cullFace = true;break;
+ case gl.DEPTH_TEST:
+ self.depthTest = true;break;
+ case gl.BLEND:
+ self.blend = true;break;
+ case gl.SCISSOR_TEST:
+ self.scissorTest = true;break;
+ case gl.STENCIL_TEST:
+ self.stencilTest = true;break;
+ }
+ self.realEnable.call(gl, pname);
+ };
+ gl.disable = function (pname) {
+ switch (pname) {
+ case gl.CULL_FACE:
+ self.cullFace = false;break;
+ case gl.DEPTH_TEST:
+ self.depthTest = false;break;
+ case gl.BLEND:
+ self.blend = false;break;
+ case gl.SCISSOR_TEST:
+ self.scissorTest = false;break;
+ case gl.STENCIL_TEST:
+ self.stencilTest = false;break;
+ }
+ self.realDisable.call(gl, pname);
+ };
+ this.colorMask = gl.getParameter(gl.COLOR_WRITEMASK);
+ gl.colorMask = function (r, g, b, a) {
+ self.colorMask[0] = r;
+ self.colorMask[1] = g;
+ self.colorMask[2] = b;
+ self.colorMask[3] = a;
+ self.realColorMask.call(gl, r, g, b, a);
+ };
+ this.clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE);
+ gl.clearColor = function (r, g, b, a) {
+ self.clearColor[0] = r;
+ self.clearColor[1] = g;
+ self.clearColor[2] = b;
+ self.clearColor[3] = a;
+ self.realClearColor.call(gl, r, g, b, a);
+ };
+ this.viewport = gl.getParameter(gl.VIEWPORT);
+ gl.viewport = function (x, y, w, h) {
+ self.viewport[0] = x;
+ self.viewport[1] = y;
+ self.viewport[2] = w;
+ self.viewport[3] = h;
+ self.realViewport.call(gl, x, y, w, h);
+ };
+ this.isPatched = true;
+ safariCssSizeWorkaround(canvas);
+};
+CardboardDistorter.prototype.unpatch = function () {
+ if (!this.isPatched) {
+ return;
+ }
+ var gl = this.gl;
+ var canvas = this.gl.canvas;
+ if (!isIOS()) {
+ Object.defineProperty(canvas, 'width', this.realCanvasWidth);
+ Object.defineProperty(canvas, 'height', this.realCanvasHeight);
+ }
+ canvas.width = this.bufferWidth;
+ canvas.height = this.bufferHeight;
+ gl.bindFramebuffer = this.realBindFramebuffer;
+ gl.enable = this.realEnable;
+ gl.disable = this.realDisable;
+ gl.colorMask = this.realColorMask;
+ gl.clearColor = this.realClearColor;
+ gl.viewport = this.realViewport;
+ if (this.lastBoundFramebuffer == this.framebuffer) {
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ }
+ this.isPatched = false;
+ setTimeout(function () {
+ safariCssSizeWorkaround(canvas);
+ }, 1);
+};
+CardboardDistorter.prototype.setTextureBounds = function (leftBounds, rightBounds) {
+ if (!leftBounds) {
+ leftBounds = [0, 0, 0.5, 1];
+ }
+ if (!rightBounds) {
+ rightBounds = [0.5, 0, 0.5, 1];
+ }
+ this.viewportOffsetScale[0] = leftBounds[0];
+ this.viewportOffsetScale[1] = leftBounds[1];
+ this.viewportOffsetScale[2] = leftBounds[2];
+ this.viewportOffsetScale[3] = leftBounds[3];
+ this.viewportOffsetScale[4] = rightBounds[0];
+ this.viewportOffsetScale[5] = rightBounds[1];
+ this.viewportOffsetScale[6] = rightBounds[2];
+ this.viewportOffsetScale[7] = rightBounds[3];
+};
+CardboardDistorter.prototype.submitFrame = function () {
+ var gl = this.gl;
+ var self = this;
+ var glState = [];
+ if (!this.dirtySubmitFrameBindings) {
+ glState.push(gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0);
+ }
+ glPreserveState(gl, glState, function (gl) {
+ self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);
+ if (self.cullFace) {
+ self.realDisable.call(gl, gl.CULL_FACE);
+ }
+ if (self.depthTest) {
+ self.realDisable.call(gl, gl.DEPTH_TEST);
+ }
+ if (self.blend) {
+ self.realDisable.call(gl, gl.BLEND);
+ }
+ if (self.scissorTest) {
+ self.realDisable.call(gl, gl.SCISSOR_TEST);
+ }
+ if (self.stencilTest) {
+ self.realDisable.call(gl, gl.STENCIL_TEST);
+ }
+ self.realColorMask.call(gl, true, true, true, true);
+ self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ if (self.ctxAttribs.alpha || isIOS()) {
+ self.realClearColor.call(gl, 0, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+ gl.useProgram(self.program);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer);
+ gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
+ gl.enableVertexAttribArray(self.attribs.position);
+ gl.enableVertexAttribArray(self.attribs.texCoord);
+ gl.vertexAttribPointer(self.attribs.position, 2, gl.FLOAT, false, 20, 0);
+ gl.vertexAttribPointer(self.attribs.texCoord, 3, gl.FLOAT, false, 20, 8);
+ gl.activeTexture(gl.TEXTURE0);
+ gl.uniform1i(self.uniforms.diffuse, 0);
+ gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);
+ gl.uniform4fv(self.uniforms.viewportOffsetScale, self.viewportOffsetScale);
+ gl.drawElements(gl.TRIANGLES, self.indexCount, gl.UNSIGNED_SHORT, 0);
+ if (self.cardboardUI) {
+ self.cardboardUI.renderNoState();
+ }
+ self.realBindFramebuffer.call(self.gl, gl.FRAMEBUFFER, self.framebuffer);
+ if (!self.ctxAttribs.preserveDrawingBuffer) {
+ self.realClearColor.call(gl, 0, 0, 0, 0);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ }
+ if (!self.dirtySubmitFrameBindings) {
+ self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);
+ }
+ if (self.cullFace) {
+ self.realEnable.call(gl, gl.CULL_FACE);
+ }
+ if (self.depthTest) {
+ self.realEnable.call(gl, gl.DEPTH_TEST);
+ }
+ if (self.blend) {
+ self.realEnable.call(gl, gl.BLEND);
+ }
+ if (self.scissorTest) {
+ self.realEnable.call(gl, gl.SCISSOR_TEST);
+ }
+ if (self.stencilTest) {
+ self.realEnable.call(gl, gl.STENCIL_TEST);
+ }
+ self.realColorMask.apply(gl, self.colorMask);
+ self.realViewport.apply(gl, self.viewport);
+ if (self.ctxAttribs.alpha || !self.ctxAttribs.preserveDrawingBuffer) {
+ self.realClearColor.apply(gl, self.clearColor);
+ }
+ });
+ if (isIOS()) {
+ var canvas = gl.canvas;
+ if (canvas.width != self.bufferWidth || canvas.height != self.bufferHeight) {
+ self.bufferWidth = canvas.width;
+ self.bufferHeight = canvas.height;
+ self.onResize();
+ }
+ }
+};
+CardboardDistorter.prototype.updateDeviceInfo = function (deviceInfo) {
+ var gl = this.gl;
+ var self = this;
+ var glState = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING];
+ glPreserveState(gl, glState, function (gl) {
+ var vertices = self.computeMeshVertices_(self.meshWidth, self.meshHeight, deviceInfo);
+ gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
+ if (!self.indexCount) {
+ var indices = self.computeMeshIndices_(self.meshWidth, self.meshHeight);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
+ self.indexCount = indices.length;
+ }
+ });
+};
+CardboardDistorter.prototype.computeMeshVertices_ = function (width, height, deviceInfo) {
+ var vertices = new Float32Array(2 * width * height * 5);
+ var lensFrustum = deviceInfo.getLeftEyeVisibleTanAngles();
+ var noLensFrustum = deviceInfo.getLeftEyeNoLensTanAngles();
+ var viewport = deviceInfo.getLeftEyeVisibleScreenRect(noLensFrustum);
+ var vidx = 0;
+ for (var e = 0; e < 2; e++) {
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++, vidx++) {
+ var u = i / (width - 1);
+ var v = j / (height - 1);
+ var s = u;
+ var t = v;
+ var x = lerp(lensFrustum[0], lensFrustum[2], u);
+ var y = lerp(lensFrustum[3], lensFrustum[1], v);
+ var d = Math.sqrt(x * x + y * y);
+ var r = deviceInfo.distortion.distortInverse(d);
+ var p = x * r / d;
+ var q = y * r / d;
+ u = (p - noLensFrustum[0]) / (noLensFrustum[2] - noLensFrustum[0]);
+ v = (q - noLensFrustum[3]) / (noLensFrustum[1] - noLensFrustum[3]);
+ u = (viewport.x + u * viewport.width - 0.5) * 2.0;
+ v = (viewport.y + v * viewport.height - 0.5) * 2.0;
+ vertices[vidx * 5 + 0] = u;
+ vertices[vidx * 5 + 1] = v;
+ vertices[vidx * 5 + 2] = s;
+ vertices[vidx * 5 + 3] = t;
+ vertices[vidx * 5 + 4] = e;
+ }
+ }
+ var w = lensFrustum[2] - lensFrustum[0];
+ lensFrustum[0] = -(w + lensFrustum[0]);
+ lensFrustum[2] = w - lensFrustum[2];
+ w = noLensFrustum[2] - noLensFrustum[0];
+ noLensFrustum[0] = -(w + noLensFrustum[0]);
+ noLensFrustum[2] = w - noLensFrustum[2];
+ viewport.x = 1 - (viewport.x + viewport.width);
+ }
+ return vertices;
+};
+CardboardDistorter.prototype.computeMeshIndices_ = function (width, height) {
+ var indices = new Uint16Array(2 * (width - 1) * (height - 1) * 6);
+ var halfwidth = width / 2;
+ var halfheight = height / 2;
+ var vidx = 0;
+ var iidx = 0;
+ for (var e = 0; e < 2; e++) {
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++, vidx++) {
+ if (i == 0 || j == 0) continue;
+ if (i <= halfwidth == j <= halfheight) {
+ indices[iidx++] = vidx;
+ indices[iidx++] = vidx - width - 1;
+ indices[iidx++] = vidx - width;
+ indices[iidx++] = vidx - width - 1;
+ indices[iidx++] = vidx;
+ indices[iidx++] = vidx - 1;
+ } else {
+ indices[iidx++] = vidx - 1;
+ indices[iidx++] = vidx - width;
+ indices[iidx++] = vidx;
+ indices[iidx++] = vidx - width;
+ indices[iidx++] = vidx - 1;
+ indices[iidx++] = vidx - width - 1;
+ }
+ }
+ }
+ }
+ return indices;
+};
+CardboardDistorter.prototype.getOwnPropertyDescriptor_ = function (proto, attrName) {
+ var descriptor = Object.getOwnPropertyDescriptor(proto, attrName);
+ if (descriptor.get === undefined || descriptor.set === undefined) {
+ descriptor.configurable = true;
+ descriptor.enumerable = true;
+ descriptor.get = function () {
+ return this.getAttribute(attrName);
+ };
+ descriptor.set = function (val) {
+ this.setAttribute(attrName, val);
+ };
+ }
+ return descriptor;
+};
+var uiVS = ['attribute vec2 position;', 'uniform mat4 projectionMat;', 'void main() {', ' gl_Position = projectionMat * vec4( position, -1.0, 1.0 );', '}'].join('\n');
+var uiFS = ['precision mediump float;', 'uniform vec4 color;', 'void main() {', ' gl_FragColor = color;', '}'].join('\n');
+var DEG2RAD = Math.PI / 180.0;
+var kAnglePerGearSection = 60;
+var kOuterRimEndAngle = 12;
+var kInnerRimBeginAngle = 20;
+var kOuterRadius = 1;
+var kMiddleRadius = 0.75;
+var kInnerRadius = 0.3125;
+var kCenterLineThicknessDp = 4;
+var kButtonWidthDp = 28;
+var kTouchSlopFactor = 1.5;
+function CardboardUI(gl) {
+ this.gl = gl;
+ this.attribs = {
+ position: 0
+ };
+ this.program = linkProgram(gl, uiVS, uiFS, this.attribs);
+ this.uniforms = getProgramUniforms(gl, this.program);
+ this.vertexBuffer = gl.createBuffer();
+ this.gearOffset = 0;
+ this.gearVertexCount = 0;
+ this.arrowOffset = 0;
+ this.arrowVertexCount = 0;
+ this.projMat = new Float32Array(16);
+ this.listener = null;
+ this.onResize();
+}
+CardboardUI.prototype.destroy = function () {
+ var gl = this.gl;
+ if (this.listener) {
+ gl.canvas.removeEventListener('click', this.listener, false);
+ }
+ gl.deleteProgram(this.program);
+ gl.deleteBuffer(this.vertexBuffer);
+};
+CardboardUI.prototype.listen = function (optionsCallback, backCallback) {
+ var canvas = this.gl.canvas;
+ this.listener = function (event) {
+ var midline = canvas.clientWidth / 2;
+ var buttonSize = kButtonWidthDp * kTouchSlopFactor;
+ if (event.clientX > midline - buttonSize && event.clientX < midline + buttonSize && event.clientY > canvas.clientHeight - buttonSize) {
+ optionsCallback(event);
+ }
+ else if (event.clientX < buttonSize && event.clientY < buttonSize) {
+ backCallback(event);
+ }
+ };
+ canvas.addEventListener('click', this.listener, false);
+};
+CardboardUI.prototype.onResize = function () {
+ var gl = this.gl;
+ var self = this;
+ var glState = [gl.ARRAY_BUFFER_BINDING];
+ glPreserveState(gl, glState, function (gl) {
+ var vertices = [];
+ var midline = gl.drawingBufferWidth / 2;
+ var physicalPixels = Math.max(screen.width, screen.height) * window.devicePixelRatio;
+ var scalingRatio = gl.drawingBufferWidth / physicalPixels;
+ var dps = scalingRatio * window.devicePixelRatio;
+ var lineWidth = kCenterLineThicknessDp * dps / 2;
+ var buttonSize = kButtonWidthDp * kTouchSlopFactor * dps;
+ var buttonScale = kButtonWidthDp * dps / 2;
+ var buttonBorder = (kButtonWidthDp * kTouchSlopFactor - kButtonWidthDp) * dps;
+ vertices.push(midline - lineWidth, buttonSize);
+ vertices.push(midline - lineWidth, gl.drawingBufferHeight);
+ vertices.push(midline + lineWidth, buttonSize);
+ vertices.push(midline + lineWidth, gl.drawingBufferHeight);
+ self.gearOffset = vertices.length / 2;
+ function addGearSegment(theta, r) {
+ var angle = (90 - theta) * DEG2RAD;
+ var x = Math.cos(angle);
+ var y = Math.sin(angle);
+ vertices.push(kInnerRadius * x * buttonScale + midline, kInnerRadius * y * buttonScale + buttonScale);
+ vertices.push(r * x * buttonScale + midline, r * y * buttonScale + buttonScale);
+ }
+ for (var i = 0; i <= 6; i++) {
+ var segmentTheta = i * kAnglePerGearSection;
+ addGearSegment(segmentTheta, kOuterRadius);
+ addGearSegment(segmentTheta + kOuterRimEndAngle, kOuterRadius);
+ addGearSegment(segmentTheta + kInnerRimBeginAngle, kMiddleRadius);
+ addGearSegment(segmentTheta + (kAnglePerGearSection - kInnerRimBeginAngle), kMiddleRadius);
+ addGearSegment(segmentTheta + (kAnglePerGearSection - kOuterRimEndAngle), kOuterRadius);
+ }
+ self.gearVertexCount = vertices.length / 2 - self.gearOffset;
+ self.arrowOffset = vertices.length / 2;
+ function addArrowVertex(x, y) {
+ vertices.push(buttonBorder + x, gl.drawingBufferHeight - buttonBorder - y);
+ }
+ var angledLineWidth = lineWidth / Math.sin(45 * DEG2RAD);
+ addArrowVertex(0, buttonScale);
+ addArrowVertex(buttonScale, 0);
+ addArrowVertex(buttonScale + angledLineWidth, angledLineWidth);
+ addArrowVertex(angledLineWidth, buttonScale + angledLineWidth);
+ addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);
+ addArrowVertex(0, buttonScale);
+ addArrowVertex(buttonScale, buttonScale * 2);
+ addArrowVertex(buttonScale + angledLineWidth, buttonScale * 2 - angledLineWidth);
+ addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);
+ addArrowVertex(0, buttonScale);
+ addArrowVertex(angledLineWidth, buttonScale - lineWidth);
+ addArrowVertex(kButtonWidthDp * dps, buttonScale - lineWidth);
+ addArrowVertex(angledLineWidth, buttonScale + lineWidth);
+ addArrowVertex(kButtonWidthDp * dps, buttonScale + lineWidth);
+ self.arrowVertexCount = vertices.length / 2 - self.arrowOffset;
+ gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+ });
+};
+CardboardUI.prototype.render = function () {
+ var gl = this.gl;
+ var self = this;
+ var glState = [gl.CULL_FACE, gl.DEPTH_TEST, gl.BLEND, gl.SCISSOR_TEST, gl.STENCIL_TEST, gl.COLOR_WRITEMASK, gl.VIEWPORT, gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING];
+ glPreserveState(gl, glState, function (gl) {
+ gl.disable(gl.CULL_FACE);
+ gl.disable(gl.DEPTH_TEST);
+ gl.disable(gl.BLEND);
+ gl.disable(gl.SCISSOR_TEST);
+ gl.disable(gl.STENCIL_TEST);
+ gl.colorMask(true, true, true, true);
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ self.renderNoState();
+ });
+};
+CardboardUI.prototype.renderNoState = function () {
+ var gl = this.gl;
+ gl.useProgram(this.program);
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
+ gl.enableVertexAttribArray(this.attribs.position);
+ gl.vertexAttribPointer(this.attribs.position, 2, gl.FLOAT, false, 8, 0);
+ gl.uniform4f(this.uniforms.color, 1.0, 1.0, 1.0, 1.0);
+ orthoMatrix(this.projMat, 0, gl.drawingBufferWidth, 0, gl.drawingBufferHeight, 0.1, 1024.0);
+ gl.uniformMatrix4fv(this.uniforms.projectionMat, false, this.projMat);
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+ gl.drawArrays(gl.TRIANGLE_STRIP, this.gearOffset, this.gearVertexCount);
+ gl.drawArrays(gl.TRIANGLE_STRIP, this.arrowOffset, this.arrowVertexCount);
+};
+function Distortion(coefficients) {
+ this.coefficients = coefficients;
+}
+Distortion.prototype.distortInverse = function (radius) {
+ var r0 = 0;
+ var r1 = 1;
+ var dr0 = radius - this.distort(r0);
+ while (Math.abs(r1 - r0) > 0.0001 ) {
+ var dr1 = radius - this.distort(r1);
+ var r2 = r1 - dr1 * ((r1 - r0) / (dr1 - dr0));
+ r0 = r1;
+ r1 = r2;
+ dr0 = dr1;
+ }
+ return r1;
+};
+Distortion.prototype.distort = function (radius) {
+ var r2 = radius * radius;
+ var ret = 0;
+ for (var i = 0; i < this.coefficients.length; i++) {
+ ret = r2 * (ret + this.coefficients[i]);
+ }
+ return (ret + 1) * radius;
+};
+var degToRad = Math.PI / 180;
+var radToDeg = 180 / Math.PI;
+var Vector3 = function Vector3(x, y, z) {
+ this.x = x || 0;
+ this.y = y || 0;
+ this.z = z || 0;
+};
+Vector3.prototype = {
+ constructor: Vector3,
+ set: function set(x, y, z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ return this;
+ },
+ copy: function copy(v) {
+ this.x = v.x;
+ this.y = v.y;
+ this.z = v.z;
+ return this;
+ },
+ length: function length() {
+ return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
+ },
+ normalize: function normalize() {
+ var scalar = this.length();
+ if (scalar !== 0) {
+ var invScalar = 1 / scalar;
+ this.multiplyScalar(invScalar);
+ } else {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ }
+ return this;
+ },
+ multiplyScalar: function multiplyScalar(scalar) {
+ this.x *= scalar;
+ this.y *= scalar;
+ this.z *= scalar;
+ },
+ applyQuaternion: function applyQuaternion(q) {
+ var x = this.x;
+ var y = this.y;
+ var z = this.z;
+ var qx = q.x;
+ var qy = q.y;
+ var qz = q.z;
+ var qw = q.w;
+ var ix = qw * x + qy * z - qz * y;
+ var iy = qw * y + qz * x - qx * z;
+ var iz = qw * z + qx * y - qy * x;
+ var iw = -qx * x - qy * y - qz * z;
+ this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return this;
+ },
+ dot: function dot(v) {
+ return this.x * v.x + this.y * v.y + this.z * v.z;
+ },
+ crossVectors: function crossVectors(a, b) {
+ var ax = a.x,
+ ay = a.y,
+ az = a.z;
+ var bx = b.x,
+ by = b.y,
+ bz = b.z;
+ this.x = ay * bz - az * by;
+ this.y = az * bx - ax * bz;
+ this.z = ax * by - ay * bx;
+ return this;
+ }
+};
+var Quaternion = function Quaternion(x, y, z, w) {
+ this.x = x || 0;
+ this.y = y || 0;
+ this.z = z || 0;
+ this.w = w !== undefined ? w : 1;
+};
+Quaternion.prototype = {
+ constructor: Quaternion,
+ set: function set(x, y, z, w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ return this;
+ },
+ copy: function copy(quaternion) {
+ this.x = quaternion.x;
+ this.y = quaternion.y;
+ this.z = quaternion.z;
+ this.w = quaternion.w;
+ return this;
+ },
+ setFromEulerXYZ: function setFromEulerXYZ(x, y, z) {
+ var c1 = Math.cos(x / 2);
+ var c2 = Math.cos(y / 2);
+ var c3 = Math.cos(z / 2);
+ var s1 = Math.sin(x / 2);
+ var s2 = Math.sin(y / 2);
+ var s3 = Math.sin(z / 2);
+ this.x = s1 * c2 * c3 + c1 * s2 * s3;
+ this.y = c1 * s2 * c3 - s1 * c2 * s3;
+ this.z = c1 * c2 * s3 + s1 * s2 * c3;
+ this.w = c1 * c2 * c3 - s1 * s2 * s3;
+ return this;
+ },
+ setFromEulerYXZ: function setFromEulerYXZ(x, y, z) {
+ var c1 = Math.cos(x / 2);
+ var c2 = Math.cos(y / 2);
+ var c3 = Math.cos(z / 2);
+ var s1 = Math.sin(x / 2);
+ var s2 = Math.sin(y / 2);
+ var s3 = Math.sin(z / 2);
+ this.x = s1 * c2 * c3 + c1 * s2 * s3;
+ this.y = c1 * s2 * c3 - s1 * c2 * s3;
+ this.z = c1 * c2 * s3 - s1 * s2 * c3;
+ this.w = c1 * c2 * c3 + s1 * s2 * s3;
+ return this;
+ },
+ setFromAxisAngle: function setFromAxisAngle(axis, angle) {
+ var halfAngle = angle / 2,
+ s = Math.sin(halfAngle);
+ this.x = axis.x * s;
+ this.y = axis.y * s;
+ this.z = axis.z * s;
+ this.w = Math.cos(halfAngle);
+ return this;
+ },
+ multiply: function multiply(q) {
+ return this.multiplyQuaternions(this, q);
+ },
+ multiplyQuaternions: function multiplyQuaternions(a, b) {
+ var qax = a.x,
+ qay = a.y,
+ qaz = a.z,
+ qaw = a.w;
+ var qbx = b.x,
+ qby = b.y,
+ qbz = b.z,
+ qbw = b.w;
+ this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
+ this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
+ this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
+ this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
+ return this;
+ },
+ inverse: function inverse() {
+ this.x *= -1;
+ this.y *= -1;
+ this.z *= -1;
+ this.normalize();
+ return this;
+ },
+ normalize: function normalize() {
+ var l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
+ if (l === 0) {
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.w = 1;
+ } else {
+ l = 1 / l;
+ this.x = this.x * l;
+ this.y = this.y * l;
+ this.z = this.z * l;
+ this.w = this.w * l;
+ }
+ return this;
+ },
+ slerp: function slerp(qb, t) {
+ if (t === 0) return this;
+ if (t === 1) return this.copy(qb);
+ var x = this.x,
+ y = this.y,
+ z = this.z,
+ w = this.w;
+ var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z;
+ if (cosHalfTheta < 0) {
+ this.w = -qb.w;
+ this.x = -qb.x;
+ this.y = -qb.y;
+ this.z = -qb.z;
+ cosHalfTheta = -cosHalfTheta;
+ } else {
+ this.copy(qb);
+ }
+ if (cosHalfTheta >= 1.0) {
+ this.w = w;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ return this;
+ }
+ var halfTheta = Math.acos(cosHalfTheta);
+ var sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta);
+ if (Math.abs(sinHalfTheta) < 0.001) {
+ this.w = 0.5 * (w + this.w);
+ this.x = 0.5 * (x + this.x);
+ this.y = 0.5 * (y + this.y);
+ this.z = 0.5 * (z + this.z);
+ return this;
+ }
+ var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta,
+ ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
+ this.w = w * ratioA + this.w * ratioB;
+ this.x = x * ratioA + this.x * ratioB;
+ this.y = y * ratioA + this.y * ratioB;
+ this.z = z * ratioA + this.z * ratioB;
+ return this;
+ },
+ setFromUnitVectors: function () {
+ var v1, r;
+ var EPS = 0.000001;
+ return function (vFrom, vTo) {
+ if (v1 === undefined) v1 = new Vector3();
+ r = vFrom.dot(vTo) + 1;
+ if (r < EPS) {
+ r = 0;
+ if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) {
+ v1.set(-vFrom.y, vFrom.x, 0);
+ } else {
+ v1.set(0, -vFrom.z, vFrom.y);
+ }
+ } else {
+ v1.crossVectors(vFrom, vTo);
+ }
+ this.x = v1.x;
+ this.y = v1.y;
+ this.z = v1.z;
+ this.w = r;
+ this.normalize();
+ return this;
+ };
+ }()
+};
+function Device(params) {
+ this.width = params.width || getScreenWidth();
+ this.height = params.height || getScreenHeight();
+ this.widthMeters = params.widthMeters;
+ this.heightMeters = params.heightMeters;
+ this.bevelMeters = params.bevelMeters;
+}
+var DEFAULT_ANDROID = new Device({
+ widthMeters: 0.110,
+ heightMeters: 0.062,
+ bevelMeters: 0.004
+});
+var DEFAULT_IOS = new Device({
+ widthMeters: 0.1038,
+ heightMeters: 0.0584,
+ bevelMeters: 0.004
+});
+var Viewers = {
+ CardboardV1: new CardboardViewer({
+ id: 'CardboardV1',
+ label: 'Cardboard I/O 2014',
+ fov: 40,
+ interLensDistance: 0.060,
+ baselineLensDistance: 0.035,
+ screenLensDistance: 0.042,
+ distortionCoefficients: [0.441, 0.156],
+ inverseCoefficients: [-0.4410035, 0.42756155, -0.4804439, 0.5460139, -0.58821183, 0.5733938, -0.48303202, 0.33299083, -0.17573841, 0.0651772, -0.01488963, 0.001559834]
+ }),
+ CardboardV2: new CardboardViewer({
+ id: 'CardboardV2',
+ label: 'Cardboard I/O 2015',
+ fov: 60,
+ interLensDistance: 0.064,
+ baselineLensDistance: 0.035,
+ screenLensDistance: 0.039,
+ distortionCoefficients: [0.34, 0.55],
+ inverseCoefficients: [-0.33836704, -0.18162185, 0.862655, -1.2462051, 1.0560602, -0.58208317, 0.21609078, -0.05444823, 0.009177956, -9.904169E-4, 6.183535E-5, -1.6981803E-6]
+ })
+};
+function DeviceInfo(deviceParams, additionalViewers) {
+ this.viewer = Viewers.CardboardV2;
+ this.updateDeviceParams(deviceParams);
+ this.distortion = new Distortion(this.viewer.distortionCoefficients);
+ for (var i = 0; i < additionalViewers.length; i++) {
+ var viewer = additionalViewers[i];
+ Viewers[viewer.id] = new CardboardViewer(viewer);
+ }
+}
+DeviceInfo.prototype.updateDeviceParams = function (deviceParams) {
+ this.device = this.determineDevice_(deviceParams) || this.device;
+};
+DeviceInfo.prototype.getDevice = function () {
+ return this.device;
+};
+DeviceInfo.prototype.setViewer = function (viewer) {
+ this.viewer = viewer;
+ this.distortion = new Distortion(this.viewer.distortionCoefficients);
+};
+DeviceInfo.prototype.determineDevice_ = function (deviceParams) {
+ if (!deviceParams) {
+ if (isIOS()) {
+ console.warn('Using fallback iOS device measurements.');
+ return DEFAULT_IOS;
+ } else {
+ console.warn('Using fallback Android device measurements.');
+ return DEFAULT_ANDROID;
+ }
+ }
+ var METERS_PER_INCH = 0.0254;
+ var metersPerPixelX = METERS_PER_INCH / deviceParams.xdpi;
+ var metersPerPixelY = METERS_PER_INCH / deviceParams.ydpi;
+ var width = getScreenWidth();
+ var height = getScreenHeight();
+ return new Device({
+ widthMeters: metersPerPixelX * width,
+ heightMeters: metersPerPixelY * height,
+ bevelMeters: deviceParams.bevelMm * 0.001
+ });
+};
+DeviceInfo.prototype.getDistortedFieldOfViewLeftEye = function () {
+ var viewer = this.viewer;
+ var device = this.device;
+ var distortion = this.distortion;
+ var eyeToScreenDistance = viewer.screenLensDistance;
+ var outerDist = (device.widthMeters - viewer.interLensDistance) / 2;
+ var innerDist = viewer.interLensDistance / 2;
+ var bottomDist = viewer.baselineLensDistance - device.bevelMeters;
+ var topDist = device.heightMeters - bottomDist;
+ var outerAngle = radToDeg * Math.atan(distortion.distort(outerDist / eyeToScreenDistance));
+ var innerAngle = radToDeg * Math.atan(distortion.distort(innerDist / eyeToScreenDistance));
+ var bottomAngle = radToDeg * Math.atan(distortion.distort(bottomDist / eyeToScreenDistance));
+ var topAngle = radToDeg * Math.atan(distortion.distort(topDist / eyeToScreenDistance));
+ return {
+ leftDegrees: Math.min(outerAngle, viewer.fov),
+ rightDegrees: Math.min(innerAngle, viewer.fov),
+ downDegrees: Math.min(bottomAngle, viewer.fov),
+ upDegrees: Math.min(topAngle, viewer.fov)
+ };
+};
+DeviceInfo.prototype.getLeftEyeVisibleTanAngles = function () {
+ var viewer = this.viewer;
+ var device = this.device;
+ var distortion = this.distortion;
+ var fovLeft = Math.tan(-degToRad * viewer.fov);
+ var fovTop = Math.tan(degToRad * viewer.fov);
+ var fovRight = Math.tan(degToRad * viewer.fov);
+ var fovBottom = Math.tan(-degToRad * viewer.fov);
+ var halfWidth = device.widthMeters / 4;
+ var halfHeight = device.heightMeters / 2;
+ var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight;
+ var centerX = viewer.interLensDistance / 2 - halfWidth;
+ var centerY = -verticalLensOffset;
+ var centerZ = viewer.screenLensDistance;
+ var screenLeft = distortion.distort((centerX - halfWidth) / centerZ);
+ var screenTop = distortion.distort((centerY + halfHeight) / centerZ);
+ var screenRight = distortion.distort((centerX + halfWidth) / centerZ);
+ var screenBottom = distortion.distort((centerY - halfHeight) / centerZ);
+ var result = new Float32Array(4);
+ result[0] = Math.max(fovLeft, screenLeft);
+ result[1] = Math.min(fovTop, screenTop);
+ result[2] = Math.min(fovRight, screenRight);
+ result[3] = Math.max(fovBottom, screenBottom);
+ return result;
+};
+DeviceInfo.prototype.getLeftEyeNoLensTanAngles = function () {
+ var viewer = this.viewer;
+ var device = this.device;
+ var distortion = this.distortion;
+ var result = new Float32Array(4);
+ var fovLeft = distortion.distortInverse(Math.tan(-degToRad * viewer.fov));
+ var fovTop = distortion.distortInverse(Math.tan(degToRad * viewer.fov));
+ var fovRight = distortion.distortInverse(Math.tan(degToRad * viewer.fov));
+ var fovBottom = distortion.distortInverse(Math.tan(-degToRad * viewer.fov));
+ var halfWidth = device.widthMeters / 4;
+ var halfHeight = device.heightMeters / 2;
+ var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight;
+ var centerX = viewer.interLensDistance / 2 - halfWidth;
+ var centerY = -verticalLensOffset;
+ var centerZ = viewer.screenLensDistance;
+ var screenLeft = (centerX - halfWidth) / centerZ;
+ var screenTop = (centerY + halfHeight) / centerZ;
+ var screenRight = (centerX + halfWidth) / centerZ;
+ var screenBottom = (centerY - halfHeight) / centerZ;
+ result[0] = Math.max(fovLeft, screenLeft);
+ result[1] = Math.min(fovTop, screenTop);
+ result[2] = Math.min(fovRight, screenRight);
+ result[3] = Math.max(fovBottom, screenBottom);
+ return result;
+};
+DeviceInfo.prototype.getLeftEyeVisibleScreenRect = function (undistortedFrustum) {
+ var viewer = this.viewer;
+ var device = this.device;
+ var dist = viewer.screenLensDistance;
+ var eyeX = (device.widthMeters - viewer.interLensDistance) / 2;
+ var eyeY = viewer.baselineLensDistance - device.bevelMeters;
+ var left = (undistortedFrustum[0] * dist + eyeX) / device.widthMeters;
+ var top = (undistortedFrustum[1] * dist + eyeY) / device.heightMeters;
+ var right = (undistortedFrustum[2] * dist + eyeX) / device.widthMeters;
+ var bottom = (undistortedFrustum[3] * dist + eyeY) / device.heightMeters;
+ return {
+ x: left,
+ y: bottom,
+ width: right - left,
+ height: top - bottom
+ };
+};
+DeviceInfo.prototype.getFieldOfViewLeftEye = function (opt_isUndistorted) {
+ return opt_isUndistorted ? this.getUndistortedFieldOfViewLeftEye() : this.getDistortedFieldOfViewLeftEye();
+};
+DeviceInfo.prototype.getFieldOfViewRightEye = function (opt_isUndistorted) {
+ var fov = this.getFieldOfViewLeftEye(opt_isUndistorted);
+ return {
+ leftDegrees: fov.rightDegrees,
+ rightDegrees: fov.leftDegrees,
+ upDegrees: fov.upDegrees,
+ downDegrees: fov.downDegrees
+ };
+};
+DeviceInfo.prototype.getUndistortedFieldOfViewLeftEye = function () {
+ var p = this.getUndistortedParams_();
+ return {
+ leftDegrees: radToDeg * Math.atan(p.outerDist),
+ rightDegrees: radToDeg * Math.atan(p.innerDist),
+ downDegrees: radToDeg * Math.atan(p.bottomDist),
+ upDegrees: radToDeg * Math.atan(p.topDist)
+ };
+};
+DeviceInfo.prototype.getUndistortedViewportLeftEye = function () {
+ var p = this.getUndistortedParams_();
+ var viewer = this.viewer;
+ var device = this.device;
+ var eyeToScreenDistance = viewer.screenLensDistance;
+ var screenWidth = device.widthMeters / eyeToScreenDistance;
+ var screenHeight = device.heightMeters / eyeToScreenDistance;
+ var xPxPerTanAngle = device.width / screenWidth;
+ var yPxPerTanAngle = device.height / screenHeight;
+ var x = Math.round((p.eyePosX - p.outerDist) * xPxPerTanAngle);
+ var y = Math.round((p.eyePosY - p.bottomDist) * yPxPerTanAngle);
+ return {
+ x: x,
+ y: y,
+ width: Math.round((p.eyePosX + p.innerDist) * xPxPerTanAngle) - x,
+ height: Math.round((p.eyePosY + p.topDist) * yPxPerTanAngle) - y
+ };
+};
+DeviceInfo.prototype.getUndistortedParams_ = function () {
+ var viewer = this.viewer;
+ var device = this.device;
+ var distortion = this.distortion;
+ var eyeToScreenDistance = viewer.screenLensDistance;
+ var halfLensDistance = viewer.interLensDistance / 2 / eyeToScreenDistance;
+ var screenWidth = device.widthMeters / eyeToScreenDistance;
+ var screenHeight = device.heightMeters / eyeToScreenDistance;
+ var eyePosX = screenWidth / 2 - halfLensDistance;
+ var eyePosY = (viewer.baselineLensDistance - device.bevelMeters) / eyeToScreenDistance;
+ var maxFov = viewer.fov;
+ var viewerMax = distortion.distortInverse(Math.tan(degToRad * maxFov));
+ var outerDist = Math.min(eyePosX, viewerMax);
+ var innerDist = Math.min(halfLensDistance, viewerMax);
+ var bottomDist = Math.min(eyePosY, viewerMax);
+ var topDist = Math.min(screenHeight - eyePosY, viewerMax);
+ return {
+ outerDist: outerDist,
+ innerDist: innerDist,
+ topDist: topDist,
+ bottomDist: bottomDist,
+ eyePosX: eyePosX,
+ eyePosY: eyePosY
+ };
+};
+function CardboardViewer(params) {
+ this.id = params.id;
+ this.label = params.label;
+ this.fov = params.fov;
+ this.interLensDistance = params.interLensDistance;
+ this.baselineLensDistance = params.baselineLensDistance;
+ this.screenLensDistance = params.screenLensDistance;
+ this.distortionCoefficients = params.distortionCoefficients;
+ this.inverseCoefficients = params.inverseCoefficients;
+}
+DeviceInfo.Viewers = Viewers;
+var format = 1;
+var last_updated = "2018-02-20T22:55:10Z";
+var devices = [{"type":"android","rules":[{"mdmh":"asus/*/Nexus 7/*"},{"ua":"Nexus 7"}],"dpi":[320.8,323],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"asus/*/ASUS_Z00AD/*"},{"ua":"ASUS_Z00AD"}],"dpi":[403,404.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel XL/*"},{"ua":"Pixel XL"}],"dpi":[537.9,533],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Google/*/Pixel/*"},{"ua":"Pixel"}],"dpi":[432.6,436.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC6435LVW/*"},{"ua":"HTC6435LVW"}],"dpi":[449.7,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One XL/*"},{"ua":"HTC One XL"}],"dpi":[315.3,314.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"htc/*/Nexus 9/*"},{"ua":"Nexus 9"}],"dpi":289,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One M9/*"},{"ua":"HTC One M9"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One_M8/*"},{"ua":"HTC One_M8"}],"dpi":[449.7,447.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"HTC/*/HTC One/*"},{"ua":"HTC One"}],"dpi":472.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Huawei/*/Nexus 6P/*"},{"ua":"Nexus 6P"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LENOVO/*/Lenovo PB2-690Y/*"},{"ua":"Lenovo PB2-690Y"}],"dpi":[457.2,454.713],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5X/*"},{"ua":"Nexus 5X"}],"dpi":[422,419.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS345/*"},{"ua":"LGMS345"}],"dpi":[221.7,219.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D800/*"},{"ua":"LG-D800"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/LG-D850/*"},{"ua":"LG-D850"}],"dpi":[537.9,541.9],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"LGE/*/VS985 4G/*"},{"ua":"VS985 4G"}],"dpi":[537.9,535.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 5/*"},{"ua":"Nexus 5 B"}],"dpi":[442.4,444.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/Nexus 4/*"},{"ua":"Nexus 4"}],"dpi":[319.8,318.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LG-P769/*"},{"ua":"LG-P769"}],"dpi":[240.6,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGMS323/*"},{"ua":"LGMS323"}],"dpi":[206.6,204.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"LGE/*/LGLS996/*"},{"ua":"LGLS996"}],"dpi":[403.4,401.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/4560MMX/*"},{"ua":"4560MMX"}],"dpi":[240,219.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/A250/*"},{"ua":"Micromax A250"}],"dpi":[480,446.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Micromax/*/Micromax AQ4501/*"},{"ua":"Micromax AQ4501"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/G5/*"},{"ua":"Moto G (5) Plus"}],"dpi":[403.4,403],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/DROID RAZR/*"},{"ua":"DROID RAZR"}],"dpi":[368.1,256.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT830C/*"},{"ua":"XT830C"}],"dpi":[254,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1021/*"},{"ua":"XT1021"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1023/*"},{"ua":"XT1023"}],"dpi":[254,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1028/*"},{"ua":"XT1028"}],"dpi":[326.6,327.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1034/*"},{"ua":"XT1034"}],"dpi":[326.6,328.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1053/*"},{"ua":"XT1053"}],"dpi":[315.3,316.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1562/*"},{"ua":"XT1562"}],"dpi":[403.4,402.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/Nexus 6/*"},{"ua":"Nexus 6 B"}],"dpi":[494.3,489.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1063/*"},{"ua":"XT1063"}],"dpi":[295,296.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/XT1064/*"},{"ua":"XT1064"}],"dpi":[295,295.6],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1092/*"},{"ua":"XT1092"}],"dpi":[422,424.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"motorola/*/XT1095/*"},{"ua":"XT1095"}],"dpi":[422,423.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"motorola/*/G4/*"},{"ua":"Moto G (4)"}],"dpi":401,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/A0001/*"},{"ua":"A0001"}],"dpi":[403.4,401],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE E1005/*"},{"ua":"ONE E1005"}],"dpi":[442.4,441.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A2005/*"},{"ua":"ONE A2005"}],"dpi":[391.9,405.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONEPLUS A5000/*"},{"ua":"ONEPLUS A5000 "}],"dpi":[403.411,399.737],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"OnePlus/*/ONE A5010/*"},{"ua":"ONEPLUS A5010"}],"dpi":[403,400],"bw":2,"ac":1000},{"type":"android","rules":[{"mdmh":"OPPO/*/X909/*"},{"ua":"X909"}],"dpi":[442.4,444.1],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9082/*"},{"ua":"GT-I9082"}],"dpi":[184.7,185.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G360P/*"},{"ua":"SM-G360P"}],"dpi":[196.7,205.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Nexus S/*"},{"ua":"Nexus S"}],"dpi":[234.5,229.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[304.8,303.9],"bw":5,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T230NU/*"},{"ua":"SM-T230NU"}],"dpi":216,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-T399/*"},{"ua":"SGH-T399"}],"dpi":[217.7,231.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SGH-M919/*"},{"ua":"SGH-M919"}],"dpi":[440.8,437.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N9005/*"},{"ua":"SM-N9005"}],"dpi":[386.4,387],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SM-N900A/*"},{"ua":"SAMSUNG-SM-N900A"}],"dpi":[386.4,387.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9500/*"},{"ua":"GT-I9500"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9505/*"},{"ua":"GT-I9505"}],"dpi":439.4,"bw":4,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900F/*"},{"ua":"SM-G900F"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G900M/*"},{"ua":"SM-G900M"}],"dpi":[415.6,431.6],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G800F/*"},{"ua":"SM-G800F"}],"dpi":326.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G906S/*"},{"ua":"SM-G906S"}],"dpi":[562.7,572.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300/*"},{"ua":"GT-I9300"}],"dpi":[306.7,304.8],"bw":5,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-T535/*"},{"ua":"SM-T535"}],"dpi":[142.6,136.4],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920C/*"},{"ua":"SM-N920C"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920P/*"},{"ua":"SM-N920P"}],"dpi":[386.3655,390.144],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N920W8/*"},{"ua":"SM-N920W8"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9300I/*"},{"ua":"GT-I9300I"}],"dpi":[304.8,305.8],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-I9195/*"},{"ua":"GT-I9195"}],"dpi":[249.4,256.7],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-L520/*"},{"ua":"SPH-L520"}],"dpi":[249.4,255.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SAMSUNG-SGH-I717/*"},{"ua":"SAMSUNG-SGH-I717"}],"dpi":285.8,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SPH-D710/*"},{"ua":"SPH-D710"}],"dpi":[217.7,204.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/GT-N7100/*"},{"ua":"GT-N7100"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SCH-I605/*"},{"ua":"SCH-I605"}],"dpi":265.1,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/Galaxy Nexus/*"},{"ua":"Galaxy Nexus"}],"dpi":[315.3,314.2],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910H/*"},{"ua":"SM-N910H"}],"dpi":[515.1,518],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-N910C/*"},{"ua":"SM-N910C"}],"dpi":[515.2,520.2],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G130M/*"},{"ua":"SM-G130M"}],"dpi":[165.9,164.8],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G928I/*"},{"ua":"SM-G928I"}],"dpi":[515.1,518.4],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920F/*"},{"ua":"SM-G920F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G920P/*"},{"ua":"SM-G920P"}],"dpi":[522.5,577],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925F/*"},{"ua":"SM-G925F"}],"dpi":580.6,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G925V/*"},{"ua":"SM-G925V"}],"dpi":[522.5,576.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G930F/*"},{"ua":"SM-G930F"}],"dpi":576.6,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G935F/*"},{"ua":"SM-G935F"}],"dpi":533,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G950F/*"},{"ua":"SM-G950F"}],"dpi":[562.707,565.293],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"samsung/*/SM-G955U/*"},{"ua":"SM-G955U"}],"dpi":[522.514,525.762],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/C6903/*"},{"ua":"C6903"}],"dpi":[442.5,443.3],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"Sony/*/D6653/*"},{"ua":"D6653"}],"dpi":[428.6,427.6],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6653/*"},{"ua":"E6653"}],"dpi":[428.6,425.7],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/E6853/*"},{"ua":"E6853"}],"dpi":[403.4,401.9],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Sony/*/SGP321/*"},{"ua":"SGP321"}],"dpi":[224.7,224.1],"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"TCT/*/ALCATEL ONE TOUCH Fierce/*"},{"ua":"ALCATEL ONE TOUCH Fierce"}],"dpi":[240,247.5],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"THL/*/thl 5000/*"},{"ua":"thl 5000"}],"dpi":[480,443.3],"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"Fly/*/IQ4412/*"},{"ua":"IQ4412"}],"dpi":307.9,"bw":3,"ac":1000},{"type":"android","rules":[{"mdmh":"ZTE/*/ZTE Blade L2/*"},{"ua":"ZTE Blade L2"}],"dpi":240,"bw":3,"ac":500},{"type":"android","rules":[{"mdmh":"BENEVE/*/VR518/*"},{"ua":"VR518"}],"dpi":480,"bw":3,"ac":500},{"type":"ios","rules":[{"res":[640,960]}],"dpi":[325.1,328.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[640,1136]}],"dpi":[317.1,320.2],"bw":3,"ac":1000},{"type":"ios","rules":[{"res":[750,1334]}],"dpi":326.4,"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1242,2208]}],"dpi":[453.6,458.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2001]}],"dpi":[410.9,415.4],"bw":4,"ac":1000},{"type":"ios","rules":[{"res":[1125,2436]}],"dpi":458,"bw":4,"ac":1000}];
+var DPDB_CACHE = {
+ format: format,
+ last_updated: last_updated,
+ devices: devices
+};
+function Dpdb(url, onDeviceParamsUpdated) {
+ this.dpdb = DPDB_CACHE;
+ this.recalculateDeviceParams_();
+ if (url) {
+ this.onDeviceParamsUpdated = onDeviceParamsUpdated;
+ var xhr = new XMLHttpRequest();
+ var obj = this;
+ xhr.open('GET', url, true);
+ xhr.addEventListener('load', function () {
+ obj.loading = false;
+ if (xhr.status >= 200 && xhr.status <= 299) {
+ obj.dpdb = JSON.parse(xhr.response);
+ obj.recalculateDeviceParams_();
+ } else {
+ console.error('Error loading online DPDB!');
+ }
+ });
+ xhr.send();
+ }
+}
+Dpdb.prototype.getDeviceParams = function () {
+ return this.deviceParams;
+};
+Dpdb.prototype.recalculateDeviceParams_ = function () {
+ var newDeviceParams = this.calcDeviceParams_();
+ if (newDeviceParams) {
+ this.deviceParams = newDeviceParams;
+ if (this.onDeviceParamsUpdated) {
+ this.onDeviceParamsUpdated(this.deviceParams);
+ }
+ } else {
+ console.error('Failed to recalculate device parameters.');
+ }
+};
+Dpdb.prototype.calcDeviceParams_ = function () {
+ var db = this.dpdb;
+ if (!db) {
+ console.error('DPDB not available.');
+ return null;
+ }
+ if (db.format != 1) {
+ console.error('DPDB has unexpected format version.');
+ return null;
+ }
+ if (!db.devices || !db.devices.length) {
+ console.error('DPDB does not have a devices section.');
+ return null;
+ }
+ var userAgent = navigator.userAgent || navigator.vendor || window.opera;
+ var width = getScreenWidth();
+ var height = getScreenHeight();
+ if (!db.devices) {
+ console.error('DPDB has no devices section.');
+ return null;
+ }
+ for (var i = 0; i < db.devices.length; i++) {
+ var device = db.devices[i];
+ if (!device.rules) {
+ console.warn('Device[' + i + '] has no rules section.');
+ continue;
+ }
+ if (device.type != 'ios' && device.type != 'android') {
+ console.warn('Device[' + i + '] has invalid type.');
+ continue;
+ }
+ if (isIOS() != (device.type == 'ios')) continue;
+ var matched = false;
+ for (var j = 0; j < device.rules.length; j++) {
+ var rule = device.rules[j];
+ if (this.matchRule_(rule, userAgent, width, height)) {
+ matched = true;
+ break;
+ }
+ }
+ if (!matched) continue;
+ var xdpi = device.dpi[0] || device.dpi;
+ var ydpi = device.dpi[1] || device.dpi;
+ return new DeviceParams({ xdpi: xdpi, ydpi: ydpi, bevelMm: device.bw });
+ }
+ console.warn('No DPDB device match.');
+ return null;
+};
+Dpdb.prototype.matchRule_ = function (rule, ua, screenWidth, screenHeight) {
+ if (!rule.ua && !rule.res) return false;
+ if (rule.ua && ua.indexOf(rule.ua) < 0) return false;
+ if (rule.res) {
+ if (!rule.res[0] || !rule.res[1]) return false;
+ var resX = rule.res[0];
+ var resY = rule.res[1];
+ if (Math.min(screenWidth, screenHeight) != Math.min(resX, resY) || Math.max(screenWidth, screenHeight) != Math.max(resX, resY)) {
+ return false;
+ }
+ }
+ return true;
+};
+function DeviceParams(params) {
+ this.xdpi = params.xdpi;
+ this.ydpi = params.ydpi;
+ this.bevelMm = params.bevelMm;
+}
+function SensorSample(sample, timestampS) {
+ this.set(sample, timestampS);
+}
+SensorSample.prototype.set = function (sample, timestampS) {
+ this.sample = sample;
+ this.timestampS = timestampS;
+};
+SensorSample.prototype.copy = function (sensorSample) {
+ this.set(sensorSample.sample, sensorSample.timestampS);
+};
+function ComplementaryFilter(kFilter, isDebug) {
+ this.kFilter = kFilter;
+ this.isDebug = isDebug;
+ this.currentAccelMeasurement = new SensorSample();
+ this.currentGyroMeasurement = new SensorSample();
+ this.previousGyroMeasurement = new SensorSample();
+ if (isIOS()) {
+ this.filterQ = new Quaternion(-1, 0, 0, 1);
+ } else {
+ this.filterQ = new Quaternion(1, 0, 0, 1);
+ }
+ this.previousFilterQ = new Quaternion();
+ this.previousFilterQ.copy(this.filterQ);
+ this.accelQ = new Quaternion();
+ this.isOrientationInitialized = false;
+ this.estimatedGravity = new Vector3();
+ this.measuredGravity = new Vector3();
+ this.gyroIntegralQ = new Quaternion();
+}
+ComplementaryFilter.prototype.addAccelMeasurement = function (vector, timestampS) {
+ this.currentAccelMeasurement.set(vector, timestampS);
+};
+ComplementaryFilter.prototype.addGyroMeasurement = function (vector, timestampS) {
+ this.currentGyroMeasurement.set(vector, timestampS);
+ var deltaT = timestampS - this.previousGyroMeasurement.timestampS;
+ if (isTimestampDeltaValid(deltaT)) {
+ this.run_();
+ }
+ this.previousGyroMeasurement.copy(this.currentGyroMeasurement);
+};
+ComplementaryFilter.prototype.run_ = function () {
+ if (!this.isOrientationInitialized) {
+ this.accelQ = this.accelToQuaternion_(this.currentAccelMeasurement.sample);
+ this.previousFilterQ.copy(this.accelQ);
+ this.isOrientationInitialized = true;
+ return;
+ }
+ var deltaT = this.currentGyroMeasurement.timestampS - this.previousGyroMeasurement.timestampS;
+ var gyroDeltaQ = this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample, deltaT);
+ this.gyroIntegralQ.multiply(gyroDeltaQ);
+ this.filterQ.copy(this.previousFilterQ);
+ this.filterQ.multiply(gyroDeltaQ);
+ var invFilterQ = new Quaternion();
+ invFilterQ.copy(this.filterQ);
+ invFilterQ.inverse();
+ this.estimatedGravity.set(0, 0, -1);
+ this.estimatedGravity.applyQuaternion(invFilterQ);
+ this.estimatedGravity.normalize();
+ this.measuredGravity.copy(this.currentAccelMeasurement.sample);
+ this.measuredGravity.normalize();
+ var deltaQ = new Quaternion();
+ deltaQ.setFromUnitVectors(this.estimatedGravity, this.measuredGravity);
+ deltaQ.inverse();
+ if (this.isDebug) {
+ console.log('Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)', radToDeg * getQuaternionAngle(deltaQ), this.estimatedGravity.x.toFixed(1), this.estimatedGravity.y.toFixed(1), this.estimatedGravity.z.toFixed(1), this.measuredGravity.x.toFixed(1), this.measuredGravity.y.toFixed(1), this.measuredGravity.z.toFixed(1));
+ }
+ var targetQ = new Quaternion();
+ targetQ.copy(this.filterQ);
+ targetQ.multiply(deltaQ);
+ this.filterQ.slerp(targetQ, 1 - this.kFilter);
+ this.previousFilterQ.copy(this.filterQ);
+};
+ComplementaryFilter.prototype.getOrientation = function () {
+ return this.filterQ;
+};
+ComplementaryFilter.prototype.accelToQuaternion_ = function (accel) {
+ var normAccel = new Vector3();
+ normAccel.copy(accel);
+ normAccel.normalize();
+ var quat = new Quaternion();
+ quat.setFromUnitVectors(new Vector3(0, 0, -1), normAccel);
+ quat.inverse();
+ return quat;
+};
+ComplementaryFilter.prototype.gyroToQuaternionDelta_ = function (gyro, dt) {
+ var quat = new Quaternion();
+ var axis = new Vector3();
+ axis.copy(gyro);
+ axis.normalize();
+ quat.setFromAxisAngle(axis, gyro.length() * dt);
+ return quat;
+};
+function PosePredictor(predictionTimeS, isDebug) {
+ this.predictionTimeS = predictionTimeS;
+ this.isDebug = isDebug;
+ this.previousQ = new Quaternion();
+ this.previousTimestampS = null;
+ this.deltaQ = new Quaternion();
+ this.outQ = new Quaternion();
+}
+PosePredictor.prototype.getPrediction = function (currentQ, gyro, timestampS) {
+ if (!this.previousTimestampS) {
+ this.previousQ.copy(currentQ);
+ this.previousTimestampS = timestampS;
+ return currentQ;
+ }
+ var axis = new Vector3();
+ axis.copy(gyro);
+ axis.normalize();
+ var angularSpeed = gyro.length();
+ if (angularSpeed < degToRad * 20) {
+ if (this.isDebug) {
+ console.log('Moving slowly, at %s deg/s: no prediction', (radToDeg * angularSpeed).toFixed(1));
+ }
+ this.outQ.copy(currentQ);
+ this.previousQ.copy(currentQ);
+ return this.outQ;
+ }
+ var predictAngle = angularSpeed * this.predictionTimeS;
+ this.deltaQ.setFromAxisAngle(axis, predictAngle);
+ this.outQ.copy(this.previousQ);
+ this.outQ.multiply(this.deltaQ);
+ this.previousQ.copy(currentQ);
+ this.previousTimestampS = timestampS;
+ return this.outQ;
+};
+function FusionPoseSensor(kFilter, predictionTime, yawOnly, isDebug) {
+ this.yawOnly = yawOnly;
+ this.accelerometer = new Vector3();
+ this.gyroscope = new Vector3();
+ this.filter = new ComplementaryFilter(kFilter, isDebug);
+ this.posePredictor = new PosePredictor(predictionTime, isDebug);
+ this.isFirefoxAndroid = isFirefoxAndroid();
+ this.isIOS = isIOS();
+ var chromeVersion = getChromeVersion();
+ this.isDeviceMotionInRadians = !this.isIOS && chromeVersion && chromeVersion < 66;
+ this.isWithoutDeviceMotion = isChromeWithoutDeviceMotion();
+ this.filterToWorldQ = new Quaternion();
+ if (isIOS()) {
+ this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2);
+ } else {
+ this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2);
+ }
+ this.inverseWorldToScreenQ = new Quaternion();
+ this.worldToScreenQ = new Quaternion();
+ this.originalPoseAdjustQ = new Quaternion();
+ this.originalPoseAdjustQ.setFromAxisAngle(new Vector3(0, 0, 1), -window.orientation * Math.PI / 180);
+ this.setScreenTransform_();
+ if (isLandscapeMode()) {
+ this.filterToWorldQ.multiply(this.inverseWorldToScreenQ);
+ }
+ this.resetQ = new Quaternion();
+ this.orientationOut_ = new Float32Array(4);
+ this.start();
+}
+FusionPoseSensor.prototype.getPosition = function () {
+ return null;
+};
+FusionPoseSensor.prototype.getOrientation = function () {
+ var orientation = void 0;
+ if (this.isWithoutDeviceMotion && this._deviceOrientationQ) {
+ this.deviceOrientationFixQ = this.deviceOrientationFixQ || function () {
+ var z = new Quaternion().setFromAxisAngle(new Vector3(0, 0, -1), 0);
+ var y = new Quaternion();
+ if (window.orientation === -90) {
+ y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / -2);
+ } else {
+ y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 2);
+ }
+ return z.multiply(y);
+ }();
+ this.deviceOrientationFilterToWorldQ = this.deviceOrientationFilterToWorldQ || function () {
+ var q = new Quaternion();
+ q.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2);
+ return q;
+ }();
+ orientation = this._deviceOrientationQ;
+ var out = new Quaternion();
+ out.copy(orientation);
+ out.multiply(this.deviceOrientationFilterToWorldQ);
+ out.multiply(this.resetQ);
+ out.multiply(this.worldToScreenQ);
+ out.multiplyQuaternions(this.deviceOrientationFixQ, out);
+ if (this.yawOnly) {
+ out.x = 0;
+ out.z = 0;
+ out.normalize();
+ }
+ this.orientationOut_[0] = out.x;
+ this.orientationOut_[1] = out.y;
+ this.orientationOut_[2] = out.z;
+ this.orientationOut_[3] = out.w;
+ return this.orientationOut_;
+ } else {
+ var filterOrientation = this.filter.getOrientation();
+ orientation = this.posePredictor.getPrediction(filterOrientation, this.gyroscope, this.previousTimestampS);
+ }
+ var out = new Quaternion();
+ out.copy(this.filterToWorldQ);
+ out.multiply(this.resetQ);
+ out.multiply(orientation);
+ out.multiply(this.worldToScreenQ);
+ if (this.yawOnly) {
+ out.x = 0;
+ out.z = 0;
+ out.normalize();
+ }
+ this.orientationOut_[0] = out.x;
+ this.orientationOut_[1] = out.y;
+ this.orientationOut_[2] = out.z;
+ this.orientationOut_[3] = out.w;
+ return this.orientationOut_;
+};
+FusionPoseSensor.prototype.resetPose = function () {
+ this.resetQ.copy(this.filter.getOrientation());
+ this.resetQ.x = 0;
+ this.resetQ.y = 0;
+ this.resetQ.z *= -1;
+ this.resetQ.normalize();
+ if (isLandscapeMode()) {
+ this.resetQ.multiply(this.inverseWorldToScreenQ);
+ }
+ this.resetQ.multiply(this.originalPoseAdjustQ);
+};
+FusionPoseSensor.prototype.onDeviceOrientation_ = function (e) {
+ this._deviceOrientationQ = this._deviceOrientationQ || new Quaternion();
+ var alpha = e.alpha,
+ beta = e.beta,
+ gamma = e.gamma;
+ alpha = (alpha || 0) * Math.PI / 180;
+ beta = (beta || 0) * Math.PI / 180;
+ gamma = (gamma || 0) * Math.PI / 180;
+ this._deviceOrientationQ.setFromEulerYXZ(beta, alpha, -gamma);
+};
+FusionPoseSensor.prototype.onDeviceMotion_ = function (deviceMotion) {
+ this.updateDeviceMotion_(deviceMotion);
+};
+FusionPoseSensor.prototype.updateDeviceMotion_ = function (deviceMotion) {
+ var accGravity = deviceMotion.accelerationIncludingGravity;
+ var rotRate = deviceMotion.rotationRate;
+ var timestampS = deviceMotion.timeStamp / 1000;
+ var deltaS = timestampS - this.previousTimestampS;
+ if (deltaS < 0) {
+ warnOnce('fusion-pose-sensor:invalid:non-monotonic', 'Invalid timestamps detected: non-monotonic timestamp from devicemotion');
+ this.previousTimestampS = timestampS;
+ return;
+ } else if (deltaS <= MIN_TIMESTEP || deltaS > MAX_TIMESTEP) {
+ warnOnce('fusion-pose-sensor:invalid:outside-threshold', 'Invalid timestamps detected: Timestamp from devicemotion outside expected range.');
+ this.previousTimestampS = timestampS;
+ return;
+ }
+ this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z);
+ if (isR7()) {
+ this.gyroscope.set(-rotRate.beta, rotRate.alpha, rotRate.gamma);
+ } else {
+ this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma);
+ }
+ if (!this.isDeviceMotionInRadians) {
+ this.gyroscope.multiplyScalar(Math.PI / 180);
+ }
+ this.filter.addAccelMeasurement(this.accelerometer, timestampS);
+ this.filter.addGyroMeasurement(this.gyroscope, timestampS);
+ this.previousTimestampS = timestampS;
+};
+FusionPoseSensor.prototype.onOrientationChange_ = function (screenOrientation) {
+ this.setScreenTransform_();
+};
+FusionPoseSensor.prototype.onMessage_ = function (event) {
+ var message = event.data;
+ if (!message || !message.type) {
+ return;
+ }
+ var type = message.type.toLowerCase();
+ if (type !== 'devicemotion') {
+ return;
+ }
+ this.updateDeviceMotion_(message.deviceMotionEvent);
+};
+FusionPoseSensor.prototype.setScreenTransform_ = function () {
+ this.worldToScreenQ.set(0, 0, 0, 1);
+ switch (window.orientation) {
+ case 0:
+ break;
+ case 90:
+ this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), -Math.PI / 2);
+ break;
+ case -90:
+ this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), Math.PI / 2);
+ break;
+ case 180:
+ break;
+ }
+ this.inverseWorldToScreenQ.copy(this.worldToScreenQ);
+ this.inverseWorldToScreenQ.inverse();
+};
+FusionPoseSensor.prototype.start = function () {
+ this.onDeviceMotionCallback_ = this.onDeviceMotion_.bind(this);
+ this.onOrientationChangeCallback_ = this.onOrientationChange_.bind(this);
+ this.onMessageCallback_ = this.onMessage_.bind(this);
+ this.onDeviceOrientationCallback_ = this.onDeviceOrientation_.bind(this);
+ if (isIOS() && isInsideCrossOriginIFrame()) {
+ window.addEventListener('message', this.onMessageCallback_);
+ }
+ window.addEventListener('orientationchange', this.onOrientationChangeCallback_);
+ if (this.isWithoutDeviceMotion) {
+ window.addEventListener('deviceorientation', this.onDeviceOrientationCallback_);
+ } else {
+ window.addEventListener('devicemotion', this.onDeviceMotionCallback_);
+ }
+};
+FusionPoseSensor.prototype.stop = function () {
+ window.removeEventListener('devicemotion', this.onDeviceMotionCallback_);
+ window.removeEventListener('deviceorientation', this.onDeviceOrientationCallback_);
+ window.removeEventListener('orientationchange', this.onOrientationChangeCallback_);
+ window.removeEventListener('message', this.onMessageCallback_);
+};
+var SENSOR_FREQUENCY = 60;
+var X_AXIS = new Vector3(1, 0, 0);
+var Z_AXIS = new Vector3(0, 0, 1);
+var orientation = {};
+if (screen.orientation) {
+ orientation = screen.orientation;
+} else if (screen.msOrientation) {
+ orientation = screen.msOrientation;
+} else {
+ Object.defineProperty(orientation, 'angle', {
+ get: function get$$1() {
+ return window.orientation || 0;
+ }
+ });
+}
+var SENSOR_TO_VR = new Quaternion();
+SENSOR_TO_VR.setFromAxisAngle(X_AXIS, -Math.PI / 2);
+SENSOR_TO_VR.multiply(new Quaternion().setFromAxisAngle(Z_AXIS, Math.PI / 2));
+var PoseSensor = function () {
+ function PoseSensor(config) {
+ classCallCheck(this, PoseSensor);
+ this.config = config;
+ this.sensor = null;
+ this.fusionSensor = null;
+ this._out = new Float32Array(4);
+ this.api = null;
+ this.errors = [];
+ this._sensorQ = new Quaternion();
+ this._worldToScreenQ = new Quaternion();
+ this._outQ = new Quaternion();
+ this._onSensorRead = this._onSensorRead.bind(this);
+ this._onSensorError = this._onSensorError.bind(this);
+ this._onOrientationChange = this._onOrientationChange.bind(this);
+ this._onOrientationChange();
+ this.init();
+ }
+ createClass(PoseSensor, [{
+ key: 'init',
+ value: function init() {
+ var sensor = null;
+ try {
+ sensor = new RelativeOrientationSensor({ frequency: SENSOR_FREQUENCY });
+ sensor.addEventListener('error', this._onSensorError);
+ } catch (error) {
+ this.errors.push(error);
+ if (error.name === 'SecurityError') {
+ console.error('Cannot construct sensors due to the Feature Policy');
+ console.warn('Attempting to fall back using "devicemotion"; however this will ' + 'fail in the future without correct permissions.');
+ this.useDeviceMotion();
+ } else if (error.name === 'ReferenceError') {
+ this.useDeviceMotion();
+ } else {
+ console.error(error);
+ }
+ }
+ if (sensor) {
+ this.api = 'sensor';
+ this.sensor = sensor;
+ this.sensor.addEventListener('reading', this._onSensorRead);
+ this.sensor.start();
+ }
+ window.addEventListener('orientationchange', this._onOrientationChange);
+ }
+ }, {
+ key: 'useDeviceMotion',
+ value: function useDeviceMotion() {
+ this.api = 'devicemotion';
+ this.fusionSensor = new FusionPoseSensor(this.config.K_FILTER, this.config.PREDICTION_TIME_S, this.config.YAW_ONLY, this.config.DEBUG);
+ if (this.sensor) {
+ this.sensor.removeEventListener('reading', this._onSensorRead);
+ this.sensor.removeEventListener('error', this._onSensorError);
+ this.sensor = null;
+ }
+ }
+ }, {
+ key: 'getOrientation',
+ value: function getOrientation() {
+ if (this.fusionSensor) {
+ return this.fusionSensor.getOrientation();
+ }
+ if (!this.sensor || !this.sensor.quaternion) {
+ this._out[0] = this._out[1] = this._out[2] = 0;
+ this._out[3] = 1;
+ return this._out;
+ }
+ var q = this.sensor.quaternion;
+ this._sensorQ.set(q[0], q[1], q[2], q[3]);
+ var out = this._outQ;
+ out.copy(SENSOR_TO_VR);
+ out.multiply(this._sensorQ);
+ out.multiply(this._worldToScreenQ);
+ if (this.config.YAW_ONLY) {
+ out.x = out.z = 0;
+ out.normalize();
+ }
+ this._out[0] = out.x;
+ this._out[1] = out.y;
+ this._out[2] = out.z;
+ this._out[3] = out.w;
+ return this._out;
+ }
+ }, {
+ key: '_onSensorError',
+ value: function _onSensorError(event) {
+ this.errors.push(event.error);
+ if (event.error.name === 'NotAllowedError') {
+ console.error('Permission to access sensor was denied');
+ } else if (event.error.name === 'NotReadableError') {
+ console.error('Sensor could not be read');
+ } else {
+ console.error(event.error);
+ }
+ this.useDeviceMotion();
+ }
+ }, {
+ key: '_onSensorRead',
+ value: function _onSensorRead() {}
+ }, {
+ key: '_onOrientationChange',
+ value: function _onOrientationChange() {
+ var angle = -orientation.angle * Math.PI / 180;
+ this._worldToScreenQ.setFromAxisAngle(Z_AXIS, angle);
+ }
+ }]);
+ return PoseSensor;
+}();
+var rotateInstructionsAsset = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjE5OHB4IiBoZWlnaHQ9IjI0MHB4IiB2aWV3Qm94PSIwIDAgMTk4IDI0MCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpza2V0Y2g9Imh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaC9ucyI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDMuMy4zICgxMjA4MSkgLSBodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2ggLS0+CiAgICA8dGl0bGU+dHJhbnNpdGlvbjwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxkZWZzPjwvZGVmcz4KICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHNrZXRjaDp0eXBlPSJNU1BhZ2UiPgogICAgICAgIDxnIGlkPSJ0cmFuc2l0aW9uIiBza2V0Y2g6dHlwZT0iTVNBcnRib2FyZEdyb3VwIj4KICAgICAgICAgICAgPGcgaWQ9IkltcG9ydGVkLUxheWVycy1Db3B5LTQtKy1JbXBvcnRlZC1MYXllcnMtQ29weS0rLUltcG9ydGVkLUxheWVycy1Db3B5LTItQ29weSIgc2tldGNoOnR5cGU9Ik1TTGF5ZXJHcm91cCI+CiAgICAgICAgICAgICAgICA8ZyBpZD0iSW1wb3J0ZWQtTGF5ZXJzLUNvcHktNCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsIDEwNy4wMDAwMDApIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ5LjYyNSwyLjUyNyBDMTQ5LjYyNSwyLjUyNyAxNTUuODA1LDYuMDk2IDE1Ni4zNjIsNi40MTggTDE1Ni4zNjIsNy4zMDQgQzE1Ni4zNjIsNy40ODEgMTU2LjM3NSw3LjY2NCAxNTYuNCw3Ljg1MyBDMTU2LjQxLDcuOTM0IDE1Ni40Miw4LjAxNSAxNTYuNDI3LDguMDk1IEMxNTYuNTY3LDkuNTEgMTU3LjQwMSwxMS4wOTMgMTU4LjUzMiwxMi4wOTQgTDE2NC4yNTIsMTcuMTU2IEwxNjQuMzMzLDE3LjA2NiBDMTY0LjMzMywxNy4wNjYgMTY4LjcxNSwxNC41MzYgMTY5LjU2OCwxNC4wNDIgQzE3MS4wMjUsMTQuODgzIDE5NS41MzgsMjkuMDM1IDE5NS41MzgsMjkuMDM1IEwxOTUuNTM4LDgzLjAzNiBDMTk1LjUzOCw4My44MDcgMTk1LjE1Miw4NC4yNTMgMTk0LjU5LDg0LjI1MyBDMTk0LjM1Nyw4NC4yNTMgMTk0LjA5NSw4NC4xNzcgMTkzLjgxOCw4NC4wMTcgTDE2OS44NTEsNzAuMTc5IEwxNjkuODM3LDcwLjIwMyBMMTQyLjUxNSw4NS45NzggTDE0MS42NjUsODQuNjU1IEMxMzYuOTM0LDgzLjEyNiAxMzEuOTE3LDgxLjkxNSAxMjYuNzE0LDgxLjA0NSBDMTI2LjcwOSw4MS4wNiAxMjYuNzA3LDgxLjA2OSAxMjYuNzA3LDgxLjA2OSBMMTIxLjY0LDk4LjAzIEwxMTMuNzQ5LDEwMi41ODYgTDExMy43MTIsMTAyLjUyMyBMMTEzLjcxMiwxMzAuMTEzIEMxMTMuNzEyLDEzMC44ODUgMTEzLjMyNiwxMzEuMzMgMTEyLjc2NCwxMzEuMzMgQzExMi41MzIsMTMxLjMzIDExMi4yNjksMTMxLjI1NCAxMTEuOTkyLDEzMS4wOTQgTDY5LjUxOSwxMDYuNTcyIEM2OC41NjksMTA2LjAyMyA2Ny43OTksMTA0LjY5NSA2Ny43OTksMTAzLjYwNSBMNjcuNzk5LDEwMi41NyBMNjcuNzc4LDEwMi42MTcgQzY3LjI3LDEwMi4zOTMgNjYuNjQ4LDEwMi4yNDkgNjUuOTYyLDEwMi4yMTggQzY1Ljg3NSwxMDIuMjE0IDY1Ljc4OCwxMDIuMjEyIDY1LjcwMSwxMDIuMjEyIEM2NS42MDYsMTAyLjIxMiA2NS41MTEsMTAyLjIxNSA2NS40MTYsMTAyLjIxOSBDNjUuMTk1LDEwMi4yMjkgNjQuOTc0LDEwMi4yMzUgNjQuNzU0LDEwMi4yMzUgQzY0LjMzMSwxMDIuMjM1IDYzLjkxMSwxMDIuMjE2IDYzLjQ5OCwxMDIuMTc4IEM2MS44NDMsMTAyLjAyNSA2MC4yOTgsMTAxLjU3OCA1OS4wOTQsMTAwLjg4MiBMMTIuNTE4LDczLjk5MiBMMTIuNTIzLDc0LjAwNCBMMi4yNDUsNTUuMjU0IEMxLjI0NCw1My40MjcgMi4wMDQsNTEuMDM4IDMuOTQzLDQ5LjkxOCBMNTkuOTU0LDE3LjU3MyBDNjAuNjI2LDE3LjE4NSA2MS4zNSwxNy4wMDEgNjIuMDUzLDE3LjAwMSBDNjMuMzc5LDE3LjAwMSA2NC42MjUsMTcuNjYgNjUuMjgsMTguODU0IEw2NS4yODUsMTguODUxIEw2NS41MTIsMTkuMjY0IEw2NS41MDYsMTkuMjY4IEM2NS45MDksMjAuMDAzIDY2LjQwNSwyMC42OCA2Ni45ODMsMjEuMjg2IEw2Ny4yNiwyMS41NTYgQzY5LjE3NCwyMy40MDYgNzEuNzI4LDI0LjM1NyA3NC4zNzMsMjQuMzU3IEM3Ni4zMjIsMjQuMzU3IDc4LjMyMSwyMy44NCA4MC4xNDgsMjIuNzg1IEM4MC4xNjEsMjIuNzg1IDg3LjQ2NywxOC41NjYgODcuNDY3LDE4LjU2NiBDODguMTM5LDE4LjE3OCA4OC44NjMsMTcuOTk0IDg5LjU2NiwxNy45OTQgQzkwLjg5MiwxNy45OTQgOTIuMTM4LDE4LjY1MiA5Mi43OTIsMTkuODQ3IEw5Ni4wNDIsMjUuNzc1IEw5Ni4wNjQsMjUuNzU3IEwxMDIuODQ5LDI5LjY3NCBMMTAyLjc0NCwyOS40OTIgTDE0OS42MjUsMi41MjcgTTE0OS42MjUsMC44OTIgQzE0OS4zNDMsMC44OTIgMTQ5LjA2MiwwLjk2NSAxNDguODEsMS4xMSBMMTAyLjY0MSwyNy42NjYgTDk3LjIzMSwyNC41NDIgTDk0LjIyNiwxOS4wNjEgQzkzLjMxMywxNy4zOTQgOTEuNTI3LDE2LjM1OSA4OS41NjYsMTYuMzU4IEM4OC41NTUsMTYuMzU4IDg3LjU0NiwxNi42MzIgODYuNjQ5LDE3LjE1IEM4My44NzgsMTguNzUgNzkuNjg3LDIxLjE2OSA3OS4zNzQsMjEuMzQ1IEM3OS4zNTksMjEuMzUzIDc5LjM0NSwyMS4zNjEgNzkuMzMsMjEuMzY5IEM3Ny43OTgsMjIuMjU0IDc2LjA4NCwyMi43MjIgNzQuMzczLDIyLjcyMiBDNzIuMDgxLDIyLjcyMiA2OS45NTksMjEuODkgNjguMzk3LDIwLjM4IEw2OC4xNDUsMjAuMTM1IEM2Ny43MDYsMTkuNjcyIDY3LjMyMywxOS4xNTYgNjcuMDA2LDE4LjYwMSBDNjYuOTg4LDE4LjU1OSA2Ni45NjgsMTguNTE5IDY2Ljk0NiwxOC40NzkgTDY2LjcxOSwxOC4wNjUgQzY2LjY5LDE4LjAxMiA2Ni42NTgsMTcuOTYgNjYuNjI0LDE3LjkxMSBDNjUuNjg2LDE2LjMzNyA2My45NTEsMTUuMzY2IDYyLjA1MywxNS4zNjYgQzYxLjA0MiwxNS4zNjYgNjAuMDMzLDE1LjY0IDU5LjEzNiwxNi4xNTggTDMuMTI1LDQ4LjUwMiBDMC40MjYsNTAuMDYxIC0wLjYxMyw1My40NDIgMC44MTEsNTYuMDQgTDExLjA4OSw3NC43OSBDMTEuMjY2LDc1LjExMyAxMS41MzcsNzUuMzUzIDExLjg1LDc1LjQ5NCBMNTguMjc2LDEwMi4yOTggQzU5LjY3OSwxMDMuMTA4IDYxLjQzMywxMDMuNjMgNjMuMzQ4LDEwMy44MDYgQzYzLjgxMiwxMDMuODQ4IDY0LjI4NSwxMDMuODcgNjQuNzU0LDEwMy44NyBDNjUsMTAzLjg3IDY1LjI0OSwxMDMuODY0IDY1LjQ5NCwxMDMuODUyIEM2NS41NjMsMTAzLjg0OSA2NS42MzIsMTAzLjg0NyA2NS43MDEsMTAzLjg0NyBDNjUuNzY0LDEwMy44NDcgNjUuODI4LDEwMy44NDkgNjUuODksMTAzLjg1MiBDNjUuOTg2LDEwMy44NTYgNjYuMDgsMTAzLjg2MyA2Ni4xNzMsMTAzLjg3NCBDNjYuMjgyLDEwNS40NjcgNjcuMzMyLDEwNy4xOTcgNjguNzAyLDEwNy45ODggTDExMS4xNzQsMTMyLjUxIEMxMTEuNjk4LDEzMi44MTIgMTEyLjIzMiwxMzIuOTY1IDExMi43NjQsMTMyLjk2NSBDMTE0LjI2MSwxMzIuOTY1IDExNS4zNDcsMTMxLjc2NSAxMTUuMzQ3LDEzMC4xMTMgTDExNS4zNDcsMTAzLjU1MSBMMTIyLjQ1OCw5OS40NDYgQzEyMi44MTksOTkuMjM3IDEyMy4wODcsOTguODk4IDEyMy4yMDcsOTguNDk4IEwxMjcuODY1LDgyLjkwNSBDMTMyLjI3OSw4My43MDIgMTM2LjU1Nyw4NC43NTMgMTQwLjYwNyw4Ni4wMzMgTDE0MS4xNCw4Ni44NjIgQzE0MS40NTEsODcuMzQ2IDE0MS45NzcsODcuNjEzIDE0Mi41MTYsODcuNjEzIEMxNDIuNzk0LDg3LjYxMyAxNDMuMDc2LDg3LjU0MiAxNDMuMzMzLDg3LjM5MyBMMTY5Ljg2NSw3Mi4wNzYgTDE5Myw4NS40MzMgQzE5My41MjMsODUuNzM1IDE5NC4wNTgsODUuODg4IDE5NC41OSw4NS44ODggQzE5Ni4wODcsODUuODg4IDE5Ny4xNzMsODQuNjg5IDE5Ny4xNzMsODMuMDM2IEwxOTcuMTczLDI5LjAzNSBDMTk3LjE3MywyOC40NTEgMTk2Ljg2MSwyNy45MTEgMTk2LjM1NSwyNy42MTkgQzE5Ni4zNTUsMjcuNjE5IDE3MS44NDMsMTMuNDY3IDE3MC4zODUsMTIuNjI2IEMxNzAuMTMyLDEyLjQ4IDE2OS44NSwxMi40MDcgMTY5LjU2OCwxMi40MDcgQzE2OS4yODUsMTIuNDA3IDE2OS4wMDIsMTIuNDgxIDE2OC43NDksMTIuNjI3IEMxNjguMTQzLDEyLjk3OCAxNjUuNzU2LDE0LjM1NyAxNjQuNDI0LDE1LjEyNSBMMTU5LjYxNSwxMC44NyBDMTU4Ljc5NiwxMC4xNDUgMTU4LjE1NCw4LjkzNyAxNTguMDU0LDcuOTM0IEMxNTguMDQ1LDcuODM3IDE1OC4wMzQsNy43MzkgMTU4LjAyMSw3LjY0IEMxNTguMDA1LDcuNTIzIDE1Ny45OTgsNy40MSAxNTcuOTk4LDcuMzA0IEwxNTcuOTk4LDYuNDE4IEMxNTcuOTk4LDUuODM0IDE1Ny42ODYsNS4yOTUgMTU3LjE4MSw1LjAwMiBDMTU2LjYyNCw0LjY4IDE1MC40NDIsMS4xMTEgMTUwLjQ0MiwxLjExMSBDMTUwLjE4OSwwLjk2NSAxNDkuOTA3LDAuODkyIDE0OS42MjUsMC44OTIiIGlkPSJGaWxsLTEiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTYuMDI3LDI1LjYzNiBMMTQyLjYwMyw1Mi41MjcgQzE0My44MDcsNTMuMjIyIDE0NC41ODIsNTQuMTE0IDE0NC44NDUsNTUuMDY4IEwxNDQuODM1LDU1LjA3NSBMNjMuNDYxLDEwMi4wNTcgTDYzLjQ2LDEwMi4wNTcgQzYxLjgwNiwxMDEuOTA1IDYwLjI2MSwxMDEuNDU3IDU5LjA1NywxMDAuNzYyIEwxMi40ODEsNzMuODcxIEw5Ni4wMjcsMjUuNjM2IiBpZD0iRmlsbC0yIiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTYzLjQ2MSwxMDIuMTc0IEM2My40NTMsMTAyLjE3NCA2My40NDYsMTAyLjE3NCA2My40MzksMTAyLjE3MiBDNjEuNzQ2LDEwMi4wMTYgNjAuMjExLDEwMS41NjMgNTguOTk4LDEwMC44NjMgTDEyLjQyMiw3My45NzMgQzEyLjM4Niw3My45NTIgMTIuMzY0LDczLjkxNCAxMi4zNjQsNzMuODcxIEMxMi4zNjQsNzMuODMgMTIuMzg2LDczLjc5MSAxMi40MjIsNzMuNzcgTDk1Ljk2OCwyNS41MzUgQzk2LjAwNCwyNS41MTQgOTYuMDQ5LDI1LjUxNCA5Ni4wODUsMjUuNTM1IEwxNDIuNjYxLDUyLjQyNiBDMTQzLjg4OCw1My4xMzQgMTQ0LjY4Miw1NC4wMzggMTQ0Ljk1Nyw1NS4wMzcgQzE0NC45Nyw1NS4wODMgMTQ0Ljk1Myw1NS4xMzMgMTQ0LjkxNSw1NS4xNjEgQzE0NC45MTEsNTUuMTY1IDE0NC44OTgsNTUuMTc0IDE0NC44OTQsNTUuMTc3IEw2My41MTksMTAyLjE1OCBDNjMuNTAxLDEwMi4xNjkgNjMuNDgxLDEwMi4xNzQgNjMuNDYxLDEwMi4xNzQgTDYzLjQ2MSwxMDIuMTc0IFogTTEyLjcxNCw3My44NzEgTDU5LjExNSwxMDAuNjYxIEM2MC4yOTMsMTAxLjM0MSA2MS43ODYsMTAxLjc4MiA2My40MzUsMTAxLjkzNyBMMTQ0LjcwNyw1NS4wMTUgQzE0NC40MjgsNTQuMTA4IDE0My42ODIsNTMuMjg1IDE0Mi41NDQsNTIuNjI4IEw5Ni4wMjcsMjUuNzcxIEwxMi43MTQsNzMuODcxIEwxMi43MTQsNzMuODcxIFoiIGlkPSJGaWxsLTMiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ4LjMyNyw1OC40NzEgQzE0OC4xNDUsNTguNDggMTQ3Ljk2Miw1OC40OCAxNDcuNzgxLDU4LjQ3MiBDMTQ1Ljg4Nyw1OC4zODkgMTQ0LjQ3OSw1Ny40MzQgMTQ0LjYzNiw1Ni4zNCBDMTQ0LjY4OSw1NS45NjcgMTQ0LjY2NCw1NS41OTcgMTQ0LjU2NCw1NS4yMzUgTDYzLjQ2MSwxMDIuMDU3IEM2NC4wODksMTAyLjExNSA2NC43MzMsMTAyLjEzIDY1LjM3OSwxMDIuMDk5IEM2NS41NjEsMTAyLjA5IDY1Ljc0MywxMDIuMDkgNjUuOTI1LDEwMi4wOTggQzY3LjgxOSwxMDIuMTgxIDY5LjIyNywxMDMuMTM2IDY5LjA3LDEwNC4yMyBMMTQ4LjMyNyw1OC40NzEiIGlkPSJGaWxsLTQiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNjkuMDcsMTA0LjM0NyBDNjkuMDQ4LDEwNC4zNDcgNjkuMDI1LDEwNC4zNCA2OS4wMDUsMTA0LjMyNyBDNjguOTY4LDEwNC4zMDEgNjguOTQ4LDEwNC4yNTcgNjguOTU1LDEwNC4yMTMgQzY5LDEwMy44OTYgNjguODk4LDEwMy41NzYgNjguNjU4LDEwMy4yODggQzY4LjE1MywxMDIuNjc4IDY3LjEwMywxMDIuMjY2IDY1LjkyLDEwMi4yMTQgQzY1Ljc0MiwxMDIuMjA2IDY1LjU2MywxMDIuMjA3IDY1LjM4NSwxMDIuMjE1IEM2NC43NDIsMTAyLjI0NiA2NC4wODcsMTAyLjIzMiA2My40NSwxMDIuMTc0IEM2My4zOTksMTAyLjE2OSA2My4zNTgsMTAyLjEzMiA2My4zNDcsMTAyLjA4MiBDNjMuMzM2LDEwMi4wMzMgNjMuMzU4LDEwMS45ODEgNjMuNDAyLDEwMS45NTYgTDE0NC41MDYsNTUuMTM0IEMxNDQuNTM3LDU1LjExNiAxNDQuNTc1LDU1LjExMyAxNDQuNjA5LDU1LjEyNyBDMTQ0LjY0Miw1NS4xNDEgMTQ0LjY2OCw1NS4xNyAxNDQuNjc3LDU1LjIwNCBDMTQ0Ljc4MSw1NS41ODUgMTQ0LjgwNiw1NS45NzIgMTQ0Ljc1MSw1Ni4zNTcgQzE0NC43MDYsNTYuNjczIDE0NC44MDgsNTYuOTk0IDE0NS4wNDcsNTcuMjgyIEMxNDUuNTUzLDU3Ljg5MiAxNDYuNjAyLDU4LjMwMyAxNDcuNzg2LDU4LjM1NSBDMTQ3Ljk2NCw1OC4zNjMgMTQ4LjE0Myw1OC4zNjMgMTQ4LjMyMSw1OC4zNTQgQzE0OC4zNzcsNTguMzUyIDE0OC40MjQsNTguMzg3IDE0OC40MzksNTguNDM4IEMxNDguNDU0LDU4LjQ5IDE0OC40MzIsNTguNTQ1IDE0OC4zODUsNTguNTcyIEw2OS4xMjksMTA0LjMzMSBDNjkuMTExLDEwNC4zNDIgNjkuMDksMTA0LjM0NyA2OS4wNywxMDQuMzQ3IEw2OS4wNywxMDQuMzQ3IFogTTY1LjY2NSwxMDEuOTc1IEM2NS43NTQsMTAxLjk3NSA2NS44NDIsMTAxLjk3NyA2NS45MywxMDEuOTgxIEM2Ny4xOTYsMTAyLjAzNyA2OC4yODMsMTAyLjQ2OSA2OC44MzgsMTAzLjEzOSBDNjkuMDY1LDEwMy40MTMgNjkuMTg4LDEwMy43MTQgNjkuMTk4LDEwNC4wMjEgTDE0Ny44ODMsNTguNTkyIEMxNDcuODQ3LDU4LjU5MiAxNDcuODExLDU4LjU5MSAxNDcuNzc2LDU4LjU4OSBDMTQ2LjUwOSw1OC41MzMgMTQ1LjQyMiw1OC4xIDE0NC44NjcsNTcuNDMxIEMxNDQuNTg1LDU3LjA5MSAxNDQuNDY1LDU2LjcwNyAxNDQuNTIsNTYuMzI0IEMxNDQuNTYzLDU2LjAyMSAxNDQuNTUyLDU1LjcxNiAxNDQuNDg4LDU1LjQxNCBMNjMuODQ2LDEwMS45NyBDNjQuMzUzLDEwMi4wMDIgNjQuODY3LDEwMi4wMDYgNjUuMzc0LDEwMS45ODIgQzY1LjQ3MSwxMDEuOTc3IDY1LjU2OCwxMDEuOTc1IDY1LjY2NSwxMDEuOTc1IEw2NS42NjUsMTAxLjk3NSBaIiBpZD0iRmlsbC01IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTIuMjA4LDU1LjEzNCBDMS4yMDcsNTMuMzA3IDEuOTY3LDUwLjkxNyAzLjkwNiw0OS43OTcgTDU5LjkxNywxNy40NTMgQzYxLjg1NiwxNi4zMzMgNjQuMjQxLDE2LjkwNyA2NS4yNDMsMTguNzM0IEw2NS40NzUsMTkuMTQ0IEM2NS44NzIsMTkuODgyIDY2LjM2OCwyMC41NiA2Ni45NDUsMjEuMTY1IEw2Ny4yMjMsMjEuNDM1IEM3MC41NDgsMjQuNjQ5IDc1LjgwNiwyNS4xNTEgODAuMTExLDIyLjY2NSBMODcuNDMsMTguNDQ1IEM4OS4zNywxNy4zMjYgOTEuNzU0LDE3Ljg5OSA5Mi43NTUsMTkuNzI3IEw5Ni4wMDUsMjUuNjU1IEwxMi40ODYsNzMuODg0IEwyLjIwOCw1NS4xMzQgWiIgaWQ9IkZpbGwtNiIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMi40ODYsNzQuMDAxIEMxMi40NzYsNzQuMDAxIDEyLjQ2NSw3My45OTkgMTIuNDU1LDczLjk5NiBDMTIuNDI0LDczLjk4OCAxMi4zOTksNzMuOTY3IDEyLjM4NCw3My45NCBMMi4xMDYsNTUuMTkgQzEuMDc1LDUzLjMxIDEuODU3LDUwLjg0NSAzLjg0OCw0OS42OTYgTDU5Ljg1OCwxNy4zNTIgQzYwLjUyNSwxNi45NjcgNjEuMjcxLDE2Ljc2NCA2Mi4wMTYsMTYuNzY0IEM2My40MzEsMTYuNzY0IDY0LjY2NiwxNy40NjYgNjUuMzI3LDE4LjY0NiBDNjUuMzM3LDE4LjY1NCA2NS4zNDUsMTguNjYzIDY1LjM1MSwxOC42NzQgTDY1LjU3OCwxOS4wODggQzY1LjU4NCwxOS4xIDY1LjU4OSwxOS4xMTIgNjUuNTkxLDE5LjEyNiBDNjUuOTg1LDE5LjgzOCA2Ni40NjksMjAuNDk3IDY3LjAzLDIxLjA4NSBMNjcuMzA1LDIxLjM1MSBDNjkuMTUxLDIzLjEzNyA3MS42NDksMjQuMTIgNzQuMzM2LDI0LjEyIEM3Ni4zMTMsMjQuMTIgNzguMjksMjMuNTgyIDgwLjA1MywyMi41NjMgQzgwLjA2NCwyMi41NTcgODAuMDc2LDIyLjU1MyA4MC4wODgsMjIuNTUgTDg3LjM3MiwxOC4zNDQgQzg4LjAzOCwxNy45NTkgODguNzg0LDE3Ljc1NiA4OS41MjksMTcuNzU2IEM5MC45NTYsMTcuNzU2IDkyLjIwMSwxOC40NzIgOTIuODU4LDE5LjY3IEw5Ni4xMDcsMjUuNTk5IEM5Ni4xMzgsMjUuNjU0IDk2LjExOCwyNS43MjQgOTYuMDYzLDI1Ljc1NiBMMTIuNTQ1LDczLjk4NSBDMTIuNTI2LDczLjk5NiAxMi41MDYsNzQuMDAxIDEyLjQ4Niw3NC4wMDEgTDEyLjQ4Niw3NC4wMDEgWiBNNjIuMDE2LDE2Ljk5NyBDNjEuMzEyLDE2Ljk5NyA2MC42MDYsMTcuMTkgNTkuOTc1LDE3LjU1NCBMMy45NjUsNDkuODk5IEMyLjA4Myw1MC45ODUgMS4zNDEsNTMuMzA4IDIuMzEsNTUuMDc4IEwxMi41MzEsNzMuNzIzIEw5NS44NDgsMjUuNjExIEw5Mi42NTMsMTkuNzgyIEM5Mi4wMzgsMTguNjYgOTAuODcsMTcuOTkgODkuNTI5LDE3Ljk5IEM4OC44MjUsMTcuOTkgODguMTE5LDE4LjE4MiA4Ny40ODksMTguNTQ3IEw4MC4xNzIsMjIuNzcyIEM4MC4xNjEsMjIuNzc4IDgwLjE0OSwyMi43ODIgODAuMTM3LDIyLjc4NSBDNzguMzQ2LDIzLjgxMSA3Ni4zNDEsMjQuMzU0IDc0LjMzNiwyNC4zNTQgQzcxLjU4OCwyNC4zNTQgNjkuMDMzLDIzLjM0NyA2Ny4xNDIsMjEuNTE5IEw2Ni44NjQsMjEuMjQ5IEM2Ni4yNzcsMjAuNjM0IDY1Ljc3NCwxOS45NDcgNjUuMzY3LDE5LjIwMyBDNjUuMzYsMTkuMTkyIDY1LjM1NiwxOS4xNzkgNjUuMzU0LDE5LjE2NiBMNjUuMTYzLDE4LjgxOSBDNjUuMTU0LDE4LjgxMSA2NS4xNDYsMTguODAxIDY1LjE0LDE4Ljc5IEM2NC41MjUsMTcuNjY3IDYzLjM1NywxNi45OTcgNjIuMDE2LDE2Ljk5NyBMNjIuMDE2LDE2Ljk5NyBaIiBpZD0iRmlsbC03IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTQyLjQzNCw0OC44MDggTDQyLjQzNCw0OC44MDggQzM5LjkyNCw0OC44MDcgMzcuNzM3LDQ3LjU1IDM2LjU4Miw0NS40NDMgQzM0Ljc3MSw0Mi4xMzkgMzYuMTQ0LDM3LjgwOSAzOS42NDEsMzUuNzg5IEw1MS45MzIsMjguNjkxIEM1My4xMDMsMjguMDE1IDU0LjQxMywyNy42NTggNTUuNzIxLDI3LjY1OCBDNTguMjMxLDI3LjY1OCA2MC40MTgsMjguOTE2IDYxLjU3MywzMS4wMjMgQzYzLjM4NCwzNC4zMjcgNjIuMDEyLDM4LjY1NyA1OC41MTQsNDAuNjc3IEw0Ni4yMjMsNDcuNzc1IEM0NS4wNTMsNDguNDUgNDMuNzQyLDQ4LjgwOCA0Mi40MzQsNDguODA4IEw0Mi40MzQsNDguODA4IFogTTU1LjcyMSwyOC4xMjUgQzU0LjQ5NSwyOC4xMjUgNTMuMjY1LDI4LjQ2MSA1Mi4xNjYsMjkuMDk2IEwzOS44NzUsMzYuMTk0IEMzNi41OTYsMzguMDg3IDM1LjMwMiw0Mi4xMzYgMzYuOTkyLDQ1LjIxOCBDMzguMDYzLDQ3LjE3MyA0MC4wOTgsNDguMzQgNDIuNDM0LDQ4LjM0IEM0My42NjEsNDguMzQgNDQuODksNDguMDA1IDQ1Ljk5LDQ3LjM3IEw1OC4yODEsNDAuMjcyIEM2MS41NiwzOC4zNzkgNjIuODUzLDM0LjMzIDYxLjE2NCwzMS4yNDggQzYwLjA5MiwyOS4yOTMgNTguMDU4LDI4LjEyNSA1NS43MjEsMjguMTI1IEw1NS43MjEsMjguMTI1IFoiIGlkPSJGaWxsLTgiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ5LjU4OCwyLjQwNyBDMTQ5LjU4OCwyLjQwNyAxNTUuNzY4LDUuOTc1IDE1Ni4zMjUsNi4yOTcgTDE1Ni4zMjUsNy4xODQgQzE1Ni4zMjUsNy4zNiAxNTYuMzM4LDcuNTQ0IDE1Ni4zNjIsNy43MzMgQzE1Ni4zNzMsNy44MTQgMTU2LjM4Miw3Ljg5NCAxNTYuMzksNy45NzUgQzE1Ni41Myw5LjM5IDE1Ny4zNjMsMTAuOTczIDE1OC40OTUsMTEuOTc0IEwxNjUuODkxLDE4LjUxOSBDMTY2LjA2OCwxOC42NzUgMTY2LjI0OSwxOC44MTQgMTY2LjQzMiwxOC45MzQgQzE2OC4wMTEsMTkuOTc0IDE2OS4zODIsMTkuNCAxNjkuNDk0LDE3LjY1MiBDMTY5LjU0MywxNi44NjggMTY5LjU1MSwxNi4wNTcgMTY5LjUxNywxNS4yMjMgTDE2OS41MTQsMTUuMDYzIEwxNjkuNTE0LDEzLjkxMiBDMTcwLjc4LDE0LjY0MiAxOTUuNTAxLDI4LjkxNSAxOTUuNTAxLDI4LjkxNSBMMTk1LjUwMSw4Mi45MTUgQzE5NS41MDEsODQuMDA1IDE5NC43MzEsODQuNDQ1IDE5My43ODEsODMuODk3IEwxNTEuMzA4LDU5LjM3NCBDMTUwLjM1OCw1OC44MjYgMTQ5LjU4OCw1Ny40OTcgMTQ5LjU4OCw1Ni40MDggTDE0OS41ODgsMjIuMzc1IiBpZD0iRmlsbC05IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE5NC41NTMsODQuMjUgQzE5NC4yOTYsODQuMjUgMTk0LjAxMyw4NC4xNjUgMTkzLjcyMiw4My45OTcgTDE1MS4yNSw1OS40NzYgQzE1MC4yNjksNTguOTA5IDE0OS40NzEsNTcuNTMzIDE0OS40NzEsNTYuNDA4IEwxNDkuNDcxLDIyLjM3NSBMMTQ5LjcwNSwyMi4zNzUgTDE0OS43MDUsNTYuNDA4IEMxNDkuNzA1LDU3LjQ1OSAxNTAuNDUsNTguNzQ0IDE1MS4zNjYsNTkuMjc0IEwxOTMuODM5LDgzLjc5NSBDMTk0LjI2Myw4NC4wNCAxOTQuNjU1LDg0LjA4MyAxOTQuOTQyLDgzLjkxNyBDMTk1LjIyNyw4My43NTMgMTk1LjM4NCw4My4zOTcgMTk1LjM4NCw4Mi45MTUgTDE5NS4zODQsMjguOTgyIEMxOTQuMTAyLDI4LjI0MiAxNzIuMTA0LDE1LjU0MiAxNjkuNjMxLDE0LjExNCBMMTY5LjYzNCwxNS4yMiBDMTY5LjY2OCwxNi4wNTIgMTY5LjY2LDE2Ljg3NCAxNjkuNjEsMTcuNjU5IEMxNjkuNTU2LDE4LjUwMyAxNjkuMjE0LDE5LjEyMyAxNjguNjQ3LDE5LjQwNSBDMTY4LjAyOCwxOS43MTQgMTY3LjE5NywxOS41NzggMTY2LjM2NywxOS4wMzIgQzE2Ni4xODEsMTguOTA5IDE2NS45OTUsMTguNzY2IDE2NS44MTQsMTguNjA2IEwxNTguNDE3LDEyLjA2MiBDMTU3LjI1OSwxMS4wMzYgMTU2LjQxOCw5LjQzNyAxNTYuMjc0LDcuOTg2IEMxNTYuMjY2LDcuOTA3IDE1Ni4yNTcsNy44MjcgMTU2LjI0Nyw3Ljc0OCBDMTU2LjIyMSw3LjU1NSAxNTYuMjA5LDcuMzY1IDE1Ni4yMDksNy4xODQgTDE1Ni4yMDksNi4zNjQgQzE1NS4zNzUsNS44ODMgMTQ5LjUyOSwyLjUwOCAxNDkuNTI5LDIuNTA4IEwxNDkuNjQ2LDIuMzA2IEMxNDkuNjQ2LDIuMzA2IDE1NS44MjcsNS44NzQgMTU2LjM4NCw2LjE5NiBMMTU2LjQ0Miw2LjIzIEwxNTYuNDQyLDcuMTg0IEMxNTYuNDQyLDcuMzU1IDE1Ni40NTQsNy41MzUgMTU2LjQ3OCw3LjcxNyBDMTU2LjQ4OSw3LjggMTU2LjQ5OSw3Ljg4MiAxNTYuNTA3LDcuOTYzIEMxNTYuNjQ1LDkuMzU4IDE1Ny40NTUsMTAuODk4IDE1OC41NzIsMTEuODg2IEwxNjUuOTY5LDE4LjQzMSBDMTY2LjE0MiwxOC41ODQgMTY2LjMxOSwxOC43MiAxNjYuNDk2LDE4LjgzNyBDMTY3LjI1NCwxOS4zMzYgMTY4LDE5LjQ2NyAxNjguNTQzLDE5LjE5NiBDMTY5LjAzMywxOC45NTMgMTY5LjMyOSwxOC40MDEgMTY5LjM3NywxNy42NDUgQzE2OS40MjcsMTYuODY3IDE2OS40MzQsMTYuMDU0IDE2OS40MDEsMTUuMjI4IEwxNjkuMzk3LDE1LjA2NSBMMTY5LjM5NywxMy43MSBMMTY5LjU3MiwxMy44MSBDMTcwLjgzOSwxNC41NDEgMTk1LjU1OSwyOC44MTQgMTk1LjU1OSwyOC44MTQgTDE5NS42MTgsMjguODQ3IEwxOTUuNjE4LDgyLjkxNSBDMTk1LjYxOCw4My40ODQgMTk1LjQyLDgzLjkxMSAxOTUuMDU5LDg0LjExOSBDMTk0LjkwOCw4NC4yMDYgMTk0LjczNyw4NC4yNSAxOTQuNTUzLDg0LjI1IiBpZD0iRmlsbC0xMCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNDUuNjg1LDU2LjE2MSBMMTY5LjgsNzAuMDgzIEwxNDMuODIyLDg1LjA4MSBMMTQyLjM2LDg0Ljc3NCBDMTM1LjgyNiw4Mi42MDQgMTI4LjczMiw4MS4wNDYgMTIxLjM0MSw4MC4xNTggQzExNi45NzYsNzkuNjM0IDExMi42NzgsODEuMjU0IDExMS43NDMsODMuNzc4IEMxMTEuNTA2LDg0LjQxNCAxMTEuNTAzLDg1LjA3MSAxMTEuNzMyLDg1LjcwNiBDMTEzLjI3LDg5Ljk3MyAxMTUuOTY4LDk0LjA2OSAxMTkuNzI3LDk3Ljg0MSBMMTIwLjI1OSw5OC42ODYgQzEyMC4yNiw5OC42ODUgOTQuMjgyLDExMy42ODMgOTQuMjgyLDExMy42ODMgTDcwLjE2Nyw5OS43NjEgTDE0NS42ODUsNTYuMTYxIiBpZD0iRmlsbC0xMSIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik05NC4yODIsMTEzLjgxOCBMOTQuMjIzLDExMy43ODUgTDY5LjkzMyw5OS43NjEgTDcwLjEwOCw5OS42NiBMMTQ1LjY4NSw1Ni4wMjYgTDE0NS43NDMsNTYuMDU5IEwxNzAuMDMzLDcwLjA4MyBMMTQzLjg0Miw4NS4yMDUgTDE0My43OTcsODUuMTk1IEMxNDMuNzcyLDg1LjE5IDE0Mi4zMzYsODQuODg4IDE0Mi4zMzYsODQuODg4IEMxMzUuNzg3LDgyLjcxNCAxMjguNzIzLDgxLjE2MyAxMjEuMzI3LDgwLjI3NCBDMTIwLjc4OCw4MC4yMDkgMTIwLjIzNiw4MC4xNzcgMTE5LjY4OSw4MC4xNzcgQzExNS45MzEsODAuMTc3IDExMi42MzUsODEuNzA4IDExMS44NTIsODMuODE5IEMxMTEuNjI0LDg0LjQzMiAxMTEuNjIxLDg1LjA1MyAxMTEuODQyLDg1LjY2NyBDMTEzLjM3Nyw4OS45MjUgMTE2LjA1OCw5My45OTMgMTE5LjgxLDk3Ljc1OCBMMTE5LjgyNiw5Ny43NzkgTDEyMC4zNTIsOTguNjE0IEMxMjAuMzU0LDk4LjYxNyAxMjAuMzU2LDk4LjYyIDEyMC4zNTgsOTguNjI0IEwxMjAuNDIyLDk4LjcyNiBMMTIwLjMxNyw5OC43ODcgQzEyMC4yNjQsOTguODE4IDk0LjU5OSwxMTMuNjM1IDk0LjM0LDExMy43ODUgTDk0LjI4MiwxMTMuODE4IEw5NC4yODIsMTEzLjgxOCBaIE03MC40MDEsOTkuNzYxIEw5NC4yODIsMTEzLjU0OSBMMTE5LjA4NCw5OS4yMjkgQzExOS42Myw5OC45MTQgMTE5LjkzLDk4Ljc0IDEyMC4xMDEsOTguNjU0IEwxMTkuNjM1LDk3LjkxNCBDMTE1Ljg2NCw5NC4xMjcgMTEzLjE2OCw5MC4wMzMgMTExLjYyMiw4NS43NDYgQzExMS4zODIsODUuMDc5IDExMS4zODYsODQuNDA0IDExMS42MzMsODMuNzM4IEMxMTIuNDQ4LDgxLjUzOSAxMTUuODM2LDc5Ljk0MyAxMTkuNjg5LDc5Ljk0MyBDMTIwLjI0Niw3OS45NDMgMTIwLjgwNiw3OS45NzYgMTIxLjM1NSw4MC4wNDIgQzEyOC43NjcsODAuOTMzIDEzNS44NDYsODIuNDg3IDE0Mi4zOTYsODQuNjYzIEMxNDMuMjMyLDg0LjgzOCAxNDMuNjExLDg0LjkxNyAxNDMuNzg2LDg0Ljk2NyBMMTY5LjU2Niw3MC4wODMgTDE0NS42ODUsNTYuMjk1IEw3MC40MDEsOTkuNzYxIEw3MC40MDEsOTkuNzYxIFoiIGlkPSJGaWxsLTEyIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2Ny4yMywxOC45NzkgTDE2Ny4yMyw2OS44NSBMMTM5LjkwOSw4NS42MjMgTDEzMy40NDgsNzEuNDU2IEMxMzIuNTM4LDY5LjQ2IDEzMC4wMiw2OS43MTggMTI3LjgyNCw3Mi4wMyBDMTI2Ljc2OSw3My4xNCAxMjUuOTMxLDc0LjU4NSAxMjUuNDk0LDc2LjA0OCBMMTE5LjAzNCw5Ny42NzYgTDkxLjcxMiwxMTMuNDUgTDkxLjcxMiw2Mi41NzkgTDE2Ny4yMywxOC45NzkiIGlkPSJGaWxsLTEzIiBmaWxsPSIjRkZGRkZGIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTkxLjcxMiwxMTMuNTY3IEM5MS42OTIsMTEzLjU2NyA5MS42NzIsMTEzLjU2MSA5MS42NTMsMTEzLjU1MSBDOTEuNjE4LDExMy41MyA5MS41OTUsMTEzLjQ5MiA5MS41OTUsMTEzLjQ1IEw5MS41OTUsNjIuNTc5IEM5MS41OTUsNjIuNTM3IDkxLjYxOCw2Mi40OTkgOTEuNjUzLDYyLjQ3OCBMMTY3LjE3MiwxOC44NzggQzE2Ny4yMDgsMTguODU3IDE2Ny4yNTIsMTguODU3IDE2Ny4yODgsMTguODc4IEMxNjcuMzI0LDE4Ljg5OSAxNjcuMzQ3LDE4LjkzNyAxNjcuMzQ3LDE4Ljk3OSBMMTY3LjM0Nyw2OS44NSBDMTY3LjM0Nyw2OS44OTEgMTY3LjMyNCw2OS45MyAxNjcuMjg4LDY5Ljk1IEwxMzkuOTY3LDg1LjcyNSBDMTM5LjkzOSw4NS43NDEgMTM5LjkwNSw4NS43NDUgMTM5Ljg3Myw4NS43MzUgQzEzOS44NDIsODUuNzI1IDEzOS44MTYsODUuNzAyIDEzOS44MDIsODUuNjcyIEwxMzMuMzQyLDcxLjUwNCBDMTMyLjk2Nyw3MC42ODIgMTMyLjI4LDcwLjIyOSAxMzEuNDA4LDcwLjIyOSBDMTMwLjMxOSw3MC4yMjkgMTI5LjA0NCw3MC45MTUgMTI3LjkwOCw3Mi4xMSBDMTI2Ljg3NCw3My4yIDEyNi4wMzQsNzQuNjQ3IDEyNS42MDYsNzYuMDgyIEwxMTkuMTQ2LDk3LjcwOSBDMTE5LjEzNyw5Ny43MzggMTE5LjExOCw5Ny43NjIgMTE5LjA5Miw5Ny43NzcgTDkxLjc3LDExMy41NTEgQzkxLjc1MiwxMTMuNTYxIDkxLjczMiwxMTMuNTY3IDkxLjcxMiwxMTMuNTY3IEw5MS43MTIsMTEzLjU2NyBaIE05MS44MjksNjIuNjQ3IEw5MS44MjksMTEzLjI0OCBMMTE4LjkzNSw5Ny41OTggTDEyNS4zODIsNzYuMDE1IEMxMjUuODI3LDc0LjUyNSAxMjYuNjY0LDczLjA4MSAxMjcuNzM5LDcxLjk1IEMxMjguOTE5LDcwLjcwOCAxMzAuMjU2LDY5Ljk5NiAxMzEuNDA4LDY5Ljk5NiBDMTMyLjM3Nyw2OS45OTYgMTMzLjEzOSw3MC40OTcgMTMzLjU1NCw3MS40MDcgTDEzOS45NjEsODUuNDU4IEwxNjcuMTEzLDY5Ljc4MiBMMTY3LjExMywxOS4xODEgTDkxLjgyOSw2Mi42NDcgTDkxLjgyOSw2Mi42NDcgWiIgaWQ9IkZpbGwtMTQiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTY4LjU0MywxOS4yMTMgTDE2OC41NDMsNzAuMDgzIEwxNDEuMjIxLDg1Ljg1NyBMMTM0Ljc2MSw3MS42ODkgQzEzMy44NTEsNjkuNjk0IDEzMS4zMzMsNjkuOTUxIDEyOS4xMzcsNzIuMjYzIEMxMjguMDgyLDczLjM3NCAxMjcuMjQ0LDc0LjgxOSAxMjYuODA3LDc2LjI4MiBMMTIwLjM0Niw5Ny45MDkgTDkzLjAyNSwxMTMuNjgzIEw5My4wMjUsNjIuODEzIEwxNjguNTQzLDE5LjIxMyIgaWQ9IkZpbGwtMTUiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTMuMDI1LDExMy44IEM5My4wMDUsMTEzLjggOTIuOTg0LDExMy43OTUgOTIuOTY2LDExMy43ODUgQzkyLjkzMSwxMTMuNzY0IDkyLjkwOCwxMTMuNzI1IDkyLjkwOCwxMTMuNjg0IEw5Mi45MDgsNjIuODEzIEM5Mi45MDgsNjIuNzcxIDkyLjkzMSw2Mi43MzMgOTIuOTY2LDYyLjcxMiBMMTY4LjQ4NCwxOS4xMTIgQzE2OC41MiwxOS4wOSAxNjguNTY1LDE5LjA5IDE2OC42MDEsMTkuMTEyIEMxNjguNjM3LDE5LjEzMiAxNjguNjYsMTkuMTcxIDE2OC42NiwxOS4yMTIgTDE2OC42Niw3MC4wODMgQzE2OC42Niw3MC4xMjUgMTY4LjYzNyw3MC4xNjQgMTY4LjYwMSw3MC4xODQgTDE0MS4yOCw4NS45NTggQzE0MS4yNTEsODUuOTc1IDE0MS4yMTcsODUuOTc5IDE0MS4xODYsODUuOTY4IEMxNDEuMTU0LDg1Ljk1OCAxNDEuMTI5LDg1LjkzNiAxNDEuMTE1LDg1LjkwNiBMMTM0LjY1NSw3MS43MzggQzEzNC4yOCw3MC45MTUgMTMzLjU5Myw3MC40NjMgMTMyLjcyLDcwLjQ2MyBDMTMxLjYzMiw3MC40NjMgMTMwLjM1Nyw3MS4xNDggMTI5LjIyMSw3Mi4zNDQgQzEyOC4xODYsNzMuNDMzIDEyNy4zNDcsNzQuODgxIDEyNi45MTksNzYuMzE1IEwxMjAuNDU4LDk3Ljk0MyBDMTIwLjQ1LDk3Ljk3MiAxMjAuNDMxLDk3Ljk5NiAxMjAuNDA1LDk4LjAxIEw5My4wODMsMTEzLjc4NSBDOTMuMDY1LDExMy43OTUgOTMuMDQ1LDExMy44IDkzLjAyNSwxMTMuOCBMOTMuMDI1LDExMy44IFogTTkzLjE0Miw2Mi44ODEgTDkzLjE0MiwxMTMuNDgxIEwxMjAuMjQ4LDk3LjgzMiBMMTI2LjY5NSw3Ni4yNDggQzEyNy4xNCw3NC43NTggMTI3Ljk3Nyw3My4zMTUgMTI5LjA1Miw3Mi4xODMgQzEzMC4yMzEsNzAuOTQyIDEzMS41NjgsNzAuMjI5IDEzMi43Miw3MC4yMjkgQzEzMy42ODksNzAuMjI5IDEzNC40NTIsNzAuNzMxIDEzNC44NjcsNzEuNjQxIEwxNDEuMjc0LDg1LjY5MiBMMTY4LjQyNiw3MC4wMTYgTDE2OC40MjYsMTkuNDE1IEw5My4xNDIsNjIuODgxIEw5My4xNDIsNjIuODgxIFoiIGlkPSJGaWxsLTE2IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2OS44LDcwLjA4MyBMMTQyLjQ3OCw4NS44NTcgTDEzNi4wMTgsNzEuNjg5IEMxMzUuMTA4LDY5LjY5NCAxMzIuNTksNjkuOTUxIDEzMC4zOTMsNzIuMjYzIEMxMjkuMzM5LDczLjM3NCAxMjguNSw3NC44MTkgMTI4LjA2NCw3Ni4yODIgTDEyMS42MDMsOTcuOTA5IEw5NC4yODIsMTEzLjY4MyBMOTQuMjgyLDYyLjgxMyBMMTY5LjgsMTkuMjEzIEwxNjkuOCw3MC4wODMgWiIgaWQ9IkZpbGwtMTciIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTQuMjgyLDExMy45MTcgQzk0LjI0MSwxMTMuOTE3IDk0LjIwMSwxMTMuOTA3IDk0LjE2NSwxMTMuODg2IEM5NC4wOTMsMTEzLjg0NSA5NC4wNDgsMTEzLjc2NyA5NC4wNDgsMTEzLjY4NCBMOTQuMDQ4LDYyLjgxMyBDOTQuMDQ4LDYyLjczIDk0LjA5Myw2Mi42NTIgOTQuMTY1LDYyLjYxMSBMMTY5LjY4MywxOS4wMSBDMTY5Ljc1NSwxOC45NjkgMTY5Ljg0NCwxOC45NjkgMTY5LjkxNywxOS4wMSBDMTY5Ljk4OSwxOS4wNTIgMTcwLjAzMywxOS4xMjkgMTcwLjAzMywxOS4yMTIgTDE3MC4wMzMsNzAuMDgzIEMxNzAuMDMzLDcwLjE2NiAxNjkuOTg5LDcwLjI0NCAxNjkuOTE3LDcwLjI4NSBMMTQyLjU5NSw4Ni4wNiBDMTQyLjUzOCw4Ni4wOTIgMTQyLjQ2OSw4Ni4xIDE0Mi40MDcsODYuMDggQzE0Mi4zNDQsODYuMDYgMTQyLjI5Myw4Ni4wMTQgMTQyLjI2Niw4NS45NTQgTDEzNS44MDUsNzEuNzg2IEMxMzUuNDQ1LDcwLjk5NyAxMzQuODEzLDcwLjU4IDEzMy45NzcsNzAuNTggQzEzMi45MjEsNzAuNTggMTMxLjY3Niw3MS4yNTIgMTMwLjU2Miw3Mi40MjQgQzEyOS41NCw3My41MDEgMTI4LjcxMSw3NC45MzEgMTI4LjI4Nyw3Ni4zNDggTDEyMS44MjcsOTcuOTc2IEMxMjEuODEsOTguMDM0IDEyMS43NzEsOTguMDgyIDEyMS43Miw5OC4xMTIgTDk0LjM5OCwxMTMuODg2IEM5NC4zNjIsMTEzLjkwNyA5NC4zMjIsMTEzLjkxNyA5NC4yODIsMTEzLjkxNyBMOTQuMjgyLDExMy45MTcgWiBNOTQuNTE1LDYyLjk0OCBMOTQuNTE1LDExMy4yNzkgTDEyMS40MDYsOTcuNzU0IEwxMjcuODQsNzYuMjE1IEMxMjguMjksNzQuNzA4IDEyOS4xMzcsNzMuMjQ3IDEzMC4yMjQsNzIuMTAzIEMxMzEuNDI1LDcwLjgzOCAxMzIuNzkzLDcwLjExMiAxMzMuOTc3LDcwLjExMiBDMTM0Ljk5NSw3MC4xMTIgMTM1Ljc5NSw3MC42MzggMTM2LjIzLDcxLjU5MiBMMTQyLjU4NCw4NS41MjYgTDE2OS41NjYsNjkuOTQ4IEwxNjkuNTY2LDE5LjYxNyBMOTQuNTE1LDYyLjk0OCBMOTQuNTE1LDYyLjk0OCBaIiBpZD0iRmlsbC0xOCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMDkuODk0LDkyLjk0MyBMMTA5Ljg5NCw5Mi45NDMgQzEwOC4xMiw5Mi45NDMgMTA2LjY1Myw5Mi4yMTggMTA1LjY1LDkwLjgyMyBDMTA1LjU4Myw5MC43MzEgMTA1LjU5Myw5MC42MSAxMDUuNjczLDkwLjUyOSBDMTA1Ljc1Myw5MC40NDggMTA1Ljg4LDkwLjQ0IDEwNS45NzQsOTAuNTA2IEMxMDYuNzU0LDkxLjA1MyAxMDcuNjc5LDkxLjMzMyAxMDguNzI0LDkxLjMzMyBDMTEwLjA0Nyw5MS4zMzMgMTExLjQ3OCw5MC44OTQgMTEyLjk4LDkwLjAyNyBDMTE4LjI5MSw4Ni45NiAxMjIuNjExLDc5LjUwOSAxMjIuNjExLDczLjQxNiBDMTIyLjYxMSw3MS40ODkgMTIyLjE2OSw2OS44NTYgMTIxLjMzMyw2OC42OTIgQzEyMS4yNjYsNjguNiAxMjEuMjc2LDY4LjQ3MyAxMjEuMzU2LDY4LjM5MiBDMTIxLjQzNiw2OC4zMTEgMTIxLjU2Myw2OC4yOTkgMTIxLjY1Niw2OC4zNjUgQzEyMy4zMjcsNjkuNTM3IDEyNC4yNDcsNzEuNzQ2IDEyNC4yNDcsNzQuNTg0IEMxMjQuMjQ3LDgwLjgyNiAxMTkuODIxLDg4LjQ0NyAxMTQuMzgyLDkxLjU4NyBDMTEyLjgwOCw5Mi40OTUgMTExLjI5OCw5Mi45NDMgMTA5Ljg5NCw5Mi45NDMgTDEwOS44OTQsOTIuOTQzIFogTTEwNi45MjUsOTEuNDAxIEMxMDcuNzM4LDkyLjA1MiAxMDguNzQ1LDkyLjI3OCAxMDkuODkzLDkyLjI3OCBMMTA5Ljg5NCw5Mi4yNzggQzExMS4yMTUsOTIuMjc4IDExMi42NDcsOTEuOTUxIDExNC4xNDgsOTEuMDg0IEMxMTkuNDU5LDg4LjAxNyAxMjMuNzgsODAuNjIxIDEyMy43OCw3NC41MjggQzEyMy43OCw3Mi41NDkgMTIzLjMxNyw3MC45MjkgMTIyLjQ1NCw2OS43NjcgQzEyMi44NjUsNzAuODAyIDEyMy4wNzksNzIuMDQyIDEyMy4wNzksNzMuNDAyIEMxMjMuMDc5LDc5LjY0NSAxMTguNjUzLDg3LjI4NSAxMTMuMjE0LDkwLjQyNSBDMTExLjY0LDkxLjMzNCAxMTAuMTMsOTEuNzQyIDEwOC43MjQsOTEuNzQyIEMxMDguMDgzLDkxLjc0MiAxMDcuNDgxLDkxLjU5MyAxMDYuOTI1LDkxLjQwMSBMMTA2LjkyNSw5MS40MDEgWiIgaWQ9IkZpbGwtMTkiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjA5Nyw5MC4yMyBDMTE4LjQ4MSw4Ny4xMjIgMTIyLjg0NSw3OS41OTQgMTIyLjg0NSw3My40MTYgQzEyMi44NDUsNzEuMzY1IDEyMi4zNjIsNjkuNzI0IDEyMS41MjIsNjguNTU2IEMxMTkuNzM4LDY3LjMwNCAxMTcuMTQ4LDY3LjM2MiAxMTQuMjY1LDY5LjAyNiBDMTA4Ljg4MSw3Mi4xMzQgMTA0LjUxNyw3OS42NjIgMTA0LjUxNyw4NS44NCBDMTA0LjUxNyw4Ny44OTEgMTA1LDg5LjUzMiAxMDUuODQsOTAuNyBDMTA3LjYyNCw5MS45NTIgMTEwLjIxNCw5MS44OTQgMTEzLjA5Nyw5MC4yMyIgaWQ9IkZpbGwtMjAiIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTA4LjcyNCw5MS42MTQgTDEwOC43MjQsOTEuNjE0IEMxMDcuNTgyLDkxLjYxNCAxMDYuNTY2LDkxLjQwMSAxMDUuNzA1LDkwLjc5NyBDMTA1LjY4NCw5MC43ODMgMTA1LjY2NSw5MC44MTEgMTA1LjY1LDkwLjc5IEMxMDQuNzU2LDg5LjU0NiAxMDQuMjgzLDg3Ljg0MiAxMDQuMjgzLDg1LjgxNyBDMTA0LjI4Myw3OS41NzUgMTA4LjcwOSw3MS45NTMgMTE0LjE0OCw2OC44MTIgQzExNS43MjIsNjcuOTA0IDExNy4yMzIsNjcuNDQ5IDExOC42MzgsNjcuNDQ5IEMxMTkuNzgsNjcuNDQ5IDEyMC43OTYsNjcuNzU4IDEyMS42NTYsNjguMzYyIEMxMjEuNjc4LDY4LjM3NyAxMjEuNjk3LDY4LjM5NyAxMjEuNzEyLDY4LjQxOCBDMTIyLjYwNiw2OS42NjIgMTIzLjA3OSw3MS4zOSAxMjMuMDc5LDczLjQxNSBDMTIzLjA3OSw3OS42NTggMTE4LjY1Myw4Ny4xOTggMTEzLjIxNCw5MC4zMzggQzExMS42NCw5MS4yNDcgMTEwLjEzLDkxLjYxNCAxMDguNzI0LDkxLjYxNCBMMTA4LjcyNCw5MS42MTQgWiBNMTA2LjAwNiw5MC41MDUgQzEwNi43OCw5MS4wMzcgMTA3LjY5NCw5MS4yODEgMTA4LjcyNCw5MS4yODEgQzExMC4wNDcsOTEuMjgxIDExMS40NzgsOTAuODY4IDExMi45OCw5MC4wMDEgQzExOC4yOTEsODYuOTM1IDEyMi42MTEsNzkuNDk2IDEyMi42MTEsNzMuNDAzIEMxMjIuNjExLDcxLjQ5NCAxMjIuMTc3LDY5Ljg4IDEyMS4zNTYsNjguNzE4IEMxMjAuNTgyLDY4LjE4NSAxMTkuNjY4LDY3LjkxOSAxMTguNjM4LDY3LjkxOSBDMTE3LjMxNSw2Ny45MTkgMTE1Ljg4Myw2OC4zNiAxMTQuMzgyLDY5LjIyNyBDMTA5LjA3MSw3Mi4yOTMgMTA0Ljc1MSw3OS43MzMgMTA0Ljc1MSw4NS44MjYgQzEwNC43NTEsODcuNzM1IDEwNS4xODUsODkuMzQzIDEwNi4wMDYsOTAuNTA1IEwxMDYuMDA2LDkwLjUwNSBaIiBpZD0iRmlsbC0yMSIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNDkuMzE4LDcuMjYyIEwxMzkuMzM0LDE2LjE0IEwxNTUuMjI3LDI3LjE3MSBMMTYwLjgxNiwyMS4wNTkgTDE0OS4zMTgsNy4yNjIiIGlkPSJGaWxsLTIyIiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2OS42NzYsMTMuODQgTDE1OS45MjgsMTkuNDY3IEMxNTYuMjg2LDIxLjU3IDE1MC40LDIxLjU4IDE0Ni43ODEsMTkuNDkxIEMxNDMuMTYxLDE3LjQwMiAxNDMuMTgsMTQuMDAzIDE0Ni44MjIsMTEuOSBMMTU2LjMxNyw2LjI5MiBMMTQ5LjU4OCwyLjQwNyBMNjcuNzUyLDQ5LjQ3OCBMMTEzLjY3NSw3NS45OTIgTDExNi43NTYsNzQuMjEzIEMxMTcuMzg3LDczLjg0OCAxMTcuNjI1LDczLjMxNSAxMTcuMzc0LDcyLjgyMyBDMTE1LjAxNyw2OC4xOTEgMTE0Ljc4MSw2My4yNzcgMTE2LjY5MSw1OC41NjEgQzEyMi4zMjksNDQuNjQxIDE0MS4yLDMzLjc0NiAxNjUuMzA5LDMwLjQ5MSBDMTczLjQ3OCwyOS4zODggMTgxLjk4OSwyOS41MjQgMTkwLjAxMywzMC44ODUgQzE5MC44NjUsMzEuMDMgMTkxLjc4OSwzMC44OTMgMTkyLjQyLDMwLjUyOCBMMTk1LjUwMSwyOC43NSBMMTY5LjY3NiwxMy44NCIgaWQ9IkZpbGwtMjMiIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjY3NSw3Ni40NTkgQzExMy41OTQsNzYuNDU5IDExMy41MTQsNzYuNDM4IDExMy40NDIsNzYuMzk3IEw2Ny41MTgsNDkuODgyIEM2Ny4zNzQsNDkuNzk5IDY3LjI4NCw0OS42NDUgNjcuMjg1LDQ5LjQ3OCBDNjcuMjg1LDQ5LjMxMSA2Ny4zNzQsNDkuMTU3IDY3LjUxOSw0OS4wNzMgTDE0OS4zNTUsMi4wMDIgQzE0OS40OTksMS45MTkgMTQ5LjY3NywxLjkxOSAxNDkuODIxLDIuMDAyIEwxNTYuNTUsNS44ODcgQzE1Ni43NzQsNi4wMTcgMTU2Ljg1LDYuMzAyIDE1Ni43MjIsNi41MjYgQzE1Ni41OTIsNi43NDkgMTU2LjMwNyw2LjgyNiAxNTYuMDgzLDYuNjk2IEwxNDkuNTg3LDIuOTQ2IEw2OC42ODcsNDkuNDc5IEwxMTMuNjc1LDc1LjQ1MiBMMTE2LjUyMyw3My44MDggQzExNi43MTUsNzMuNjk3IDExNy4xNDMsNzMuMzk5IDExNi45NTgsNzMuMDM1IEMxMTQuNTQyLDY4LjI4NyAxMTQuMyw2My4yMjEgMTE2LjI1OCw1OC4zODUgQzExOS4wNjQsNTEuNDU4IDEyNS4xNDMsNDUuMTQzIDEzMy44NCw0MC4xMjIgQzE0Mi40OTcsMzUuMTI0IDE1My4zNTgsMzEuNjMzIDE2NS4yNDcsMzAuMDI4IEMxNzMuNDQ1LDI4LjkyMSAxODIuMDM3LDI5LjA1OCAxOTAuMDkxLDMwLjQyNSBDMTkwLjgzLDMwLjU1IDE5MS42NTIsMzAuNDMyIDE5Mi4xODYsMzAuMTI0IEwxOTQuNTY3LDI4Ljc1IEwxNjkuNDQyLDE0LjI0NCBDMTY5LjIxOSwxNC4xMTUgMTY5LjE0MiwxMy44MjkgMTY5LjI3MSwxMy42MDYgQzE2OS40LDEzLjM4MiAxNjkuNjg1LDEzLjMwNiAxNjkuOTA5LDEzLjQzNSBMMTk1LjczNCwyOC4zNDUgQzE5NS44NzksMjguNDI4IDE5NS45NjgsMjguNTgzIDE5NS45NjgsMjguNzUgQzE5NS45NjgsMjguOTE2IDE5NS44NzksMjkuMDcxIDE5NS43MzQsMjkuMTU0IEwxOTIuNjUzLDMwLjkzMyBDMTkxLjkzMiwzMS4zNSAxOTAuODksMzEuNTA4IDE4OS45MzUsMzEuMzQ2IEMxODEuOTcyLDI5Ljk5NSAxNzMuNDc4LDI5Ljg2IDE2NS4zNzIsMzAuOTU0IEMxNTMuNjAyLDMyLjU0MyAxNDIuODYsMzUuOTkzIDEzNC4zMDcsNDAuOTMxIEMxMjUuNzkzLDQ1Ljg0NyAxMTkuODUxLDUyLjAwNCAxMTcuMTI0LDU4LjczNiBDMTE1LjI3LDYzLjMxNCAxMTUuNTAxLDY4LjExMiAxMTcuNzksNzIuNjExIEMxMTguMTYsNzMuMzM2IDExNy44NDUsNzQuMTI0IDExNi45OSw3NC42MTcgTDExMy45MDksNzYuMzk3IEMxMTMuODM2LDc2LjQzOCAxMTMuNzU2LDc2LjQ1OSAxMTMuNjc1LDc2LjQ1OSIgaWQ9IkZpbGwtMjQiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTUzLjMxNiwyMS4yNzkgQzE1MC45MDMsMjEuMjc5IDE0OC40OTUsMjAuNzUxIDE0Ni42NjQsMTkuNjkzIEMxNDQuODQ2LDE4LjY0NCAxNDMuODQ0LDE3LjIzMiAxNDMuODQ0LDE1LjcxOCBDMTQzLjg0NCwxNC4xOTEgMTQ0Ljg2LDEyLjc2MyAxNDYuNzA1LDExLjY5OCBMMTU2LjE5OCw2LjA5MSBDMTU2LjMwOSw2LjAyNSAxNTYuNDUyLDYuMDYyIDE1Ni41MTgsNi4xNzMgQzE1Ni41ODMsNi4yODQgMTU2LjU0Nyw2LjQyNyAxNTYuNDM2LDYuNDkzIEwxNDYuOTQsMTIuMTAyIEMxNDUuMjQ0LDEzLjA4MSAxNDQuMzEyLDE0LjM2NSAxNDQuMzEyLDE1LjcxOCBDMTQ0LjMxMiwxNy4wNTggMTQ1LjIzLDE4LjMyNiAxNDYuODk3LDE5LjI4OSBDMTUwLjQ0NiwyMS4zMzggMTU2LjI0LDIxLjMyNyAxNTkuODExLDE5LjI2NSBMMTY5LjU1OSwxMy42MzcgQzE2OS42NywxMy41NzMgMTY5LjgxMywxMy42MTEgMTY5Ljg3OCwxMy43MjMgQzE2OS45NDMsMTMuODM0IDE2OS45MDQsMTMuOTc3IDE2OS43OTMsMTQuMDQyIEwxNjAuMDQ1LDE5LjY3IEMxNTguMTg3LDIwLjc0MiAxNTUuNzQ5LDIxLjI3OSAxNTMuMzE2LDIxLjI3OSIgaWQ9IkZpbGwtMjUiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjY3NSw3NS45OTIgTDY3Ljc2Miw0OS40ODQiIGlkPSJGaWxsLTI2IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTExMy42NzUsNzYuMzQyIEMxMTMuNjE1LDc2LjM0MiAxMTMuNTU1LDc2LjMyNyAxMTMuNSw3Ni4yOTUgTDY3LjU4Nyw0OS43ODcgQzY3LjQxOSw0OS42OSA2Ny4zNjIsNDkuNDc2IDY3LjQ1OSw0OS4zMDkgQzY3LjU1Niw0OS4xNDEgNjcuNzcsNDkuMDgzIDY3LjkzNyw0OS4xOCBMMTEzLjg1LDc1LjY4OCBDMTE0LjAxOCw3NS43ODUgMTE0LjA3NSw3NiAxMTMuOTc4LDc2LjE2NyBDMTEzLjkxNCw3Ni4yNzkgMTEzLjc5Niw3Ni4zNDIgMTEzLjY3NSw3Ni4zNDIiIGlkPSJGaWxsLTI3IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTY3Ljc2Miw0OS40ODQgTDY3Ljc2MiwxMDMuNDg1IEM2Ny43NjIsMTA0LjU3NSA2OC41MzIsMTA1LjkwMyA2OS40ODIsMTA2LjQ1MiBMMTExLjk1NSwxMzAuOTczIEMxMTIuOTA1LDEzMS41MjIgMTEzLjY3NSwxMzEuMDgzIDExMy42NzUsMTI5Ljk5MyBMMTEzLjY3NSw3NS45OTIiIGlkPSJGaWxsLTI4IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTExMi43MjcsMTMxLjU2MSBDMTEyLjQzLDEzMS41NjEgMTEyLjEwNywxMzEuNDY2IDExMS43OCwxMzEuMjc2IEw2OS4zMDcsMTA2Ljc1NSBDNjguMjQ0LDEwNi4xNDIgNjcuNDEyLDEwNC43MDUgNjcuNDEyLDEwMy40ODUgTDY3LjQxMiw0OS40ODQgQzY3LjQxMiw0OS4yOSA2Ny41NjksNDkuMTM0IDY3Ljc2Miw0OS4xMzQgQzY3Ljk1Niw0OS4xMzQgNjguMTEzLDQ5LjI5IDY4LjExMyw0OS40ODQgTDY4LjExMywxMDMuNDg1IEM2OC4xMTMsMTA0LjQ0NSA2OC44MiwxMDUuNjY1IDY5LjY1NywxMDYuMTQ4IEwxMTIuMTMsMTMwLjY3IEMxMTIuNDc0LDEzMC44NjggMTEyLjc5MSwxMzAuOTEzIDExMywxMzAuNzkyIEMxMTMuMjA2LDEzMC42NzMgMTEzLjMyNSwxMzAuMzgxIDExMy4zMjUsMTI5Ljk5MyBMMTEzLjMyNSw3NS45OTIgQzExMy4zMjUsNzUuNzk4IDExMy40ODIsNzUuNjQxIDExMy42NzUsNzUuNjQxIEMxMTMuODY5LDc1LjY0MSAxMTQuMDI1LDc1Ljc5OCAxMTQuMDI1LDc1Ljk5MiBMMTE0LjAyNSwxMjkuOTkzIEMxMTQuMDI1LDEzMC42NDggMTEzLjc4NiwxMzEuMTQ3IDExMy4zNSwxMzEuMzk5IEMxMTMuMTYyLDEzMS41MDcgMTEyLjk1MiwxMzEuNTYxIDExMi43MjcsMTMxLjU2MSIgaWQ9IkZpbGwtMjkiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEyLjg2LDQwLjUxMiBDMTEyLjg2LDQwLjUxMiAxMTIuODYsNDAuNTEyIDExMi44NTksNDAuNTEyIEMxMTAuNTQxLDQwLjUxMiAxMDguMzYsMzkuOTkgMTA2LjcxNywzOS4wNDEgQzEwNS4wMTIsMzguMDU3IDEwNC4wNzQsMzYuNzI2IDEwNC4wNzQsMzUuMjkyIEMxMDQuMDc0LDMzLjg0NyAxMDUuMDI2LDMyLjUwMSAxMDYuNzU0LDMxLjUwNCBMMTE4Ljc5NSwyNC41NTEgQzEyMC40NjMsMjMuNTg5IDEyMi42NjksMjMuMDU4IDEyNS4wMDcsMjMuMDU4IEMxMjcuMzI1LDIzLjA1OCAxMjkuNTA2LDIzLjU4MSAxMzEuMTUsMjQuNTMgQzEzMi44NTQsMjUuNTE0IDEzMy43OTMsMjYuODQ1IDEzMy43OTMsMjguMjc4IEMxMzMuNzkzLDI5LjcyNCAxMzIuODQxLDMxLjA2OSAxMzEuMTEzLDMyLjA2NyBMMTE5LjA3MSwzOS4wMTkgQzExNy40MDMsMzkuOTgyIDExNS4xOTcsNDAuNTEyIDExMi44Niw0MC41MTIgTDExMi44Niw0MC41MTIgWiBNMTI1LjAwNywyMy43NTkgQzEyMi43OSwyMy43NTkgMTIwLjcwOSwyNC4yNTYgMTE5LjE0NiwyNS4xNTggTDEwNy4xMDQsMzIuMTEgQzEwNS42MDIsMzIuOTc4IDEwNC43NzQsMzQuMTA4IDEwNC43NzQsMzUuMjkyIEMxMDQuNzc0LDM2LjQ2NSAxMDUuNTg5LDM3LjU4MSAxMDcuMDY3LDM4LjQzNCBDMTA4LjYwNSwzOS4zMjMgMTEwLjY2MywzOS44MTIgMTEyLjg1OSwzOS44MTIgTDExMi44NiwzOS44MTIgQzExNS4wNzYsMzkuODEyIDExNy4xNTgsMzkuMzE1IDExOC43MjEsMzguNDEzIEwxMzAuNzYyLDMxLjQ2IEMxMzIuMjY0LDMwLjU5MyAxMzMuMDkyLDI5LjQ2MyAxMzMuMDkyLDI4LjI3OCBDMTMzLjA5MiwyNy4xMDYgMTMyLjI3OCwyNS45OSAxMzAuOCwyNS4xMzYgQzEyOS4yNjEsMjQuMjQ4IDEyNy4yMDQsMjMuNzU5IDEyNS4wMDcsMjMuNzU5IEwxMjUuMDA3LDIzLjc1OSBaIiBpZD0iRmlsbC0zMCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNjUuNjMsMTYuMjE5IEwxNTkuODk2LDE5LjUzIEMxNTYuNzI5LDIxLjM1OCAxNTEuNjEsMjEuMzY3IDE0OC40NjMsMTkuNTUgQzE0NS4zMTYsMTcuNzMzIDE0NS4zMzIsMTQuNzc4IDE0OC40OTksMTIuOTQ5IEwxNTQuMjMzLDkuNjM5IEwxNjUuNjMsMTYuMjE5IiBpZD0iRmlsbC0zMSIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNTQuMjMzLDEwLjQ0OCBMMTY0LjIyOCwxNi4yMTkgTDE1OS41NDYsMTguOTIzIEMxNTguMTEyLDE5Ljc1IDE1Ni4xOTQsMjAuMjA2IDE1NC4xNDcsMjAuMjA2IEMxNTIuMTE4LDIwLjIwNiAxNTAuMjI0LDE5Ljc1NyAxNDguODE0LDE4Ljk0MyBDMTQ3LjUyNCwxOC4xOTkgMTQ2LjgxNCwxNy4yNDkgMTQ2LjgxNCwxNi4yNjkgQzE0Ni44MTQsMTUuMjc4IDE0Ny41MzcsMTQuMzE0IDE0OC44NSwxMy41NTYgTDE1NC4yMzMsMTAuNDQ4IE0xNTQuMjMzLDkuNjM5IEwxNDguNDk5LDEyLjk0OSBDMTQ1LjMzMiwxNC43NzggMTQ1LjMxNiwxNy43MzMgMTQ4LjQ2MywxOS41NSBDMTUwLjAzMSwyMC40NTUgMTUyLjA4NiwyMC45MDcgMTU0LjE0NywyMC45MDcgQzE1Ni4yMjQsMjAuOTA3IDE1OC4zMDYsMjAuNDQ3IDE1OS44OTYsMTkuNTMgTDE2NS42MywxNi4yMTkgTDE1NC4yMzMsOS42MzkiIGlkPSJGaWxsLTMyIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0NS40NDUsNzIuNjY3IEwxNDUuNDQ1LDcyLjY2NyBDMTQzLjY3Miw3Mi42NjcgMTQyLjIwNCw3MS44MTcgMTQxLjIwMiw3MC40MjIgQzE0MS4xMzUsNzAuMzMgMTQxLjE0NSw3MC4xNDcgMTQxLjIyNSw3MC4wNjYgQzE0MS4zMDUsNjkuOTg1IDE0MS40MzIsNjkuOTQ2IDE0MS41MjUsNzAuMDExIEMxNDIuMzA2LDcwLjU1OSAxNDMuMjMxLDcwLjgyMyAxNDQuMjc2LDcwLjgyMiBDMTQ1LjU5OCw3MC44MjIgMTQ3LjAzLDcwLjM3NiAxNDguNTMyLDY5LjUwOSBDMTUzLjg0Miw2Ni40NDMgMTU4LjE2Myw1OC45ODcgMTU4LjE2Myw1Mi44OTQgQzE1OC4xNjMsNTAuOTY3IDE1Ny43MjEsNDkuMzMyIDE1Ni44ODQsNDguMTY4IEMxNTYuODE4LDQ4LjA3NiAxNTYuODI4LDQ3Ljk0OCAxNTYuOTA4LDQ3Ljg2NyBDMTU2Ljk4OCw0Ny43ODYgMTU3LjExNCw0Ny43NzQgMTU3LjIwOCw0Ny44NCBDMTU4Ljg3OCw0OS4wMTIgMTU5Ljc5OCw1MS4yMiAxNTkuNzk4LDU0LjA1OSBDMTU5Ljc5OCw2MC4zMDEgMTU1LjM3Myw2OC4wNDYgMTQ5LjkzMyw3MS4xODYgQzE0OC4zNiw3Mi4wOTQgMTQ2Ljg1LDcyLjY2NyAxNDUuNDQ1LDcyLjY2NyBMMTQ1LjQ0NSw3Mi42NjcgWiBNMTQyLjQ3Niw3MSBDMTQzLjI5LDcxLjY1MSAxNDQuMjk2LDcyLjAwMiAxNDUuNDQ1LDcyLjAwMiBDMTQ2Ljc2Nyw3Mi4wMDIgMTQ4LjE5OCw3MS41NSAxNDkuNyw3MC42ODIgQzE1NS4wMSw2Ny42MTcgMTU5LjMzMSw2MC4xNTkgMTU5LjMzMSw1NC4wNjUgQzE1OS4zMzEsNTIuMDg1IDE1OC44NjgsNTAuNDM1IDE1OC4wMDYsNDkuMjcyIEMxNTguNDE3LDUwLjMwNyAxNTguNjMsNTEuNTMyIDE1OC42Myw1Mi44OTIgQzE1OC42Myw1OS4xMzQgMTU0LjIwNSw2Ni43NjcgMTQ4Ljc2NSw2OS45MDcgQzE0Ny4xOTIsNzAuODE2IDE0NS42ODEsNzEuMjgzIDE0NC4yNzYsNzEuMjgzIEMxNDMuNjM0LDcxLjI4MyAxNDMuMDMzLDcxLjE5MiAxNDIuNDc2LDcxIEwxNDIuNDc2LDcxIFoiIGlkPSJGaWxsLTMzIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0OC42NDgsNjkuNzA0IEMxNTQuMDMyLDY2LjU5NiAxNTguMzk2LDU5LjA2OCAxNTguMzk2LDUyLjg5MSBDMTU4LjM5Niw1MC44MzkgMTU3LjkxMyw0OS4xOTggMTU3LjA3NCw0OC4wMyBDMTU1LjI4OSw0Ni43NzggMTUyLjY5OSw0Ni44MzYgMTQ5LjgxNiw0OC41MDEgQzE0NC40MzMsNTEuNjA5IDE0MC4wNjgsNTkuMTM3IDE0MC4wNjgsNjUuMzE0IEMxNDAuMDY4LDY3LjM2NSAxNDAuNTUyLDY5LjAwNiAxNDEuMzkxLDcwLjE3NCBDMTQzLjE3Niw3MS40MjcgMTQ1Ljc2NSw3MS4zNjkgMTQ4LjY0OCw2OS43MDQiIGlkPSJGaWxsLTM0IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0NC4yNzYsNzEuMjc2IEwxNDQuMjc2LDcxLjI3NiBDMTQzLjEzMyw3MS4yNzYgMTQyLjExOCw3MC45NjkgMTQxLjI1Nyw3MC4zNjUgQzE0MS4yMzYsNzAuMzUxIDE0MS4yMTcsNzAuMzMyIDE0MS4yMDIsNzAuMzExIEMxNDAuMzA3LDY5LjA2NyAxMzkuODM1LDY3LjMzOSAxMzkuODM1LDY1LjMxNCBDMTM5LjgzNSw1OS4wNzMgMTQ0LjI2LDUxLjQzOSAxNDkuNyw0OC4yOTggQzE1MS4yNzMsNDcuMzkgMTUyLjc4NCw0Ni45MjkgMTU0LjE4OSw0Ni45MjkgQzE1NS4zMzIsNDYuOTI5IDE1Ni4zNDcsNDcuMjM2IDE1Ny4yMDgsNDcuODM5IEMxNTcuMjI5LDQ3Ljg1NCAxNTcuMjQ4LDQ3Ljg3MyAxNTcuMjYzLDQ3Ljg5NCBDMTU4LjE1Nyw0OS4xMzggMTU4LjYzLDUwLjg2NSAxNTguNjMsNTIuODkxIEMxNTguNjMsNTkuMTMyIDE1NC4yMDUsNjYuNzY2IDE0OC43NjUsNjkuOTA3IEMxNDcuMTkyLDcwLjgxNSAxNDUuNjgxLDcxLjI3NiAxNDQuMjc2LDcxLjI3NiBMMTQ0LjI3Niw3MS4yNzYgWiBNMTQxLjU1OCw3MC4xMDQgQzE0Mi4zMzEsNzAuNjM3IDE0My4yNDUsNzEuMDA1IDE0NC4yNzYsNzEuMDA1IEMxNDUuNTk4LDcxLjAwNSAxNDcuMDMsNzAuNDY3IDE0OC41MzIsNjkuNiBDMTUzLjg0Miw2Ni41MzQgMTU4LjE2Myw1OS4wMzMgMTU4LjE2Myw1Mi45MzkgQzE1OC4xNjMsNTEuMDMxIDE1Ny43MjksNDkuMzg1IDE1Ni45MDcsNDguMjIzIEMxNTYuMTMzLDQ3LjY5MSAxNTUuMjE5LDQ3LjQwOSAxNTQuMTg5LDQ3LjQwOSBDMTUyLjg2Nyw0Ny40MDkgMTUxLjQzNSw0Ny44NDIgMTQ5LjkzMyw0OC43MDkgQzE0NC42MjMsNTEuNzc1IDE0MC4zMDIsNTkuMjczIDE0MC4zMDIsNjUuMzY2IEMxNDAuMzAyLDY3LjI3NiAxNDAuNzM2LDY4Ljk0MiAxNDEuNTU4LDcwLjEwNCBMMTQxLjU1OCw3MC4xMDQgWiIgaWQ9IkZpbGwtMzUiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTUwLjcyLDY1LjM2MSBMMTUwLjM1Nyw2NS4wNjYgQzE1MS4xNDcsNjQuMDkyIDE1MS44NjksNjMuMDQgMTUyLjUwNSw2MS45MzggQzE1My4zMTMsNjAuNTM5IDE1My45NzgsNTkuMDY3IDE1NC40ODIsNTcuNTYzIEwxNTQuOTI1LDU3LjcxMiBDMTU0LjQxMiw1OS4yNDUgMTUzLjczMyw2MC43NDUgMTUyLjkxLDYyLjE3MiBDMTUyLjI2Miw2My4yOTUgMTUxLjUyNSw2NC4zNjggMTUwLjcyLDY1LjM2MSIgaWQ9IkZpbGwtMzYiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTE1LjkxNyw4NC41MTQgTDExNS41NTQsODQuMjIgQzExNi4zNDQsODMuMjQ1IDExNy4wNjYsODIuMTk0IDExNy43MDIsODEuMDkyIEMxMTguNTEsNzkuNjkyIDExOS4xNzUsNzguMjIgMTE5LjY3OCw3Ni43MTcgTDEyMC4xMjEsNzYuODY1IEMxMTkuNjA4LDc4LjM5OCAxMTguOTMsNzkuODk5IDExOC4xMDYsODEuMzI2IEMxMTcuNDU4LDgyLjQ0OCAxMTYuNzIyLDgzLjUyMSAxMTUuOTE3LDg0LjUxNCIgaWQ9IkZpbGwtMzciIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTE0LDEzMC40NzYgTDExNCwxMzAuMDA4IEwxMTQsNzYuMDUyIEwxMTQsNzUuNTg0IEwxMTQsNzYuMDUyIEwxMTQsMTMwLjAwOCBMMTE0LDEzMC40NzYiIGlkPSJGaWxsLTM4IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgICAgICA8ZyBpZD0iSW1wb3J0ZWQtTGF5ZXJzLUNvcHkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDYyLjAwMDAwMCwgMC4wMDAwMDApIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTkuODIyLDM3LjQ3NCBDMTkuODM5LDM3LjMzOSAxOS43NDcsMzcuMTk0IDE5LjU1NSwzNy4wODIgQzE5LjIyOCwzNi44OTQgMTguNzI5LDM2Ljg3MiAxOC40NDYsMzcuMDM3IEwxMi40MzQsNDAuNTA4IEMxMi4zMDMsNDAuNTg0IDEyLjI0LDQwLjY4NiAxMi4yNDMsNDAuNzkzIEMxMi4yNDUsNDAuOTI1IDEyLjI0NSw0MS4yNTQgMTIuMjQ1LDQxLjM3MSBMMTIuMjQ1LDQxLjQxNCBMMTIuMjM4LDQxLjU0MiBDOC4xNDgsNDMuODg3IDUuNjQ3LDQ1LjMyMSA1LjY0Nyw0NS4zMjEgQzUuNjQ2LDQ1LjMyMSAzLjU3LDQ2LjM2NyAyLjg2LDUwLjUxMyBDMi44Niw1MC41MTMgMS45NDgsNTcuNDc0IDEuOTYyLDcwLjI1OCBDMS45NzcsODIuODI4IDIuNTY4LDg3LjMyOCAzLjEyOSw5MS42MDkgQzMuMzQ5LDkzLjI5MyA2LjEzLDkzLjczNCA2LjEzLDkzLjczNCBDNi40NjEsOTMuNzc0IDYuODI4LDkzLjcwNyA3LjIxLDkzLjQ4NiBMODIuNDgzLDQ5LjkzNSBDODQuMjkxLDQ4Ljg2NiA4NS4xNSw0Ni4yMTYgODUuNTM5LDQzLjY1MSBDODYuNzUyLDM1LjY2MSA4Ny4yMTQsMTAuNjczIDg1LjI2NCwzLjc3MyBDODUuMDY4LDMuMDggODQuNzU0LDIuNjkgODQuMzk2LDIuNDkxIEw4Mi4zMSwxLjcwMSBDODEuNTgzLDEuNzI5IDgwLjg5NCwyLjE2OCA4MC43NzYsMi4yMzYgQzgwLjYzNiwyLjMxNyA0MS44MDcsMjQuNTg1IDIwLjAzMiwzNy4wNzIgTDE5LjgyMiwzNy40NzQiIGlkPSJGaWxsLTEiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNODIuMzExLDEuNzAxIEw4NC4zOTYsMi40OTEgQzg0Ljc1NCwyLjY5IDg1LjA2OCwzLjA4IDg1LjI2NCwzLjc3MyBDODcuMjEzLDEwLjY3MyA4Ni43NTEsMzUuNjYgODUuNTM5LDQzLjY1MSBDODUuMTQ5LDQ2LjIxNiA4NC4yOSw0OC44NjYgODIuNDgzLDQ5LjkzNSBMNy4yMSw5My40ODYgQzYuODk3LDkzLjY2NyA2LjU5NSw5My43NDQgNi4zMTQsOTMuNzQ0IEw2LjEzMSw5My43MzMgQzYuMTMxLDkzLjczNCAzLjM0OSw5My4yOTMgMy4xMjgsOTEuNjA5IEMyLjU2OCw4Ny4zMjcgMS45NzcsODIuODI4IDEuOTYzLDcwLjI1OCBDMS45NDgsNTcuNDc0IDIuODYsNTAuNTEzIDIuODYsNTAuNTEzIEMzLjU3LDQ2LjM2NyA1LjY0Nyw0NS4zMjEgNS42NDcsNDUuMzIxIEM1LjY0Nyw0NS4zMjEgOC4xNDgsNDMuODg3IDEyLjIzOCw0MS41NDIgTDEyLjI0NSw0MS40MTQgTDEyLjI0NSw0MS4zNzEgQzEyLjI0NSw0MS4yNTQgMTIuMjQ1LDQwLjkyNSAxMi4yNDMsNDAuNzkzIEMxMi4yNCw0MC42ODYgMTIuMzAyLDQwLjU4MyAxMi40MzQsNDAuNTA4IEwxOC40NDYsMzcuMDM2IEMxOC41NzQsMzYuOTYyIDE4Ljc0NiwzNi45MjYgMTguOTI3LDM2LjkyNiBDMTkuMTQ1LDM2LjkyNiAxOS4zNzYsMzYuOTc5IDE5LjU1NCwzNy4wODIgQzE5Ljc0NywzNy4xOTQgMTkuODM5LDM3LjM0IDE5LjgyMiwzNy40NzQgTDIwLjAzMywzNy4wNzIgQzQxLjgwNiwyNC41ODUgODAuNjM2LDIuMzE4IDgwLjc3NywyLjIzNiBDODAuODk0LDIuMTY4IDgxLjU4MywxLjcyOSA4Mi4zMTEsMS43MDEgTTgyLjMxMSwwLjcwNCBMODIuMjcyLDAuNzA1IEM4MS42NTQsMC43MjggODAuOTg5LDAuOTQ5IDgwLjI5OCwxLjM2MSBMODAuMjc3LDEuMzczIEM4MC4xMjksMS40NTggNTkuNzY4LDEzLjEzNSAxOS43NTgsMzYuMDc5IEMxOS41LDM1Ljk4MSAxOS4yMTQsMzUuOTI5IDE4LjkyNywzNS45MjkgQzE4LjU2MiwzNS45MjkgMTguMjIzLDM2LjAxMyAxNy45NDcsMzYuMTczIEwxMS45MzUsMzkuNjQ0IEMxMS40OTMsMzkuODk5IDExLjIzNiw0MC4zMzQgMTEuMjQ2LDQwLjgxIEwxMS4yNDcsNDAuOTYgTDUuMTY3LDQ0LjQ0NyBDNC43OTQsNDQuNjQ2IDIuNjI1LDQ1Ljk3OCAxLjg3Nyw1MC4zNDUgTDEuODcxLDUwLjM4NCBDMS44NjIsNTAuNDU0IDAuOTUxLDU3LjU1NyAwLjk2NSw3MC4yNTkgQzAuOTc5LDgyLjg3OSAxLjU2OCw4Ny4zNzUgMi4xMzcsOTEuNzI0IEwyLjEzOSw5MS43MzkgQzIuNDQ3LDk0LjA5NCA1LjYxNCw5NC42NjIgNS45NzUsOTQuNzE5IEw2LjAwOSw5NC43MjMgQzYuMTEsOTQuNzM2IDYuMjEzLDk0Ljc0MiA2LjMxNCw5NC43NDIgQzYuNzksOTQuNzQyIDcuMjYsOTQuNjEgNy43MSw5NC4zNSBMODIuOTgzLDUwLjc5OCBDODQuNzk0LDQ5LjcyNyA4NS45ODIsNDcuMzc1IDg2LjUyNSw0My44MDEgQzg3LjcxMSwzNS45ODcgODguMjU5LDEwLjcwNSA4Ni4yMjQsMy41MDIgQzg1Ljk3MSwyLjYwOSA4NS41MiwxLjk3NSA4NC44ODEsMS42MiBMODQuNzQ5LDEuNTU4IEw4Mi42NjQsMC43NjkgQzgyLjU1MSwwLjcyNSA4Mi40MzEsMC43MDQgODIuMzExLDAuNzA0IiBpZD0iRmlsbC0yIiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTY2LjI2NywxMS41NjUgTDY3Ljc2MiwxMS45OTkgTDExLjQyMyw0NC4zMjUiIGlkPSJGaWxsLTMiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTIuMjAyLDkwLjU0NSBDMTIuMDI5LDkwLjU0NSAxMS44NjIsOTAuNDU1IDExLjc2OSw5MC4yOTUgQzExLjYzMiw5MC4wNTcgMTEuNzEzLDg5Ljc1MiAxMS45NTIsODkuNjE0IEwzMC4zODksNzguOTY5IEMzMC42MjgsNzguODMxIDMwLjkzMyw3OC45MTMgMzEuMDcxLDc5LjE1MiBDMzEuMjA4LDc5LjM5IDMxLjEyNyw3OS42OTYgMzAuODg4LDc5LjgzMyBMMTIuNDUxLDkwLjQ3OCBMMTIuMjAyLDkwLjU0NSIgaWQ9IkZpbGwtNCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMy43NjQsNDIuNjU0IEwxMy42NTYsNDIuNTkyIEwxMy43MDIsNDIuNDIxIEwxOC44MzcsMzkuNDU3IEwxOS4wMDcsMzkuNTAyIEwxOC45NjIsMzkuNjczIEwxMy44MjcsNDIuNjM3IEwxMy43NjQsNDIuNjU0IiBpZD0iRmlsbC01IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTguNTIsOTAuMzc1IEw4LjUyLDQ2LjQyMSBMOC41ODMsNDYuMzg1IEw3NS44NCw3LjU1NCBMNzUuODQsNTEuNTA4IEw3NS43NzgsNTEuNTQ0IEw4LjUyLDkwLjM3NSBMOC41Miw5MC4zNzUgWiBNOC43Nyw0Ni41NjQgTDguNzcsODkuOTQ0IEw3NS41OTEsNTEuMzY1IEw3NS41OTEsNy45ODUgTDguNzcsNDYuNTY0IEw4Ljc3LDQ2LjU2NCBaIiBpZD0iRmlsbC02IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTI0Ljk4Niw4My4xODIgQzI0Ljc1Niw4My4zMzEgMjQuMzc0LDgzLjU2NiAyNC4xMzcsODMuNzA1IEwxMi42MzIsOTAuNDA2IEMxMi4zOTUsOTAuNTQ1IDEyLjQyNiw5MC42NTggMTIuNyw5MC42NTggTDEzLjI2NSw5MC42NTggQzEzLjU0LDkwLjY1OCAxMy45NTgsOTAuNTQ1IDE0LjE5NSw5MC40MDYgTDI1LjcsODMuNzA1IEMyNS45MzcsODMuNTY2IDI2LjEyOCw4My40NTIgMjYuMTI1LDgzLjQ0OSBDMjYuMTIyLDgzLjQ0NyAyNi4xMTksODMuMjIgMjYuMTE5LDgyLjk0NiBDMjYuMTE5LDgyLjY3MiAyNS45MzEsODIuNTY5IDI1LjcwMSw4Mi43MTkgTDI0Ljk4Niw4My4xODIiIGlkPSJGaWxsLTciIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTMuMjY2LDkwLjc4MiBMMTIuNyw5MC43ODIgQzEyLjUsOTAuNzgyIDEyLjM4NCw5MC43MjYgMTIuMzU0LDkwLjYxNiBDMTIuMzI0LDkwLjUwNiAxMi4zOTcsOTAuMzk5IDEyLjU2OSw5MC4yOTkgTDI0LjA3NCw4My41OTcgQzI0LjMxLDgzLjQ1OSAyNC42ODksODMuMjI2IDI0LjkxOCw4My4wNzggTDI1LjYzMyw4Mi42MTQgQzI1LjcyMyw4Mi41NTUgMjUuODEzLDgyLjUyNSAyNS44OTksODIuNTI1IEMyNi4wNzEsODIuNTI1IDI2LjI0NCw4Mi42NTUgMjYuMjQ0LDgyLjk0NiBDMjYuMjQ0LDgzLjE2IDI2LjI0NSw4My4zMDkgMjYuMjQ3LDgzLjM4MyBMMjYuMjUzLDgzLjM4NyBMMjYuMjQ5LDgzLjQ1NiBDMjYuMjQ2LDgzLjUzMSAyNi4yNDYsODMuNTMxIDI1Ljc2Myw4My44MTIgTDE0LjI1OCw5MC41MTQgQzE0LDkwLjY2NSAxMy41NjQsOTAuNzgyIDEzLjI2Niw5MC43ODIgTDEzLjI2Niw5MC43ODIgWiBNMTIuNjY2LDkwLjUzMiBMMTIuNyw5MC41MzMgTDEzLjI2Niw5MC41MzMgQzEzLjUxOCw5MC41MzMgMTMuOTE1LDkwLjQyNSAxNC4xMzIsOTAuMjk5IEwyNS42MzcsODMuNTk3IEMyNS44MDUsODMuNDk5IDI1LjkzMSw4My40MjQgMjUuOTk4LDgzLjM4MyBDMjUuOTk0LDgzLjI5OSAyNS45OTQsODMuMTY1IDI1Ljk5NCw4Mi45NDYgTDI1Ljg5OSw4Mi43NzUgTDI1Ljc2OCw4Mi44MjQgTDI1LjA1NCw4My4yODcgQzI0LjgyMiw4My40MzcgMjQuNDM4LDgzLjY3MyAyNC4yLDgzLjgxMiBMMTIuNjk1LDkwLjUxNCBMMTIuNjY2LDkwLjUzMiBMMTIuNjY2LDkwLjUzMiBaIiBpZD0iRmlsbC04IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTEzLjI2Niw4OS44NzEgTDEyLjcsODkuODcxIEMxMi41LDg5Ljg3MSAxMi4zODQsODkuODE1IDEyLjM1NCw4OS43MDUgQzEyLjMyNCw4OS41OTUgMTIuMzk3LDg5LjQ4OCAxMi41NjksODkuMzg4IEwyNC4wNzQsODIuNjg2IEMyNC4zMzIsODIuNTM1IDI0Ljc2OCw4Mi40MTggMjUuMDY3LDgyLjQxOCBMMjUuNjMyLDgyLjQxOCBDMjUuODMyLDgyLjQxOCAyNS45NDgsODIuNDc0IDI1Ljk3OCw4Mi41ODQgQzI2LjAwOCw4Mi42OTQgMjUuOTM1LDgyLjgwMSAyNS43NjMsODIuOTAxIEwxNC4yNTgsODkuNjAzIEMxNCw4OS43NTQgMTMuNTY0LDg5Ljg3MSAxMy4yNjYsODkuODcxIEwxMy4yNjYsODkuODcxIFogTTEyLjY2Niw4OS42MjEgTDEyLjcsODkuNjIyIEwxMy4yNjYsODkuNjIyIEMxMy41MTgsODkuNjIyIDEzLjkxNSw4OS41MTUgMTQuMTMyLDg5LjM4OCBMMjUuNjM3LDgyLjY4NiBMMjUuNjY3LDgyLjY2OCBMMjUuNjMyLDgyLjY2NyBMMjUuMDY3LDgyLjY2NyBDMjQuODE1LDgyLjY2NyAyNC40MTgsODIuNzc1IDI0LjIsODIuOTAxIEwxMi42OTUsODkuNjAzIEwxMi42NjYsODkuNjIxIEwxMi42NjYsODkuNjIxIFoiIGlkPSJGaWxsLTkiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTIuMzcsOTAuODAxIEwxMi4zNyw4OS41NTQgTDEyLjM3LDkwLjgwMSIgaWQ9IkZpbGwtMTAiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNi4xMyw5My45MDEgQzUuMzc5LDkzLjgwOCA0LjgxNiw5My4xNjQgNC42OTEsOTIuNTI1IEMzLjg2LDg4LjI4NyAzLjU0LDgzLjc0MyAzLjUyNiw3MS4xNzMgQzMuNTExLDU4LjM4OSA0LjQyMyw1MS40MjggNC40MjMsNTEuNDI4IEM1LjEzNCw0Ny4yODIgNy4yMSw0Ni4yMzYgNy4yMSw0Ni4yMzYgQzcuMjEsNDYuMjM2IDgxLjY2NywzLjI1IDgyLjA2OSwzLjAxNyBDODIuMjkyLDIuODg4IDg0LjU1NiwxLjQzMyA4NS4yNjQsMy45NCBDODcuMjE0LDEwLjg0IDg2Ljc1MiwzNS44MjcgODUuNTM5LDQzLjgxOCBDODUuMTUsNDYuMzgzIDg0LjI5MSw0OS4wMzMgODIuNDgzLDUwLjEwMSBMNy4yMSw5My42NTMgQzYuODI4LDkzLjg3NCA2LjQ2MSw5My45NDEgNi4xMyw5My45MDEgQzYuMTMsOTMuOTAxIDMuMzQ5LDkzLjQ2IDMuMTI5LDkxLjc3NiBDMi41NjgsODcuNDk1IDEuOTc3LDgyLjk5NSAxLjk2Miw3MC40MjUgQzEuOTQ4LDU3LjY0MSAyLjg2LDUwLjY4IDIuODYsNTAuNjggQzMuNTcsNDYuNTM0IDUuNjQ3LDQ1LjQ4OSA1LjY0Nyw0NS40ODkgQzUuNjQ2LDQ1LjQ4OSA4LjA2NSw0NC4wOTIgMTIuMjQ1LDQxLjY3OSBMMTMuMTE2LDQxLjU2IEwxOS43MTUsMzcuNzMgTDE5Ljc2MSwzNy4yNjkgTDYuMTMsOTMuOTAxIiBpZD0iRmlsbC0xMSIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik02LjMxNyw5NC4xNjEgTDYuMTAyLDk0LjE0OCBMNi4xMDEsOTQuMTQ4IEw1Ljg1Nyw5NC4xMDEgQzUuMTM4LDkzLjk0NSAzLjA4NSw5My4zNjUgMi44ODEsOTEuODA5IEMyLjMxMyw4Ny40NjkgMS43MjcsODIuOTk2IDEuNzEzLDcwLjQyNSBDMS42OTksNTcuNzcxIDIuNjA0LDUwLjcxOCAyLjYxMyw1MC42NDggQzMuMzM4LDQ2LjQxNyA1LjQ0NSw0NS4zMSA1LjUzNSw0NS4yNjYgTDEyLjE2Myw0MS40MzkgTDEzLjAzMyw0MS4zMiBMMTkuNDc5LDM3LjU3OCBMMTkuNTEzLDM3LjI0NCBDMTkuNTI2LDM3LjEwNyAxOS42NDcsMzcuMDA4IDE5Ljc4NiwzNy4wMjEgQzE5LjkyMiwzNy4wMzQgMjAuMDIzLDM3LjE1NiAyMC4wMDksMzcuMjkzIEwxOS45NSwzNy44ODIgTDEzLjE5OCw0MS44MDEgTDEyLjMyOCw0MS45MTkgTDUuNzcyLDQ1LjcwNCBDNS43NDEsNDUuNzIgMy43ODIsNDYuNzcyIDMuMTA2LDUwLjcyMiBDMy4wOTksNTAuNzgyIDIuMTk4LDU3LjgwOCAyLjIxMiw3MC40MjQgQzIuMjI2LDgyLjk2MyAyLjgwOSw4Ny40MiAzLjM3Myw5MS43MjkgQzMuNDY0LDkyLjQyIDQuMDYyLDkyLjg4MyA0LjY4Miw5My4xODEgQzQuNTY2LDkyLjk4NCA0LjQ4Niw5Mi43NzYgNC40NDYsOTIuNTcyIEMzLjY2NSw4OC41ODggMy4yOTEsODQuMzcgMy4yNzYsNzEuMTczIEMzLjI2Miw1OC41MiA0LjE2Nyw1MS40NjYgNC4xNzYsNTEuMzk2IEM0LjkwMSw0Ny4xNjUgNy4wMDgsNDYuMDU5IDcuMDk4LDQ2LjAxNCBDNy4wOTQsNDYuMDE1IDgxLjU0MiwzLjAzNCA4MS45NDQsMi44MDIgTDgxLjk3MiwyLjc4NSBDODIuODc2LDIuMjQ3IDgzLjY5MiwyLjA5NyA4NC4zMzIsMi4zNTIgQzg0Ljg4NywyLjU3MyA4NS4yODEsMy4wODUgODUuNTA0LDMuODcyIEM4Ny41MTgsMTEgODYuOTY0LDM2LjA5MSA4NS43ODUsNDMuODU1IEM4NS4yNzgsNDcuMTk2IDg0LjIxLDQ5LjM3IDgyLjYxLDUwLjMxNyBMNy4zMzUsOTMuODY5IEM2Ljk5OSw5NC4wNjMgNi42NTgsOTQuMTYxIDYuMzE3LDk0LjE2MSBMNi4zMTcsOTQuMTYxIFogTTYuMTcsOTMuNjU0IEM2LjQ2Myw5My42OSA2Ljc3NCw5My42MTcgNy4wODUsOTMuNDM3IEw4Mi4zNTgsNDkuODg2IEM4NC4xODEsNDguODA4IDg0Ljk2LDQ1Ljk3MSA4NS4yOTIsNDMuNzggQzg2LjQ2NiwzNi4wNDkgODcuMDIzLDExLjA4NSA4NS4wMjQsNC4wMDggQzg0Ljg0NiwzLjM3NyA4NC41NTEsMi45NzYgODQuMTQ4LDIuODE2IEM4My42NjQsMi42MjMgODIuOTgyLDIuNzY0IDgyLjIyNywzLjIxMyBMODIuMTkzLDMuMjM0IEM4MS43OTEsMy40NjYgNy4zMzUsNDYuNDUyIDcuMzM1LDQ2LjQ1MiBDNy4zMDQsNDYuNDY5IDUuMzQ2LDQ3LjUyMSA0LjY2OSw1MS40NzEgQzQuNjYyLDUxLjUzIDMuNzYxLDU4LjU1NiAzLjc3NSw3MS4xNzMgQzMuNzksODQuMzI4IDQuMTYxLDg4LjUyNCA0LjkzNiw5Mi40NzYgQzUuMDI2LDkyLjkzNyA1LjQxMiw5My40NTkgNS45NzMsOTMuNjE1IEM2LjA4Nyw5My42NCA2LjE1OCw5My42NTIgNi4xNjksOTMuNjU0IEw2LjE3LDkzLjY1NCBMNi4xNyw5My42NTQgWiIgaWQ9IkZpbGwtMTIiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNy4zMTcsNjguOTgyIEM3LjgwNiw2OC43MDEgOC4yMDIsNjguOTI2IDguMjAyLDY5LjQ4NyBDOC4yMDIsNzAuMDQ3IDcuODA2LDcwLjczIDcuMzE3LDcxLjAxMiBDNi44MjksNzEuMjk0IDYuNDMzLDcxLjA2OSA2LjQzMyw3MC41MDggQzYuNDMzLDY5Ljk0OCA2LjgyOSw2OS4yNjUgNy4zMTcsNjguOTgyIiBpZD0iRmlsbC0xMyIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik02LjkyLDcxLjEzMyBDNi42MzEsNzEuMTMzIDYuNDMzLDcwLjkwNSA2LjQzMyw3MC41MDggQzYuNDMzLDY5Ljk0OCA2LjgyOSw2OS4yNjUgNy4zMTcsNjguOTgyIEM3LjQ2LDY4LjkgNy41OTUsNjguODYxIDcuNzE0LDY4Ljg2MSBDOC4wMDMsNjguODYxIDguMjAyLDY5LjA5IDguMjAyLDY5LjQ4NyBDOC4yMDIsNzAuMDQ3IDcuODA2LDcwLjczIDcuMzE3LDcxLjAxMiBDNy4xNzQsNzEuMDk0IDcuMDM5LDcxLjEzMyA2LjkyLDcxLjEzMyBNNy43MTQsNjguNjc0IEM3LjU1Nyw2OC42NzQgNy4zOTIsNjguNzIzIDcuMjI0LDY4LjgyMSBDNi42NzYsNjkuMTM4IDYuMjQ2LDY5Ljg3OSA2LjI0Niw3MC41MDggQzYuMjQ2LDcwLjk5NCA2LjUxNyw3MS4zMiA2LjkyLDcxLjMyIEM3LjA3OCw3MS4zMiA3LjI0Myw3MS4yNzEgNy40MTEsNzEuMTc0IEM3Ljk1OSw3MC44NTcgOC4zODksNzAuMTE3IDguMzg5LDY5LjQ4NyBDOC4zODksNjkuMDAxIDguMTE3LDY4LjY3NCA3LjcxNCw2OC42NzQiIGlkPSJGaWxsLTE0IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTYuOTIsNzAuOTQ3IEM2LjY0OSw3MC45NDcgNi42MjEsNzAuNjQgNi42MjEsNzAuNTA4IEM2LjYyMSw3MC4wMTcgNi45ODIsNjkuMzkyIDcuNDExLDY5LjE0NSBDNy41MjEsNjkuMDgyIDcuNjI1LDY5LjA0OSA3LjcxNCw2OS4wNDkgQzcuOTg2LDY5LjA0OSA4LjAxNSw2OS4zNTUgOC4wMTUsNjkuNDg3IEM4LjAxNSw2OS45NzggNy42NTIsNzAuNjAzIDcuMjI0LDcwLjg1MSBDNy4xMTUsNzAuOTE0IDcuMDEsNzAuOTQ3IDYuOTIsNzAuOTQ3IE03LjcxNCw2OC44NjEgQzcuNTk1LDY4Ljg2MSA3LjQ2LDY4LjkgNy4zMTcsNjguOTgyIEM2LjgyOSw2OS4yNjUgNi40MzMsNjkuOTQ4IDYuNDMzLDcwLjUwOCBDNi40MzMsNzAuOTA1IDYuNjMxLDcxLjEzMyA2LjkyLDcxLjEzMyBDNy4wMzksNzEuMTMzIDcuMTc0LDcxLjA5NCA3LjMxNyw3MS4wMTIgQzcuODA2LDcwLjczIDguMjAyLDcwLjA0NyA4LjIwMiw2OS40ODcgQzguMjAyLDY5LjA5IDguMDAzLDY4Ljg2MSA3LjcxNCw2OC44NjEiIGlkPSJGaWxsLTE1IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTcuNDQ0LDg1LjM1IEM3LjcwOCw4NS4xOTggNy45MjEsODUuMzE5IDcuOTIxLDg1LjYyMiBDNy45MjEsODUuOTI1IDcuNzA4LDg2LjI5MiA3LjQ0NCw4Ni40NDQgQzcuMTgxLDg2LjU5NyA2Ljk2Nyw4Ni40NzUgNi45NjcsODYuMTczIEM2Ljk2Nyw4NS44NzEgNy4xODEsODUuNTAyIDcuNDQ0LDg1LjM1IiBpZD0iRmlsbC0xNiIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik03LjIzLDg2LjUxIEM3LjA3NCw4Ni41MSA2Ljk2Nyw4Ni4zODcgNi45NjcsODYuMTczIEM2Ljk2Nyw4NS44NzEgNy4xODEsODUuNTAyIDcuNDQ0LDg1LjM1IEM3LjUyMSw4NS4zMDUgNy41OTQsODUuMjg0IDcuNjU4LDg1LjI4NCBDNy44MTQsODUuMjg0IDcuOTIxLDg1LjQwOCA3LjkyMSw4NS42MjIgQzcuOTIxLDg1LjkyNSA3LjcwOCw4Ni4yOTIgNy40NDQsODYuNDQ0IEM3LjM2Nyw4Ni40ODkgNy4yOTQsODYuNTEgNy4yMyw4Ni41MSBNNy42NTgsODUuMDk4IEM3LjU1OCw4NS4wOTggNy40NTUsODUuMTI3IDcuMzUxLDg1LjE4OCBDNy4wMzEsODUuMzczIDYuNzgxLDg1LjgwNiA2Ljc4MSw4Ni4xNzMgQzYuNzgxLDg2LjQ4MiA2Ljk2Niw4Ni42OTcgNy4yMyw4Ni42OTcgQzcuMzMsODYuNjk3IDcuNDMzLDg2LjY2NiA3LjUzOCw4Ni42MDcgQzcuODU4LDg2LjQyMiA4LjEwOCw4NS45ODkgOC4xMDgsODUuNjIyIEM4LjEwOCw4NS4zMTMgNy45MjMsODUuMDk4IDcuNjU4LDg1LjA5OCIgaWQ9IkZpbGwtMTciIGZpbGw9IiM4MDk3QTIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNy4yMyw4Ni4zMjIgTDcuMTU0LDg2LjE3MyBDNy4xNTQsODUuOTM4IDcuMzMzLDg1LjYyOSA3LjUzOCw4NS41MTIgTDcuNjU4LDg1LjQ3MSBMNy43MzQsODUuNjIyIEM3LjczNCw4NS44NTYgNy41NTUsODYuMTY0IDcuMzUxLDg2LjI4MiBMNy4yMyw4Ni4zMjIgTTcuNjU4LDg1LjI4NCBDNy41OTQsODUuMjg0IDcuNTIxLDg1LjMwNSA3LjQ0NCw4NS4zNSBDNy4xODEsODUuNTAyIDYuOTY3LDg1Ljg3MSA2Ljk2Nyw4Ni4xNzMgQzYuOTY3LDg2LjM4NyA3LjA3NCw4Ni41MSA3LjIzLDg2LjUxIEM3LjI5NCw4Ni41MSA3LjM2Nyw4Ni40ODkgNy40NDQsODYuNDQ0IEM3LjcwOCw4Ni4yOTIgNy45MjEsODUuOTI1IDcuOTIxLDg1LjYyMiBDNy45MjEsODUuNDA4IDcuODE0LDg1LjI4NCA3LjY1OCw4NS4yODQiIGlkPSJGaWxsLTE4IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTc3LjI3OCw3Ljc2OSBMNzcuMjc4LDUxLjQzNiBMMTAuMjA4LDkwLjE2IEwxMC4yMDgsNDYuNDkzIEw3Ny4yNzgsNy43NjkiIGlkPSJGaWxsLTE5IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTEwLjA4Myw5MC4zNzUgTDEwLjA4Myw0Ni40MjEgTDEwLjE0Niw0Ni4zODUgTDc3LjQwMyw3LjU1NCBMNzcuNDAzLDUxLjUwOCBMNzcuMzQxLDUxLjU0NCBMMTAuMDgzLDkwLjM3NSBMMTAuMDgzLDkwLjM3NSBaIE0xMC4zMzMsNDYuNTY0IEwxMC4zMzMsODkuOTQ0IEw3Ny4xNTQsNTEuMzY1IEw3Ny4xNTQsNy45ODUgTDEwLjMzMyw0Ni41NjQgTDEwLjMzMyw0Ni41NjQgWiIgaWQ9IkZpbGwtMjAiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgIDwvZz4KICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMjUuNzM3LDg4LjY0NyBMMTE4LjA5OCw5MS45ODEgTDExOC4wOTgsODQgTDEwNi42MzksODguNzEzIEwxMDYuNjM5LDk2Ljk4MiBMOTksMTAwLjMxNSBMMTEyLjM2OSwxMDMuOTYxIEwxMjUuNzM3LDg4LjY0NyIgaWQ9IkltcG9ydGVkLUxheWVycy1Db3B5LTIiIGZpbGw9IiM0NTVBNjQiIHNrZXRjaDp0eXBlPSJNU1NoYXBlR3JvdXAiPjwvcGF0aD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+';
+function RotateInstructions() {
+ this.loadIcon_();
+ var overlay = document.createElement('div');
+ var s = overlay.style;
+ s.position = 'fixed';
+ s.top = 0;
+ s.right = 0;
+ s.bottom = 0;
+ s.left = 0;
+ s.backgroundColor = 'gray';
+ s.fontFamily = 'sans-serif';
+ s.zIndex = 1000000;
+ var img = document.createElement('img');
+ img.src = this.icon;
+ var s = img.style;
+ s.marginLeft = '25%';
+ s.marginTop = '25%';
+ s.width = '50%';
+ overlay.appendChild(img);
+ var text = document.createElement('div');
+ var s = text.style;
+ s.textAlign = 'center';
+ s.fontSize = '16px';
+ s.lineHeight = '24px';
+ s.margin = '24px 25%';
+ s.width = '50%';
+ text.innerHTML = 'Place your phone into your Cardboard viewer.';
+ overlay.appendChild(text);
+ var snackbar = document.createElement('div');
+ var s = snackbar.style;
+ s.backgroundColor = '#CFD8DC';
+ s.position = 'fixed';
+ s.bottom = 0;
+ s.width = '100%';
+ s.height = '48px';
+ s.padding = '14px 24px';
+ s.boxSizing = 'border-box';
+ s.color = '#656A6B';
+ overlay.appendChild(snackbar);
+ var snackbarText = document.createElement('div');
+ snackbarText.style.float = 'left';
+ snackbarText.innerHTML = 'No Cardboard viewer?';
+ var snackbarButton = document.createElement('a');
+ snackbarButton.href = 'https://www.google.com/get/cardboard/get-cardboard/';
+ snackbarButton.innerHTML = 'get one';
+ snackbarButton.target = '_blank';
+ var s = snackbarButton.style;
+ s.float = 'right';
+ s.fontWeight = 600;
+ s.textTransform = 'uppercase';
+ s.borderLeft = '1px solid gray';
+ s.paddingLeft = '24px';
+ s.textDecoration = 'none';
+ s.color = '#656A6B';
+ snackbar.appendChild(snackbarText);
+ snackbar.appendChild(snackbarButton);
+ this.overlay = overlay;
+ this.text = text;
+ this.hide();
+}
+RotateInstructions.prototype.show = function (parent) {
+ if (!parent && !this.overlay.parentElement) {
+ document.body.appendChild(this.overlay);
+ } else if (parent) {
+ if (this.overlay.parentElement && this.overlay.parentElement != parent) this.overlay.parentElement.removeChild(this.overlay);
+ parent.appendChild(this.overlay);
+ }
+ this.overlay.style.display = 'block';
+ var img = this.overlay.querySelector('img');
+ var s = img.style;
+ if (isLandscapeMode()) {
+ s.width = '20%';
+ s.marginLeft = '40%';
+ s.marginTop = '3%';
+ } else {
+ s.width = '50%';
+ s.marginLeft = '25%';
+ s.marginTop = '25%';
+ }
+};
+RotateInstructions.prototype.hide = function () {
+ this.overlay.style.display = 'none';
+};
+RotateInstructions.prototype.showTemporarily = function (ms, parent) {
+ this.show(parent);
+ this.timer = setTimeout(this.hide.bind(this), ms);
+};
+RotateInstructions.prototype.disableShowTemporarily = function () {
+ clearTimeout(this.timer);
+};
+RotateInstructions.prototype.update = function () {
+ this.disableShowTemporarily();
+ if (!isLandscapeMode() && isMobile()) {
+ this.show();
+ } else {
+ this.hide();
+ }
+};
+RotateInstructions.prototype.loadIcon_ = function () {
+ this.icon = base64('image/svg+xml', rotateInstructionsAsset);
+};
+var DEFAULT_VIEWER = 'CardboardV1';
+var VIEWER_KEY = 'WEBVR_CARDBOARD_VIEWER';
+var CLASS_NAME = 'webvr-polyfill-viewer-selector';
+function ViewerSelector(defaultViewer) {
+ try {
+ this.selectedKey = localStorage.getItem(VIEWER_KEY);
+ } catch (error) {
+ console.error('Failed to load viewer profile: %s', error);
+ }
+ if (!this.selectedKey) {
+ this.selectedKey = defaultViewer || DEFAULT_VIEWER;
+ }
+ this.dialog = this.createDialog_(DeviceInfo.Viewers);
+ this.root = null;
+ this.onChangeCallbacks_ = [];
+}
+ViewerSelector.prototype.show = function (root) {
+ this.root = root;
+ root.appendChild(this.dialog);
+ var selected = this.dialog.querySelector('#' + this.selectedKey);
+ selected.checked = true;
+ this.dialog.style.display = 'block';
+};
+ViewerSelector.prototype.hide = function () {
+ if (this.root && this.root.contains(this.dialog)) {
+ this.root.removeChild(this.dialog);
+ }
+ this.dialog.style.display = 'none';
+};
+ViewerSelector.prototype.getCurrentViewer = function () {
+ return DeviceInfo.Viewers[this.selectedKey];
+};
+ViewerSelector.prototype.getSelectedKey_ = function () {
+ var input = this.dialog.querySelector('input[name=field]:checked');
+ if (input) {
+ return input.id;
+ }
+ return null;
+};
+ViewerSelector.prototype.onChange = function (cb) {
+ this.onChangeCallbacks_.push(cb);
+};
+ViewerSelector.prototype.fireOnChange_ = function (viewer) {
+ for (var i = 0; i < this.onChangeCallbacks_.length; i++) {
+ this.onChangeCallbacks_[i](viewer);
+ }
+};
+ViewerSelector.prototype.onSave_ = function () {
+ this.selectedKey = this.getSelectedKey_();
+ if (!this.selectedKey || !DeviceInfo.Viewers[this.selectedKey]) {
+ console.error('ViewerSelector.onSave_: this should never happen!');
+ return;
+ }
+ this.fireOnChange_(DeviceInfo.Viewers[this.selectedKey]);
+ try {
+ localStorage.setItem(VIEWER_KEY, this.selectedKey);
+ } catch (error) {
+ console.error('Failed to save viewer profile: %s', error);
+ }
+ this.hide();
+};
+ViewerSelector.prototype.createDialog_ = function (options) {
+ var container = document.createElement('div');
+ container.classList.add(CLASS_NAME);
+ container.style.display = 'none';
+ var overlay = document.createElement('div');
+ var s = overlay.style;
+ s.position = 'fixed';
+ s.left = 0;
+ s.top = 0;
+ s.width = '100%';
+ s.height = '100%';
+ s.background = 'rgba(0, 0, 0, 0.3)';
+ overlay.addEventListener('click', this.hide.bind(this));
+ var width = 280;
+ var dialog = document.createElement('div');
+ var s = dialog.style;
+ s.boxSizing = 'border-box';
+ s.position = 'fixed';
+ s.top = '24px';
+ s.left = '50%';
+ s.marginLeft = -width / 2 + 'px';
+ s.width = width + 'px';
+ s.padding = '24px';
+ s.overflow = 'hidden';
+ s.background = '#fafafa';
+ s.fontFamily = "'Roboto', sans-serif";
+ s.boxShadow = '0px 5px 20px #666';
+ dialog.appendChild(this.createH1_('Select your viewer'));
+ for (var id in options) {
+ dialog.appendChild(this.createChoice_(id, options[id].label));
+ }
+ dialog.appendChild(this.createButton_('Save', this.onSave_.bind(this)));
+ container.appendChild(overlay);
+ container.appendChild(dialog);
+ return container;
+};
+ViewerSelector.prototype.createH1_ = function (name) {
+ var h1 = document.createElement('h1');
+ var s = h1.style;
+ s.color = 'black';
+ s.fontSize = '20px';
+ s.fontWeight = 'bold';
+ s.marginTop = 0;
+ s.marginBottom = '24px';
+ h1.innerHTML = name;
+ return h1;
+};
+ViewerSelector.prototype.createChoice_ = function (id, name) {
+ var div = document.createElement('div');
+ div.style.marginTop = '8px';
+ div.style.color = 'black';
+ var input = document.createElement('input');
+ input.style.fontSize = '30px';
+ input.setAttribute('id', id);
+ input.setAttribute('type', 'radio');
+ input.setAttribute('value', id);
+ input.setAttribute('name', 'field');
+ var label = document.createElement('label');
+ label.style.marginLeft = '4px';
+ label.setAttribute('for', id);
+ label.innerHTML = name;
+ div.appendChild(input);
+ div.appendChild(label);
+ return div;
+};
+ViewerSelector.prototype.createButton_ = function (label, onclick) {
+ var button = document.createElement('button');
+ button.innerHTML = label;
+ var s = button.style;
+ s.float = 'right';
+ s.textTransform = 'uppercase';
+ s.color = '#1094f7';
+ s.fontSize = '14px';
+ s.letterSpacing = 0;
+ s.border = 0;
+ s.background = 'none';
+ s.marginTop = '16px';
+ button.addEventListener('click', onclick);
+ return button;
+};
+var commonjsGlobal$$1 = typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {};
+function unwrapExports$$1 (x) {
+ return x && x.__esModule ? x['default'] : x;
+}
+function createCommonjsModule$$1(fn, module) {
+ return module = { exports: {} }, fn(module, module.exports), module.exports;
+}
+var NoSleep = createCommonjsModule$$1(function (module, exports) {
+(function webpackUniversalModuleDefinition(root, factory) {
+ module.exports = factory();
+})(commonjsGlobal$$1, function() {
+return (function(modules) {
+ var installedModules = {};
+ function __webpack_require__(moduleId) {
+ if(installedModules[moduleId]) {
+ return installedModules[moduleId].exports;
+ }
+ var module = installedModules[moduleId] = {
+ i: moduleId,
+ l: false,
+ exports: {}
+ };
+ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+ module.l = true;
+ return module.exports;
+ }
+ __webpack_require__.m = modules;
+ __webpack_require__.c = installedModules;
+ __webpack_require__.d = function(exports, name, getter) {
+ if(!__webpack_require__.o(exports, name)) {
+ Object.defineProperty(exports, name, {
+ configurable: false,
+ enumerable: true,
+ get: getter
+ });
+ }
+ };
+ __webpack_require__.n = function(module) {
+ var getter = module && module.__esModule ?
+ function getDefault() { return module['default']; } :
+ function getModuleExports() { return module; };
+ __webpack_require__.d(getter, 'a', getter);
+ return getter;
+ };
+ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
+ __webpack_require__.p = "";
+ return __webpack_require__(__webpack_require__.s = 0);
+ })
+ ([
+ (function(module, exports, __webpack_require__) {
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+var mediaFile = __webpack_require__(1);
+var oldIOS = typeof navigator !== 'undefined' && parseFloat(('' + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ''])[1]).replace('undefined', '3_2').replace('_', '.').replace('_', '')) < 10 && !window.MSStream;
+var NoSleep = function () {
+ function NoSleep() {
+ _classCallCheck(this, NoSleep);
+ if (oldIOS) {
+ this.noSleepTimer = null;
+ } else {
+ this.noSleepVideo = document.createElement('video');
+ this.noSleepVideo.setAttribute('playsinline', '');
+ this.noSleepVideo.setAttribute('src', mediaFile);
+ this.noSleepVideo.addEventListener('timeupdate', function (e) {
+ if (this.noSleepVideo.currentTime > 0.5) {
+ this.noSleepVideo.currentTime = Math.random();
+ }
+ }.bind(this));
+ }
+ }
+ _createClass(NoSleep, [{
+ key: 'enable',
+ value: function enable() {
+ if (oldIOS) {
+ this.disable();
+ this.noSleepTimer = window.setInterval(function () {
+ window.location.href = '/';
+ window.setTimeout(window.stop, 0);
+ }, 15000);
+ } else {
+ this.noSleepVideo.play();
+ }
+ }
+ }, {
+ key: 'disable',
+ value: function disable() {
+ if (oldIOS) {
+ if (this.noSleepTimer) {
+ window.clearInterval(this.noSleepTimer);
+ this.noSleepTimer = null;
+ }
+ } else {
+ this.noSleepVideo.pause();
+ }
+ }
+ }]);
+ return NoSleep;
+}();
+module.exports = NoSleep;
+ }),
+ (function(module, exports, __webpack_require__) {
+module.exports = 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA=';
+ })
+ ]);
+});
+});
+var NoSleep$1 = unwrapExports$$1(NoSleep);
+var nextDisplayId = 1000;
+var defaultLeftBounds = [0, 0, 0.5, 1];
+var defaultRightBounds = [0.5, 0, 0.5, 1];
+var raf = window.requestAnimationFrame;
+var caf = window.cancelAnimationFrame;
+function VRFrameData() {
+ this.leftProjectionMatrix = new Float32Array(16);
+ this.leftViewMatrix = new Float32Array(16);
+ this.rightProjectionMatrix = new Float32Array(16);
+ this.rightViewMatrix = new Float32Array(16);
+ this.pose = null;
+}
+function VRDisplayCapabilities(config) {
+ Object.defineProperties(this, {
+ hasPosition: {
+ writable: false, enumerable: true, value: config.hasPosition
+ },
+ hasExternalDisplay: {
+ writable: false, enumerable: true, value: config.hasExternalDisplay
+ },
+ canPresent: {
+ writable: false, enumerable: true, value: config.canPresent
+ },
+ maxLayers: {
+ writable: false, enumerable: true, value: config.maxLayers
+ },
+ hasOrientation: {
+ enumerable: true, get: function get() {
+ deprecateWarning('VRDisplayCapabilities.prototype.hasOrientation', 'VRDisplay.prototype.getFrameData');
+ return config.hasOrientation;
+ }
+ }
+ });
+}
+function VRDisplay(config) {
+ config = config || {};
+ var USE_WAKELOCK = 'wakelock' in config ? config.wakelock : true;
+ this.isPolyfilled = true;
+ this.displayId = nextDisplayId++;
+ this.displayName = '';
+ this.depthNear = 0.01;
+ this.depthFar = 10000.0;
+ this.isPresenting = false;
+ Object.defineProperty(this, 'isConnected', {
+ get: function get() {
+ deprecateWarning('VRDisplay.prototype.isConnected', 'VRDisplayCapabilities.prototype.hasExternalDisplay');
+ return false;
+ }
+ });
+ this.capabilities = new VRDisplayCapabilities({
+ hasPosition: false,
+ hasOrientation: false,
+ hasExternalDisplay: false,
+ canPresent: false,
+ maxLayers: 1
+ });
+ this.stageParameters = null;
+ this.waitingForPresent_ = false;
+ this.layer_ = null;
+ this.originalParent_ = null;
+ this.fullscreenElement_ = null;
+ this.fullscreenWrapper_ = null;
+ this.fullscreenElementCachedStyle_ = null;
+ this.fullscreenEventTarget_ = null;
+ this.fullscreenChangeHandler_ = null;
+ this.fullscreenErrorHandler_ = null;
+ if (USE_WAKELOCK && isMobile()) {
+ this.wakelock_ = new NoSleep$1();
+ }
+}
+VRDisplay.prototype.getFrameData = function (frameData) {
+ return frameDataFromPose(frameData, this._getPose(), this);
+};
+VRDisplay.prototype.getPose = function () {
+ deprecateWarning('VRDisplay.prototype.getPose', 'VRDisplay.prototype.getFrameData');
+ return this._getPose();
+};
+VRDisplay.prototype.resetPose = function () {
+ deprecateWarning('VRDisplay.prototype.resetPose');
+ return this._resetPose();
+};
+VRDisplay.prototype.getImmediatePose = function () {
+ deprecateWarning('VRDisplay.prototype.getImmediatePose', 'VRDisplay.prototype.getFrameData');
+ return this._getPose();
+};
+VRDisplay.prototype.requestAnimationFrame = function (callback) {
+ return raf(callback);
+};
+VRDisplay.prototype.cancelAnimationFrame = function (id) {
+ return caf(id);
+};
+VRDisplay.prototype.wrapForFullscreen = function (element) {
+ if (isIOS()) {
+ return element;
+ }
+ if (!this.fullscreenWrapper_) {
+ this.fullscreenWrapper_ = document.createElement('div');
+ var cssProperties = ['height: ' + Math.min(screen.height, screen.width) + 'px !important', 'top: 0 !important', 'left: 0 !important', 'right: 0 !important', 'border: 0', 'margin: 0', 'padding: 0', 'z-index: 999999 !important', 'position: fixed'];
+ this.fullscreenWrapper_.setAttribute('style', cssProperties.join('; ') + ';');
+ this.fullscreenWrapper_.classList.add('webvr-polyfill-fullscreen-wrapper');
+ }
+ if (this.fullscreenElement_ == element) {
+ return this.fullscreenWrapper_;
+ }
+ if (this.fullscreenElement_) {
+ if (this.originalParent_) {
+ this.originalParent_.appendChild(this.fullscreenElement_);
+ } else {
+ this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_);
+ }
+ }
+ this.fullscreenElement_ = element;
+ this.originalParent_ = element.parentElement;
+ if (!this.originalParent_) {
+ document.body.appendChild(element);
+ }
+ if (!this.fullscreenWrapper_.parentElement) {
+ var parent = this.fullscreenElement_.parentElement;
+ parent.insertBefore(this.fullscreenWrapper_, this.fullscreenElement_);
+ parent.removeChild(this.fullscreenElement_);
+ }
+ this.fullscreenWrapper_.insertBefore(this.fullscreenElement_, this.fullscreenWrapper_.firstChild);
+ this.fullscreenElementCachedStyle_ = this.fullscreenElement_.getAttribute('style');
+ var self = this;
+ function applyFullscreenElementStyle() {
+ if (!self.fullscreenElement_) {
+ return;
+ }
+ var cssProperties = ['position: absolute', 'top: 0', 'left: 0', 'width: ' + Math.max(screen.width, screen.height) + 'px', 'height: ' + Math.min(screen.height, screen.width) + 'px', 'border: 0', 'margin: 0', 'padding: 0'];
+ self.fullscreenElement_.setAttribute('style', cssProperties.join('; ') + ';');
+ }
+ applyFullscreenElementStyle();
+ return this.fullscreenWrapper_;
+};
+VRDisplay.prototype.removeFullscreenWrapper = function () {
+ if (!this.fullscreenElement_) {
+ return;
+ }
+ var element = this.fullscreenElement_;
+ if (this.fullscreenElementCachedStyle_) {
+ element.setAttribute('style', this.fullscreenElementCachedStyle_);
+ } else {
+ element.removeAttribute('style');
+ }
+ this.fullscreenElement_ = null;
+ this.fullscreenElementCachedStyle_ = null;
+ var parent = this.fullscreenWrapper_.parentElement;
+ this.fullscreenWrapper_.removeChild(element);
+ if (this.originalParent_ === parent) {
+ parent.insertBefore(element, this.fullscreenWrapper_);
+ }
+ else if (this.originalParent_) {
+ this.originalParent_.appendChild(element);
+ }
+ parent.removeChild(this.fullscreenWrapper_);
+ return element;
+};
+VRDisplay.prototype.requestPresent = function (layers) {
+ var wasPresenting = this.isPresenting;
+ var self = this;
+ if (!(layers instanceof Array)) {
+ deprecateWarning('VRDisplay.prototype.requestPresent with non-array argument', 'an array of VRLayers as the first argument');
+ layers = [layers];
+ }
+ return new Promise(function (resolve, reject) {
+ if (!self.capabilities.canPresent) {
+ reject(new Error('VRDisplay is not capable of presenting.'));
+ return;
+ }
+ if (layers.length == 0 || layers.length > self.capabilities.maxLayers) {
+ reject(new Error('Invalid number of layers.'));
+ return;
+ }
+ var incomingLayer = layers[0];
+ if (!incomingLayer.source) {
+ resolve();
+ return;
+ }
+ var leftBounds = incomingLayer.leftBounds || defaultLeftBounds;
+ var rightBounds = incomingLayer.rightBounds || defaultRightBounds;
+ if (wasPresenting) {
+ var layer = self.layer_;
+ if (layer.source !== incomingLayer.source) {
+ layer.source = incomingLayer.source;
+ }
+ for (var i = 0; i < 4; i++) {
+ layer.leftBounds[i] = leftBounds[i];
+ layer.rightBounds[i] = rightBounds[i];
+ }
+ self.wrapForFullscreen(self.layer_.source);
+ self.updatePresent_();
+ resolve();
+ return;
+ }
+ self.layer_ = {
+ predistorted: incomingLayer.predistorted,
+ source: incomingLayer.source,
+ leftBounds: leftBounds.slice(0),
+ rightBounds: rightBounds.slice(0)
+ };
+ self.waitingForPresent_ = false;
+ if (self.layer_ && self.layer_.source) {
+ var fullscreenElement = self.wrapForFullscreen(self.layer_.source);
+ var onFullscreenChange = function onFullscreenChange() {
+ var actualFullscreenElement = getFullscreenElement();
+ self.isPresenting = fullscreenElement === actualFullscreenElement;
+ if (self.isPresenting) {
+ if (screen.orientation && screen.orientation.lock) {
+ screen.orientation.lock('landscape-primary').catch(function (error) {
+ console.error('screen.orientation.lock() failed due to', error.message);
+ });
+ }
+ self.waitingForPresent_ = false;
+ self.beginPresent_();
+ resolve();
+ } else {
+ if (screen.orientation && screen.orientation.unlock) {
+ screen.orientation.unlock();
+ }
+ self.removeFullscreenWrapper();
+ self.disableWakeLock();
+ self.endPresent_();
+ self.removeFullscreenListeners_();
+ }
+ self.fireVRDisplayPresentChange_();
+ };
+ var onFullscreenError = function onFullscreenError() {
+ if (!self.waitingForPresent_) {
+ return;
+ }
+ self.removeFullscreenWrapper();
+ self.removeFullscreenListeners_();
+ self.disableWakeLock();
+ self.waitingForPresent_ = false;
+ self.isPresenting = false;
+ reject(new Error('Unable to present.'));
+ };
+ self.addFullscreenListeners_(fullscreenElement, onFullscreenChange, onFullscreenError);
+ if (requestFullscreen(fullscreenElement)) {
+ self.enableWakeLock();
+ self.waitingForPresent_ = true;
+ } else if (isIOS() || isWebViewAndroid()) {
+ self.enableWakeLock();
+ self.isPresenting = true;
+ self.beginPresent_();
+ self.fireVRDisplayPresentChange_();
+ resolve();
+ }
+ }
+ if (!self.waitingForPresent_ && !isIOS()) {
+ exitFullscreen();
+ reject(new Error('Unable to present.'));
+ }
+ });
+};
+VRDisplay.prototype.exitPresent = function () {
+ var wasPresenting = this.isPresenting;
+ var self = this;
+ this.isPresenting = false;
+ this.layer_ = null;
+ this.disableWakeLock();
+ return new Promise(function (resolve, reject) {
+ if (wasPresenting) {
+ if (!exitFullscreen() && isIOS()) {
+ self.endPresent_();
+ self.fireVRDisplayPresentChange_();
+ }
+ if (isWebViewAndroid()) {
+ self.removeFullscreenWrapper();
+ self.removeFullscreenListeners_();
+ self.endPresent_();
+ self.fireVRDisplayPresentChange_();
+ }
+ resolve();
+ } else {
+ reject(new Error('Was not presenting to VRDisplay.'));
+ }
+ });
+};
+VRDisplay.prototype.getLayers = function () {
+ if (this.layer_) {
+ return [this.layer_];
+ }
+ return [];
+};
+VRDisplay.prototype.fireVRDisplayPresentChange_ = function () {
+ var event = new CustomEvent('vrdisplaypresentchange', { detail: { display: this } });
+ window.dispatchEvent(event);
+};
+VRDisplay.prototype.fireVRDisplayConnect_ = function () {
+ var event = new CustomEvent('vrdisplayconnect', { detail: { display: this } });
+ window.dispatchEvent(event);
+};
+VRDisplay.prototype.addFullscreenListeners_ = function (element, changeHandler, errorHandler) {
+ this.removeFullscreenListeners_();
+ this.fullscreenEventTarget_ = element;
+ this.fullscreenChangeHandler_ = changeHandler;
+ this.fullscreenErrorHandler_ = errorHandler;
+ if (changeHandler) {
+ if (document.fullscreenEnabled) {
+ element.addEventListener('fullscreenchange', changeHandler, false);
+ } else if (document.webkitFullscreenEnabled) {
+ element.addEventListener('webkitfullscreenchange', changeHandler, false);
+ } else if (document.mozFullScreenEnabled) {
+ document.addEventListener('mozfullscreenchange', changeHandler, false);
+ } else if (document.msFullscreenEnabled) {
+ element.addEventListener('msfullscreenchange', changeHandler, false);
+ }
+ }
+ if (errorHandler) {
+ if (document.fullscreenEnabled) {
+ element.addEventListener('fullscreenerror', errorHandler, false);
+ } else if (document.webkitFullscreenEnabled) {
+ element.addEventListener('webkitfullscreenerror', errorHandler, false);
+ } else if (document.mozFullScreenEnabled) {
+ document.addEventListener('mozfullscreenerror', errorHandler, false);
+ } else if (document.msFullscreenEnabled) {
+ element.addEventListener('msfullscreenerror', errorHandler, false);
+ }
+ }
+};
+VRDisplay.prototype.removeFullscreenListeners_ = function () {
+ if (!this.fullscreenEventTarget_) return;
+ var element = this.fullscreenEventTarget_;
+ if (this.fullscreenChangeHandler_) {
+ var changeHandler = this.fullscreenChangeHandler_;
+ element.removeEventListener('fullscreenchange', changeHandler, false);
+ element.removeEventListener('webkitfullscreenchange', changeHandler, false);
+ document.removeEventListener('mozfullscreenchange', changeHandler, false);
+ element.removeEventListener('msfullscreenchange', changeHandler, false);
+ }
+ if (this.fullscreenErrorHandler_) {
+ var errorHandler = this.fullscreenErrorHandler_;
+ element.removeEventListener('fullscreenerror', errorHandler, false);
+ element.removeEventListener('webkitfullscreenerror', errorHandler, false);
+ document.removeEventListener('mozfullscreenerror', errorHandler, false);
+ element.removeEventListener('msfullscreenerror', errorHandler, false);
+ }
+ this.fullscreenEventTarget_ = null;
+ this.fullscreenChangeHandler_ = null;
+ this.fullscreenErrorHandler_ = null;
+};
+VRDisplay.prototype.enableWakeLock = function () {
+ if (this.wakelock_) {
+ this.wakelock_.enable();
+ }
+};
+VRDisplay.prototype.disableWakeLock = function () {
+ if (this.wakelock_) {
+ this.wakelock_.disable();
+ }
+};
+VRDisplay.prototype.beginPresent_ = function () {
+};
+VRDisplay.prototype.endPresent_ = function () {
+};
+VRDisplay.prototype.submitFrame = function (pose) {
+};
+VRDisplay.prototype.getEyeParameters = function (whichEye) {
+ return null;
+};
+var config = {
+ ADDITIONAL_VIEWERS: [],
+ DEFAULT_VIEWER: '',
+ MOBILE_WAKE_LOCK: true,
+ DEBUG: false,
+ DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json',
+ K_FILTER: 0.98,
+ PREDICTION_TIME_S: 0.040,
+ CARDBOARD_UI_DISABLED: false,
+ ROTATE_INSTRUCTIONS_DISABLED: false,
+ YAW_ONLY: false,
+ BUFFER_SCALE: 0.5,
+ DIRTY_SUBMIT_FRAME_BINDINGS: false
+};
+var Eye = {
+ LEFT: 'left',
+ RIGHT: 'right'
+};
+function CardboardVRDisplay(config$$1) {
+ var defaults = extend({}, config);
+ config$$1 = extend(defaults, config$$1 || {});
+ VRDisplay.call(this, {
+ wakelock: config$$1.MOBILE_WAKE_LOCK
+ });
+ this.config = config$$1;
+ this.displayName = 'Cardboard VRDisplay';
+ this.capabilities = new VRDisplayCapabilities({
+ hasPosition: false,
+ hasOrientation: true,
+ hasExternalDisplay: false,
+ canPresent: true,
+ maxLayers: 1
+ });
+ this.stageParameters = null;
+ this.bufferScale_ = this.config.BUFFER_SCALE;
+ this.poseSensor_ = new PoseSensor(this.config);
+ this.distorter_ = null;
+ this.cardboardUI_ = null;
+ this.dpdb_ = new Dpdb(this.config.DPDB_URL, this.onDeviceParamsUpdated_.bind(this));
+ this.deviceInfo_ = new DeviceInfo(this.dpdb_.getDeviceParams(), config$$1.ADDITIONAL_VIEWERS);
+ this.viewerSelector_ = new ViewerSelector(config$$1.DEFAULT_VIEWER);
+ this.viewerSelector_.onChange(this.onViewerChanged_.bind(this));
+ this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer());
+ if (!this.config.ROTATE_INSTRUCTIONS_DISABLED) {
+ this.rotateInstructions_ = new RotateInstructions();
+ }
+ if (isIOS()) {
+ window.addEventListener('resize', this.onResize_.bind(this));
+ }
+}
+CardboardVRDisplay.prototype = Object.create(VRDisplay.prototype);
+CardboardVRDisplay.prototype._getPose = function () {
+ return {
+ position: null,
+ orientation: this.poseSensor_.getOrientation(),
+ linearVelocity: null,
+ linearAcceleration: null,
+ angularVelocity: null,
+ angularAcceleration: null
+ };
+};
+CardboardVRDisplay.prototype._resetPose = function () {
+ if (this.poseSensor_.resetPose) {
+ this.poseSensor_.resetPose();
+ }
+};
+CardboardVRDisplay.prototype._getFieldOfView = function (whichEye) {
+ var fieldOfView;
+ if (whichEye == Eye.LEFT) {
+ fieldOfView = this.deviceInfo_.getFieldOfViewLeftEye();
+ } else if (whichEye == Eye.RIGHT) {
+ fieldOfView = this.deviceInfo_.getFieldOfViewRightEye();
+ } else {
+ console.error('Invalid eye provided: %s', whichEye);
+ return null;
+ }
+ return fieldOfView;
+};
+CardboardVRDisplay.prototype._getEyeOffset = function (whichEye) {
+ var offset;
+ if (whichEye == Eye.LEFT) {
+ offset = [-this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];
+ } else if (whichEye == Eye.RIGHT) {
+ offset = [this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];
+ } else {
+ console.error('Invalid eye provided: %s', whichEye);
+ return null;
+ }
+ return offset;
+};
+CardboardVRDisplay.prototype.getEyeParameters = function (whichEye) {
+ var offset = this._getEyeOffset(whichEye);
+ var fieldOfView = this._getFieldOfView(whichEye);
+ var eyeParams = {
+ offset: offset,
+ renderWidth: this.deviceInfo_.device.width * 0.5 * this.bufferScale_,
+ renderHeight: this.deviceInfo_.device.height * this.bufferScale_
+ };
+ Object.defineProperty(eyeParams, 'fieldOfView', {
+ enumerable: true,
+ get: function get() {
+ deprecateWarning('VRFieldOfView', 'VRFrameData\'s projection matrices');
+ return fieldOfView;
+ }
+ });
+ return eyeParams;
+};
+CardboardVRDisplay.prototype.onDeviceParamsUpdated_ = function (newParams) {
+ if (this.config.DEBUG) {
+ console.log('DPDB reported that device params were updated.');
+ }
+ this.deviceInfo_.updateDeviceParams(newParams);
+ if (this.distorter_) {
+ this.distorter_.updateDeviceInfo(this.deviceInfo_);
+ }
+};
+CardboardVRDisplay.prototype.updateBounds_ = function () {
+ if (this.layer_ && this.distorter_ && (this.layer_.leftBounds || this.layer_.rightBounds)) {
+ this.distorter_.setTextureBounds(this.layer_.leftBounds, this.layer_.rightBounds);
+ }
+};
+CardboardVRDisplay.prototype.beginPresent_ = function () {
+ var gl = this.layer_.source.getContext('webgl');
+ if (!gl) gl = this.layer_.source.getContext('experimental-webgl');
+ if (!gl) gl = this.layer_.source.getContext('webgl2');
+ if (!gl) return;
+ if (this.layer_.predistorted) {
+ if (!this.config.CARDBOARD_UI_DISABLED) {
+ gl.canvas.width = getScreenWidth() * this.bufferScale_;
+ gl.canvas.height = getScreenHeight() * this.bufferScale_;
+ this.cardboardUI_ = new CardboardUI(gl);
+ }
+ } else {
+ if (!this.config.CARDBOARD_UI_DISABLED) {
+ this.cardboardUI_ = new CardboardUI(gl);
+ }
+ this.distorter_ = new CardboardDistorter(gl, this.cardboardUI_, this.config.BUFFER_SCALE, this.config.DIRTY_SUBMIT_FRAME_BINDINGS);
+ this.distorter_.updateDeviceInfo(this.deviceInfo_);
+ }
+ if (this.cardboardUI_) {
+ this.cardboardUI_.listen(function (e) {
+ this.viewerSelector_.show(this.layer_.source.parentElement);
+ e.stopPropagation();
+ e.preventDefault();
+ }.bind(this), function (e) {
+ this.exitPresent();
+ e.stopPropagation();
+ e.preventDefault();
+ }.bind(this));
+ }
+ if (this.rotateInstructions_) {
+ if (isLandscapeMode() && isMobile()) {
+ this.rotateInstructions_.showTemporarily(3000, this.layer_.source.parentElement);
+ } else {
+ this.rotateInstructions_.update();
+ }
+ }
+ this.orientationHandler = this.onOrientationChange_.bind(this);
+ window.addEventListener('orientationchange', this.orientationHandler);
+ this.vrdisplaypresentchangeHandler = this.updateBounds_.bind(this);
+ window.addEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);
+ this.fireVRDisplayDeviceParamsChange_();
+};
+CardboardVRDisplay.prototype.endPresent_ = function () {
+ if (this.distorter_) {
+ this.distorter_.destroy();
+ this.distorter_ = null;
+ }
+ if (this.cardboardUI_) {
+ this.cardboardUI_.destroy();
+ this.cardboardUI_ = null;
+ }
+ if (this.rotateInstructions_) {
+ this.rotateInstructions_.hide();
+ }
+ this.viewerSelector_.hide();
+ window.removeEventListener('orientationchange', this.orientationHandler);
+ window.removeEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);
+};
+CardboardVRDisplay.prototype.updatePresent_ = function () {
+ this.endPresent_();
+ this.beginPresent_();
+};
+CardboardVRDisplay.prototype.submitFrame = function (pose) {
+ if (this.distorter_) {
+ this.updateBounds_();
+ this.distorter_.submitFrame();
+ } else if (this.cardboardUI_ && this.layer_) {
+ var canvas = this.layer_.source.getContext('webgl').canvas;
+ if (canvas.width != this.lastWidth || canvas.height != this.lastHeight) {
+ this.cardboardUI_.onResize();
+ }
+ this.lastWidth = canvas.width;
+ this.lastHeight = canvas.height;
+ this.cardboardUI_.render();
+ }
+};
+CardboardVRDisplay.prototype.onOrientationChange_ = function (e) {
+ this.viewerSelector_.hide();
+ if (this.rotateInstructions_) {
+ this.rotateInstructions_.update();
+ }
+ this.onResize_();
+};
+CardboardVRDisplay.prototype.onResize_ = function (e) {
+ if (this.layer_) {
+ var gl = this.layer_.source.getContext('webgl');
+ var cssProperties = ['position: absolute', 'top: 0', 'left: 0',
+ 'width: 100vw', 'height: 100vh', 'border: 0', 'margin: 0',
+ 'padding: 0px', 'box-sizing: content-box'];
+ gl.canvas.setAttribute('style', cssProperties.join('; ') + ';');
+ safariCssSizeWorkaround(gl.canvas);
+ }
+};
+CardboardVRDisplay.prototype.onViewerChanged_ = function (viewer) {
+ this.deviceInfo_.setViewer(viewer);
+ if (this.distorter_) {
+ this.distorter_.updateDeviceInfo(this.deviceInfo_);
+ }
+ this.fireVRDisplayDeviceParamsChange_();
+};
+CardboardVRDisplay.prototype.fireVRDisplayDeviceParamsChange_ = function () {
+ var event = new CustomEvent('vrdisplaydeviceparamschange', {
+ detail: {
+ vrdisplay: this,
+ deviceInfo: this.deviceInfo_
+ }
+ });
+ window.dispatchEvent(event);
+};
+CardboardVRDisplay.VRFrameData = VRFrameData;
+CardboardVRDisplay.VRDisplay = VRDisplay;
+return CardboardVRDisplay;
+})));
+});
+var CardboardVRDisplay = unwrapExports(cardboardVrDisplay);
+
+var PolyfilledXRDevice = function (_EventTarget) {
+ inherits(PolyfilledXRDevice, _EventTarget);
+ function PolyfilledXRDevice(global) {
+ classCallCheck(this, PolyfilledXRDevice);
+ var _this = possibleConstructorReturn(this, (PolyfilledXRDevice.__proto__ || Object.getPrototypeOf(PolyfilledXRDevice)).call(this));
+ _this.global = global;
+ _this.onWindowResize = _this.onWindowResize.bind(_this);
+ _this.global.window.addEventListener('resize', _this.onWindowResize);
+ _this.environmentBlendMode = 'opaque';
+ return _this;
+ }
+ createClass(PolyfilledXRDevice, [{
+ key: 'onBaseLayerSet',
+ value: function onBaseLayerSet(sessionId, layer) {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'supportsSession',
+ value: function supportsSession() {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'requestSession',
+ value: function requestSession() {
+ return new Promise(function ($return, $error) {
+ return $error(new Error('Not implemented'));
+ }.bind(this));
+ }
+ }, {
+ key: 'requestAnimationFrame',
+ value: function requestAnimationFrame(callback) {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'onFrameStart',
+ value: function onFrameStart(sessionId) {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'onFrameEnd',
+ value: function onFrameEnd(sessionId) {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'requestStageBounds',
+ value: function requestStageBounds() {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'requestFrameOfReferenceTransform',
+ value: function requestFrameOfReferenceTransform(type, options) {
+ return new Promise(function ($return, $error) {
+ return $return(undefined);
+ }.bind(this));
+ }
+ }, {
+ key: 'cancelAnimationFrame',
+ value: function cancelAnimationFrame(handle) {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'endSession',
+ value: function endSession(sessionId) {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'getViewport',
+ value: function getViewport(sessionId, eye, layer, target) {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'getProjectionMatrix',
+ value: function getProjectionMatrix(eye) {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'getBasePoseMatrix',
+ value: function getBasePoseMatrix() {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'getBaseViewMatrix',
+ value: function getBaseViewMatrix(eye) {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'getInputSources',
+ value: function getInputSources() {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'getInputPose',
+ value: function getInputPose(inputSource, coordinateSystem) {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'onWindowResize',
+ value: function onWindowResize() {
+ this.onWindowResize();
+ }
+ }, {
+ key: 'depthNear',
+ get: function get$$1() {
+ throw new Error('Not implemented');
+ }
+ ,
+ set: function set$$1(val) {
+ throw new Error('Not implemented');
+ }
+ }, {
+ key: 'depthFar',
+ get: function get$$1() {
+ throw new Error('Not implemented');
+ }
+ ,
+ set: function set$$1(val) {
+ throw new Error('Not implemented');
+ }
+ }]);
+ return PolyfilledXRDevice;
+}(EventTarget);
+
+function create$2() {
+ var out = new ARRAY_TYPE(9);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+}
+
+function create$3() {
+ var out = new ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ return out;
+}
+function clone$3(a) {
+ var out = new ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+}
+
+function copy$3(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function normalize$1(out, a) {
+ var x = a[0];
+ var y = a[1];
+ var z = a[2];
+ var w = a[3];
+ var len = x * x + y * y + z * z + w * w;
+ if (len > 0) {
+ len = 1 / Math.sqrt(len);
+ out[0] = x * len;
+ out[1] = y * len;
+ out[2] = z * len;
+ out[3] = w * len;
+ }
+ return out;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var forEach$1 = function () {
+ var vec = create$3();
+ return function (a, stride, offset, count, fn, arg) {
+ var i = void 0,
+ l = void 0;
+ if (!stride) {
+ stride = 4;
+ }
+ if (!offset) {
+ offset = 0;
+ }
+ if (count) {
+ l = Math.min(count * stride + offset, a.length);
+ } else {
+ l = a.length;
+ }
+ for (i = offset; i < l; i += stride) {
+ vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2];vec[3] = a[i + 3];
+ fn(vec, vec, arg);
+ a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2];a[i + 3] = vec[3];
+ }
+ return a;
+ };
+}();
+
+function create$4() {
+ var out = new ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+}
+
+function setAxisAngle(out, axis, rad) {
+ rad = rad * 0.5;
+ var s = Math.sin(rad);
+ out[0] = s * axis[0];
+ out[1] = s * axis[1];
+ out[2] = s * axis[2];
+ out[3] = Math.cos(rad);
+ return out;
+}
+
+function multiply$4(out, a, b) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2],
+ aw = a[3];
+ var bx = b[0],
+ by = b[1],
+ bz = b[2],
+ bw = b[3];
+ out[0] = ax * bw + aw * bx + ay * bz - az * by;
+ out[1] = ay * bw + aw * by + az * bx - ax * bz;
+ out[2] = az * bw + aw * bz + ax * by - ay * bx;
+ out[3] = aw * bw - ax * bx - ay * by - az * bz;
+ return out;
+}
+
+
+
+
+function slerp(out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2],
+ aw = a[3];
+ var bx = b[0],
+ by = b[1],
+ bz = b[2],
+ bw = b[3];
+ var omega = void 0,
+ cosom = void 0,
+ sinom = void 0,
+ scale0 = void 0,
+ scale1 = void 0;
+ cosom = ax * bx + ay * by + az * bz + aw * bw;
+ if (cosom < 0.0) {
+ cosom = -cosom;
+ bx = -bx;
+ by = -by;
+ bz = -bz;
+ bw = -bw;
+ }
+ if (1.0 - cosom > 0.000001) {
+ omega = Math.acos(cosom);
+ sinom = Math.sin(omega);
+ scale0 = Math.sin((1.0 - t) * omega) / sinom;
+ scale1 = Math.sin(t * omega) / sinom;
+ } else {
+ scale0 = 1.0 - t;
+ scale1 = t;
+ }
+ out[0] = scale0 * ax + scale1 * bx;
+ out[1] = scale0 * ay + scale1 * by;
+ out[2] = scale0 * az + scale1 * bz;
+ out[3] = scale0 * aw + scale1 * bw;
+ return out;
+}
+function invert$2(out, a) {
+ var a0 = a[0],
+ a1 = a[1],
+ a2 = a[2],
+ a3 = a[3];
+ var dot$$1 = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
+ var invDot = dot$$1 ? 1.0 / dot$$1 : 0;
+ out[0] = -a0 * invDot;
+ out[1] = -a1 * invDot;
+ out[2] = -a2 * invDot;
+ out[3] = a3 * invDot;
+ return out;
+}
+
+function fromMat3(out, m) {
+ var fTrace = m[0] + m[4] + m[8];
+ var fRoot = void 0;
+ if (fTrace > 0.0) {
+ fRoot = Math.sqrt(fTrace + 1.0);
+ out[3] = 0.5 * fRoot;
+ fRoot = 0.5 / fRoot;
+ out[0] = (m[5] - m[7]) * fRoot;
+ out[1] = (m[6] - m[2]) * fRoot;
+ out[2] = (m[1] - m[3]) * fRoot;
+ } else {
+ var i = 0;
+ if (m[4] > m[0]) i = 1;
+ if (m[8] > m[i * 3 + i]) i = 2;
+ var j = (i + 1) % 3;
+ var k = (i + 2) % 3;
+ fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
+ out[i] = 0.5 * fRoot;
+ fRoot = 0.5 / fRoot;
+ out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
+ out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
+ out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
+ }
+ return out;
+}
+function fromEuler(out, x, y, z) {
+ var halfToRad = 0.5 * Math.PI / 180.0;
+ x *= halfToRad;
+ y *= halfToRad;
+ z *= halfToRad;
+ var sx = Math.sin(x);
+ var cx = Math.cos(x);
+ var sy = Math.sin(y);
+ var cy = Math.cos(y);
+ var sz = Math.sin(z);
+ var cz = Math.cos(z);
+ out[0] = sx * cy * cz - cx * sy * sz;
+ out[1] = cx * sy * cz + sx * cy * sz;
+ out[2] = cx * cy * sz - sx * sy * cz;
+ out[3] = cx * cy * cz + sx * sy * sz;
+ return out;
+}
+
+var clone$4 = clone$3;
+
+var copy$4 = copy$3;
+
+
+
+
+
+
+
+
+
+
+var normalize$2 = normalize$1;
+
+
+var rotationTo = function () {
+ var tmpvec3 = create$1();
+ var xUnitVec3 = fromValues$1(1, 0, 0);
+ var yUnitVec3 = fromValues$1(0, 1, 0);
+ return function (out, a, b) {
+ var dot$$1 = dot(a, b);
+ if (dot$$1 < -0.999999) {
+ cross(tmpvec3, xUnitVec3, a);
+ if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a);
+ normalize(tmpvec3, tmpvec3);
+ setAxisAngle(out, tmpvec3, Math.PI);
+ return out;
+ } else if (dot$$1 > 0.999999) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+ } else {
+ cross(tmpvec3, a, b);
+ out[0] = tmpvec3[0];
+ out[1] = tmpvec3[1];
+ out[2] = tmpvec3[2];
+ out[3] = 1 + dot$$1;
+ return normalize$2(out, out);
+ }
+ };
+}();
+var sqlerp = function () {
+ var temp1 = create$4();
+ var temp2 = create$4();
+ return function (out, a, b, c, d, t) {
+ slerp(temp1, a, d, t);
+ slerp(temp2, b, c, t);
+ slerp(out, temp1, temp2, 2 * t * (1 - t));
+ return out;
+ };
+}();
+var setAxes = function () {
+ var matr = create$2();
+ return function (out, view, right, up) {
+ matr[0] = right[0];
+ matr[3] = right[1];
+ matr[6] = right[2];
+ matr[1] = up[0];
+ matr[4] = up[1];
+ matr[7] = up[2];
+ matr[2] = -view[0];
+ matr[5] = -view[1];
+ matr[8] = -view[2];
+ return normalize$2(out, fromMat3(out, matr));
+ };
+}();
+
+var HEAD_ELBOW_OFFSET_RIGHTHANDED = fromValues$1(0.155, -0.465, -0.15);
+var HEAD_ELBOW_OFFSET_LEFTHANDED = fromValues$1(-0.155, -0.465, -0.15);
+var ELBOW_WRIST_OFFSET = fromValues$1(0, 0, -0.25);
+var WRIST_CONTROLLER_OFFSET = fromValues$1(0, 0, 0.05);
+var ARM_EXTENSION_OFFSET = fromValues$1(-0.08, 0.14, 0.08);
+var ELBOW_BEND_RATIO = 0.4;
+var EXTENSION_RATIO_WEIGHT = 0.4;
+var MIN_ANGULAR_SPEED = 0.61;
+var MIN_ANGLE_DELTA = 0.175;
+var MIN_EXTENSION_COS = 0.12;
+var MAX_EXTENSION_COS = 0.87;
+var RAD_TO_DEG = 180 / Math.PI;
+function eulerFromQuaternion(out, q, order) {
+ function clamp(value, min$$1, max$$1) {
+ return value < min$$1 ? min$$1 : value > max$$1 ? max$$1 : value;
+ }
+ var sqx = q[0] * q[0];
+ var sqy = q[1] * q[1];
+ var sqz = q[2] * q[2];
+ var sqw = q[3] * q[3];
+ if (order === 'XYZ') {
+ out[0] = Math.atan2(2 * (q[0] * q[3] - q[1] * q[2]), sqw - sqx - sqy + sqz);
+ out[1] = Math.asin(clamp(2 * (q[0] * q[2] + q[1] * q[3]), -1, 1));
+ out[2] = Math.atan2(2 * (q[2] * q[3] - q[0] * q[1]), sqw + sqx - sqy - sqz);
+ } else if (order === 'YXZ') {
+ out[0] = Math.asin(clamp(2 * (q[0] * q[3] - q[1] * q[2]), -1, 1));
+ out[1] = Math.atan2(2 * (q[0] * q[2] + q[1] * q[3]), sqw - sqx - sqy + sqz);
+ out[2] = Math.atan2(2 * (q[0] * q[1] + q[2] * q[3]), sqw - sqx + sqy - sqz);
+ } else if (order === 'ZXY') {
+ out[0] = Math.asin(clamp(2 * (q[0] * q[3] + q[1] * q[2]), -1, 1));
+ out[1] = Math.atan2(2 * (q[1] * q[3] - q[2] * q[0]), sqw - sqx - sqy + sqz);
+ out[2] = Math.atan2(2 * (q[2] * q[3] - q[0] * q[1]), sqw - sqx + sqy - sqz);
+ } else if (order === 'ZYX') {
+ out[0] = Math.atan2(2 * (q[0] * q[3] + q[2] * q[1]), sqw - sqx - sqy + sqz);
+ out[1] = Math.asin(clamp(2 * (q[1] * q[3] - q[0] * q[2]), -1, 1));
+ out[2] = Math.atan2(2 * (q[0] * q[1] + q[2] * q[3]), sqw + sqx - sqy - sqz);
+ } else if (order === 'YZX') {
+ out[0] = Math.atan2(2 * (q[0] * q[3] - q[2] * q[1]), sqw - sqx + sqy - sqz);
+ out[1] = Math.atan2(2 * (q[1] * q[3] - q[0] * q[2]), sqw + sqx - sqy - sqz);
+ out[2] = Math.asin(clamp(2 * (q[0] * q[1] + q[2] * q[3]), -1, 1));
+ } else if (order === 'XZY') {
+ out[0] = Math.atan2(2 * (q[0] * q[3] + q[1] * q[2]), sqw - sqx + sqy - sqz);
+ out[1] = Math.atan2(2 * (q[0] * q[2] + q[1] * q[3]), sqw + sqx - sqy - sqz);
+ out[2] = Math.asin(clamp(2 * (q[2] * q[3] - q[0] * q[1]), -1, 1));
+ } else {
+ console.log('No order given for quaternion to euler conversion.');
+ return;
+ }
+}
+var OrientationArmModel = function () {
+ function OrientationArmModel() {
+ classCallCheck(this, OrientationArmModel);
+ this.hand = 'right';
+ this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED;
+ this.controllerQ = create$4();
+ this.lastControllerQ = create$4();
+ this.headQ = create$4();
+ this.headPos = create$1();
+ this.elbowPos = create$1();
+ this.wristPos = create$1();
+ this.time = null;
+ this.lastTime = null;
+ this.rootQ = create$4();
+ this.position = create$1();
+ }
+ createClass(OrientationArmModel, [{
+ key: 'setHandedness',
+ value: function setHandedness(hand) {
+ if (this.hand != hand) {
+ this.hand = hand;
+ if (this.hand == 'left') {
+ this.headElbowOffset = HEAD_ELBOW_OFFSET_LEFTHANDED;
+ } else {
+ this.headElbowOffset = HEAD_ELBOW_OFFSET_RIGHTHANDED;
+ }
+ }
+ }
+ }, {
+ key: 'update',
+ value: function update(controllerOrientation, headPoseMatrix) {
+ this.time = now$1();
+ if (controllerOrientation) {
+ copy$4(this.lastControllerQ, this.controllerQ);
+ copy$4(this.controllerQ, controllerOrientation);
+ }
+ if (headPoseMatrix) {
+ getTranslation(this.headPos, headPoseMatrix);
+ getRotation(this.headQ, headPoseMatrix);
+ }
+ var headYawQ = this.getHeadYawOrientation_();
+ var angleDelta = this.quatAngle_(this.lastControllerQ, this.controllerQ);
+ var timeDelta = (this.time - this.lastTime) / 1000;
+ var controllerAngularSpeed = angleDelta / timeDelta;
+ if (controllerAngularSpeed > MIN_ANGULAR_SPEED) {
+ slerp(this.rootQ, this.rootQ, headYawQ, Math.min(angleDelta / MIN_ANGLE_DELTA, 1.0));
+ } else {
+ copy$4(this.rootQ, headYawQ);
+ }
+ var controllerForward = fromValues$1(0, 0, -1.0);
+ transformQuat(controllerForward, controllerForward, this.controllerQ);
+ var controllerDotY = dot(controllerForward, [0, 1, 0]);
+ var extensionRatio = this.clamp_((controllerDotY - MIN_EXTENSION_COS) / MAX_EXTENSION_COS, 0.0, 1.0);
+ var controllerCameraQ = clone$4(this.rootQ);
+ invert$2(controllerCameraQ, controllerCameraQ);
+ multiply$4(controllerCameraQ, controllerCameraQ, this.controllerQ);
+ var elbowPos = this.elbowPos;
+ copy$1(elbowPos, this.headPos);
+ add$1(elbowPos, elbowPos, this.headElbowOffset);
+ var elbowOffset = clone$1(ARM_EXTENSION_OFFSET);
+ scale$1(elbowOffset, elbowOffset, extensionRatio);
+ add$1(elbowPos, elbowPos, elbowOffset);
+ var totalAngle = this.quatAngle_(controllerCameraQ, create$4());
+ var totalAngleDeg = totalAngle * RAD_TO_DEG;
+ var lerpSuppression = 1 - Math.pow(totalAngleDeg / 180, 4);var elbowRatio = ELBOW_BEND_RATIO;
+ var wristRatio = 1 - ELBOW_BEND_RATIO;
+ var lerpValue = lerpSuppression * (elbowRatio + wristRatio * extensionRatio * EXTENSION_RATIO_WEIGHT);
+ var wristQ = create$4();
+ slerp(wristQ, wristQ, controllerCameraQ, lerpValue);
+ var invWristQ = invert$2(create$4(), wristQ);
+ var elbowQ = clone$4(controllerCameraQ);
+ multiply$4(elbowQ, elbowQ, invWristQ);
+ var wristPos = this.wristPos;
+ copy$1(wristPos, WRIST_CONTROLLER_OFFSET);
+ transformQuat(wristPos, wristPos, wristQ);
+ add$1(wristPos, wristPos, ELBOW_WRIST_OFFSET);
+ transformQuat(wristPos, wristPos, elbowQ);
+ add$1(wristPos, wristPos, elbowPos);
+ var offset = clone$1(ARM_EXTENSION_OFFSET);
+ scale$1(offset, offset, extensionRatio);
+ add$1(this.position, this.wristPos, offset);
+ transformQuat(this.position, this.position, this.rootQ);
+ this.lastTime = this.time;
+ }
+ }, {
+ key: 'getPosition',
+ value: function getPosition() {
+ return this.position;
+ }
+ }, {
+ key: 'getHeadYawOrientation_',
+ value: function getHeadYawOrientation_() {
+ var headEuler = create$1();
+ eulerFromQuaternion(headEuler, this.headQ, 'YXZ');
+ var destinationQ = fromEuler(create$4(), 0, headEuler[1] * RAD_TO_DEG, 0);
+ return destinationQ;
+ }
+ }, {
+ key: 'clamp_',
+ value: function clamp_(value, min$$1, max$$1) {
+ return Math.min(Math.max(value, min$$1), max$$1);
+ }
+ }, {
+ key: 'quatAngle_',
+ value: function quatAngle_(q1, q2) {
+ var vec1 = [0, 0, -1];
+ var vec2 = [0, 0, -1];
+ transformQuat(vec1, vec1, q1);
+ transformQuat(vec2, vec2, q2);
+ return angle(vec1, vec2);
+ }
+ }]);
+ return OrientationArmModel;
+}();
+
+var GamepadXRInputSource = function () {
+ function GamepadXRInputSource(polyfill) {
+ var primaryButtonIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
+ classCallCheck(this, GamepadXRInputSource);
+ this.polyfill = polyfill;
+ this.gamepad = null;
+ this.inputSource = new XRInputSource(this);
+ this.lastPosition = create$1();
+ this.emulatedPosition = false;
+ this.basePoseMatrix = create();
+ this.inputPoses = new WeakMap();
+ this.primaryButtonIndex = primaryButtonIndex;
+ this.primaryActionPressed = false;
+ this.handedness = '';
+ this.targetRayMode = 'gaze';
+ this.armModel = null;
+ }
+ createClass(GamepadXRInputSource, [{
+ key: 'updateFromGamepad',
+ value: function updateFromGamepad(gamepad) {
+ this.gamepad = gamepad;
+ this.handedness = gamepad.hand;
+ if (gamepad.pose) {
+ this.targetRayMode = 'tracked-pointer';
+ this.emulatedPosition = !gamepad.pose.hasPosition;
+ } else if (gamepad.hand === '') {
+ this.targetRayMode = 'gaze';
+ this.emulatedPosition = false;
+ }
+ }
+ }, {
+ key: 'updateBasePoseMatrix',
+ value: function updateBasePoseMatrix() {
+ if (this.gamepad && this.gamepad.pose) {
+ var pose = this.gamepad.pose;
+ var position = pose.position;
+ var orientation = pose.orientation;
+ if (!position && !orientation) {
+ return;
+ }
+ if (!position) {
+ if (!pose.hasPosition) {
+ if (!this.armModel) {
+ this.armModel = new OrientationArmModel();
+ }
+ this.armModel.setHandedness(this.gamepad.hand);
+ this.armModel.update(orientation, this.polyfill.getBasePoseMatrix());
+ position = this.armModel.getPosition();
+ } else {
+ position = this.lastPosition;
+ }
+ } else {
+ this.lastPosition[0] = position[0];
+ this.lastPosition[1] = position[1];
+ this.lastPosition[2] = position[2];
+ }
+ fromRotationTranslation(this.basePoseMatrix, orientation, position);
+ } else {
+ copy(this.basePoseMatrix, this.polyfill.getBasePoseMatrix());
+ }
+ return this.basePoseMatrix;
+ }
+ }, {
+ key: 'getXRInputPose',
+ value: function getXRInputPose(coordinateSystem) {
+ this.updateBasePoseMatrix();
+ var inputPose = this.inputPoses.get(coordinateSystem);
+ if (!inputPose) {
+ inputPose = new XRInputPose(this, this.gamepad && this.gamepad.pose);
+ this.inputPoses.set(coordinateSystem, inputPose);
+ }
+ var rayTransformMatrix = new Float32Array(16);
+ coordinateSystem.transformBasePoseMatrix(rayTransformMatrix, this.basePoseMatrix);
+ inputPose.targetRay = poseMatrixToXRRay(rayTransformMatrix);
+ if (inputPose.gripMatrix) {
+ coordinateSystem.transformBasePoseMatrix(inputPose.gripMatrix, this.basePoseMatrix);
+ }
+ return inputPose;
+ }
+ }]);
+ return GamepadXRInputSource;
+}();
+
+var EXTRA_PRESENTATION_ATTRIBUTES = {
+ highRefreshRate: true
+};
+var PRIMARY_BUTTON_MAP = {
+ oculus: 1,
+ openvr: 1
+};
+var CAN_USE_GAMEPAD = _global.navigator && 'getGamepads' in _global.navigator;
+var SESSION_ID = 0;
+var Session = function Session(sessionOptions) {
+ classCallCheck(this, Session);
+ this.outputContext = sessionOptions.outputContext;
+ this.immersive = sessionOptions.immersive;
+ this.ended = null;
+ this.baseLayer = null;
+ this.id = ++SESSION_ID;
+ this.modifiedCanvasLayer = false;
+};
+
+var WebVRDevice = function (_PolyfilledXRDevice) {
+ inherits(WebVRDevice, _PolyfilledXRDevice);
+ function WebVRDevice(global, display) {
+ classCallCheck(this, WebVRDevice);
+ var canPresent = display.capabilities.canPresent;
+ var _this = possibleConstructorReturn(this, (WebVRDevice.__proto__ || Object.getPrototypeOf(WebVRDevice)).call(this, global));
+ _this.display = display;
+ _this.frame = new global.VRFrameData();
+ _this.sessions = new Map();
+ _this.immersiveSession = null;
+ _this.canPresent = canPresent;
+ _this.baseModelMatrix = create();
+ _this.gamepadInputSources = {};
+ _this.tempVec3 = new Float32Array(3);
+ _this.onVRDisplayPresentChange = _this.onVRDisplayPresentChange.bind(_this);
+ global.window.addEventListener('vrdisplaypresentchange', _this.onVRDisplayPresentChange);
+ return _this;
+ }
+ createClass(WebVRDevice, [{
+ key: 'onBaseLayerSet',
+ value: function onBaseLayerSet(sessionId, layer) {
+ var _this2 = this;
+ var session = this.sessions.get(sessionId);
+ var canvas = layer.context.canvas;
+ if (session.immersive) {
+ var left = this.display.getEyeParameters('left');
+ var right = this.display.getEyeParameters('right');
+ canvas.width = Math.max(left.renderWidth, right.renderWidth) * 2;
+ canvas.height = Math.max(left.renderHeight, right.renderHeight);
+ this.display.requestPresent([{
+ source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES
+ }]).then(function () {
+ if ("production" !== 'test' && !_this2.global.document.body.contains(canvas)) {
+ session.modifiedCanvasLayer = true;
+ _this2.global.document.body.appendChild(canvas);
+ applyCanvasStylesForMinimalRendering(canvas);
+ }
+ session.baseLayer = layer;
+ });
+ }
+ else if (session.outputContext) {
+ session.baseLayer = layer;
+ }
+ }
+ }, {
+ key: 'supportsSession',
+ value: function supportsSession() {
+ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+ if (options.immersive === true && this.canPresent === false) {
+ return false;
+ }
+ return true;
+ }
+ }, {
+ key: 'requestSession',
+ value: function requestSession() {
+ var $args = arguments;return new Promise(function ($return, $error) {
+ var options, canvas, ctx, session;
+ options = $args.length > 0 && $args[0] !== undefined ? $args[0] : {};
+ if (!this.supportsSession(options)) {
+ return $return(Promise.reject());
+ }
+ if (options.immersive) {
+ canvas = this.global.document.createElement('canvas');
+ {
+ ctx = canvas.getContext('webgl');
+ }
+ return Promise.resolve(this.display.requestPresent([{
+ source: canvas, attributes: EXTRA_PRESENTATION_ATTRIBUTES }])).then(function ($await_2) {
+ try {
+ return $If_1.call(this);
+ } catch ($boundEx) {
+ return $error($boundEx);
+ }
+ }.bind(this), $error);
+ }
+ function $If_1() {
+ session = new Session(options);
+ this.sessions.set(session.id, session);
+ if (options.immersive) {
+ this.immersiveSession = session;
+ this.dispatchEvent('@@webxr-polyfill/vr-present-start', session.id);
+ }
+ return $return(Promise.resolve(session.id));
+ }
+ return $If_1.call(this);
+ }.bind(this));
+ }
+ }, {
+ key: 'requestAnimationFrame',
+ value: function requestAnimationFrame(callback) {
+ return this.display.requestAnimationFrame(callback);
+ }
+ }, {
+ key: 'getPrimaryButtonIndex',
+ value: function getPrimaryButtonIndex(gamepad) {
+ var primaryButton = 0;
+ var name = gamepad.id.toLowerCase();
+ for (var key in PRIMARY_BUTTON_MAP) {
+ if (name.includes(key)) {
+ primaryButton = PRIMARY_BUTTON_MAP[key];
+ break;
+ }
+ }
+ return Math.min(primaryButton, gamepad.buttons.length - 1);
+ }
+ }, {
+ key: 'onFrameStart',
+ value: function onFrameStart(sessionId) {
+ this.display.getFrameData(this.frame);
+ var session = this.sessions.get(sessionId);
+ if (session.immersive && CAN_USE_GAMEPAD) {
+ var prevInputSources = this.gamepadInputSources;
+ this.gamepadInputSources = {};
+ var gamepads = _global.navigator.getGamepads();
+ for (var i = 0; i < gamepads.length; ++i) {
+ var gamepad = gamepads[i];
+ if (gamepad && gamepad.displayId === this.display.displayId) {
+ var inputSourceImpl = prevInputSources[i];
+ if (!inputSourceImpl) {
+ inputSourceImpl = new GamepadXRInputSource(this, this.getPrimaryButtonIndex(gamepad));
+ }
+ inputSourceImpl.updateFromGamepad(gamepad);
+ this.gamepadInputSources[i] = inputSourceImpl;
+ if (inputSourceImpl.primaryButtonIndex != -1) {
+ var primaryActionPressed = gamepad.buttons[inputSourceImpl.primaryButtonIndex].pressed;
+ if (primaryActionPressed && !inputSourceImpl.primaryActionPressed) {
+ this.dispatchEvent('@@webxr-polyfill/input-select-start', { sessionId: session.id, inputSource: inputSourceImpl.inputSource });
+ } else if (!primaryActionPressed && inputSourceImpl.primaryActionPressed) {
+ this.dispatchEvent('@@webxr-polyfill/input-select-end', { sessionId: session.id, inputSource: inputSourceImpl.inputSource });
+ }
+ inputSourceImpl.primaryActionPressed = primaryActionPressed;
+ }
+ }
+ }
+ }
+ if (session.outputContext && !session.immersive) {
+ var outputCanvas = session.outputContext.canvas;
+ var oWidth = outputCanvas.offsetWidth;
+ var oHeight = outputCanvas.offsetHeight;
+ if (outputCanvas.width != oWidth) {
+ outputCanvas.width = oWidth;
+ }
+ if (outputCanvas.height != oHeight) {
+ outputCanvas.height = oHeight;
+ }
+ var canvas = session.baseLayer.context.canvas;
+ if (!this.immersiveSession || canvas !== this.immersiveSession.baseLayer.context.canvas) {
+ if (canvas.width != oWidth) {
+ canvas.width = oWidth;
+ }
+ if (canvas.height != oHeight) {
+ canvas.height = oHeight;
+ }
+ perspective(this.frame.leftProjectionMatrix, Math.PI * 0.4, oWidth / oHeight, this.depthNear, this.depthFar);
+ }
+ }
+ }
+ }, {
+ key: 'onFrameEnd',
+ value: function onFrameEnd(sessionId) {
+ var session = this.sessions.get(sessionId);
+ if (session.ended || !session.baseLayer) {
+ return;
+ }
+ if (session.outputContext && !(session.immersive && !this.display.capabilities.hasExternalDisplay)) {
+ var mirroring = session.immersive && this.display.capabilities.hasExternalDisplay;
+ var canvas = session.baseLayer.context.canvas;
+ var iWidth = mirroring ? canvas.width / 2 : canvas.width;
+ var iHeight = canvas.height;
+ {
+ var outputCanvas = session.outputContext.canvas;
+ var outputContext = outputCanvas.getContext('2d');
+ var oWidth = outputCanvas.width;
+ var oHeight = outputCanvas.height;
+ outputContext.drawImage(canvas, 0, 0, iWidth, iHeight, 0, 0, oWidth, oHeight);
+ }
+ }
+ if (session.immersive && session.baseLayer) {
+ this.display.submitFrame();
+ }
+ }
+ }, {
+ key: 'cancelAnimationFrame',
+ value: function cancelAnimationFrame(handle) {
+ this.display.cancelAnimationFrame(handle);
+ }
+ }, {
+ key: 'endSession',
+ value: function endSession(sessionId) {
+ return new Promise(function ($return, $error) {
+ var session = this.sessions.get(sessionId);
+ if (session.ended) {
+ return $return();
+ }
+ if (session.immersive) {
+ return $return(this.display.exitPresent());
+ } else {
+ session.ended = true;
+ }
+ return $return();
+ }.bind(this));
+ }
+ }, {
+ key: 'requestStageBounds',
+ value: function requestStageBounds() {
+ if (this.display.stageParameters) {
+ var width = this.display.stageParameters.sizeX;
+ var depth = this.display.stageParameters.sizeZ;
+ var data = [];
+ data.push(-width / 2);
+ data.push(-depth / 2);
+ data.push(width / 2);
+ data.push(-depth / 2);
+ data.push(width / 2);
+ data.push(depth / 2);
+ data.push(-width / 2);
+ data.push(depth / 2);
+ return data;
+ }
+ return null;
+ }
+ }, {
+ key: 'requestFrameOfReferenceTransform',
+ value: function requestFrameOfReferenceTransform(type, options) {
+ return new Promise(function ($return, $error) {
+ if (type === 'stage' && this.display.stageParameters && this.display.stageParameters.sittingToStandingTransform) {
+ return $return(this.display.stageParameters.sittingToStandingTransform);
+ }
+ return $return();
+ }.bind(this));
+ }
+ }, {
+ key: 'getProjectionMatrix',
+ value: function getProjectionMatrix(eye) {
+ if (eye === 'left') {
+ return this.frame.leftProjectionMatrix;
+ } else if (eye === 'right') {
+ return this.frame.rightProjectionMatrix;
+ } else {
+ throw new Error('eye must be of type \'left\' or \'right\'');
+ }
+ }
+ }, {
+ key: 'getViewport',
+ value: function getViewport(sessionId, eye, layer, target) {
+ var session = this.sessions.get(sessionId);
+ var _layer$context$canvas = layer.context.canvas,
+ width = _layer$context$canvas.width,
+ height = _layer$context$canvas.height;
+ if (!session.immersive) {
+ target.x = target.y = 0;
+ target.width = width;
+ target.height = height;
+ return true;
+ }
+ if (eye === 'left') {
+ target.x = 0;
+ } else if (eye === 'right') {
+ target.x = width / 2;
+ } else {
+ return false;
+ }
+ target.y = 0;
+ target.width = width / 2;
+ target.height = height;
+ return true;
+ }
+ }, {
+ key: 'getBasePoseMatrix',
+ value: function getBasePoseMatrix() {
+ var _frame$pose = this.frame.pose,
+ position = _frame$pose.position,
+ orientation = _frame$pose.orientation;
+ if (!position && !orientation) {
+ return this.baseModelMatrix;
+ }
+ if (!position) {
+ position = this.tempVec3;
+ position[0] = position[1] = position[2] = 0;
+ }
+ fromRotationTranslation(this.baseModelMatrix, orientation, position);
+ return this.baseModelMatrix;
+ }
+ }, {
+ key: 'getBaseViewMatrix',
+ value: function getBaseViewMatrix(eye) {
+ if (eye === 'left') {
+ return this.frame.leftViewMatrix;
+ } else if (eye === 'right') {
+ return this.frame.rightViewMatrix;
+ } else {
+ throw new Error('eye must be of type \'left\' or \'right\'');
+ }
+ }
+ }, {
+ key: 'getInputSources',
+ value: function getInputSources() {
+ var inputSources = [];
+ for (var i in this.gamepadInputSources) {
+ inputSources.push(this.gamepadInputSources[i].inputSource);
+ }
+ return inputSources;
+ }
+ }, {
+ key: 'getInputPose',
+ value: function getInputPose(inputSource, coordinateSystem) {
+ if (!coordinateSystem) {
+ return null;
+ }
+ for (var i in this.gamepadInputSources) {
+ var inputSourceImpl = this.gamepadInputSources[i];
+ if (inputSourceImpl.inputSource === inputSource) {
+ return inputSourceImpl.getXRInputPose(coordinateSystem);
+ }
+ }
+ return null;
+ }
+ }, {
+ key: 'onWindowResize',
+ value: function onWindowResize() {}
+ }, {
+ key: 'onVRDisplayPresentChange',
+ value: function onVRDisplayPresentChange(e) {
+ var _this3 = this;
+ if (!this.display.isPresenting) {
+ this.sessions.forEach(function (session) {
+ if (session.immersive && !session.ended) {
+ if (session.modifiedCanvasLayer) {
+ var canvas = session.baseLayer.context.canvas;
+ document.body.removeChild(canvas);
+ canvas.setAttribute('style', '');
+ }
+ if (_this3.immersiveSession === session) {
+ _this3.immersiveSession = null;
+ }
+ _this3.dispatchEvent('@@webxr-polyfill/vr-present-end', session.id);
+ }
+ });
+ }
+ }
+ }, {
+ key: 'depthNear',
+ get: function get$$1() {
+ return this.display.depthNear;
+ }
+ ,
+ set: function set$$1(val) {
+ this.display.depthNear = val;
+ }
+ }, {
+ key: 'depthFar',
+ get: function get$$1() {
+ return this.display.depthFar;
+ }
+ ,
+ set: function set$$1(val) {
+ this.display.depthFar = val;
+ }
+ }]);
+ return WebVRDevice;
+}(PolyfilledXRDevice);
+
+var CardboardXRDevice = function (_WebVRDevice) {
+ inherits(CardboardXRDevice, _WebVRDevice);
+ function CardboardXRDevice(global) {
+ classCallCheck(this, CardboardXRDevice);
+ var display = new CardboardVRDisplay();
+ var _this = possibleConstructorReturn(this, (CardboardXRDevice.__proto__ || Object.getPrototypeOf(CardboardXRDevice)).call(this, global, display));
+ _this.display = display;
+ _this.frame = {
+ rightViewMatrix: new Float32Array(16),
+ leftViewMatrix: new Float32Array(16),
+ rightProjectionMatrix: new Float32Array(16),
+ leftProjectionMatrix: new Float32Array(16),
+ pose: null,
+ timestamp: null
+ };
+ return _this;
+ }
+ return CardboardXRDevice;
+}(WebVRDevice);
+
+var getXRDevice = function getXRDevice(global) {
+ return new Promise(function ($return, $error) {
+ var device;
+ device = null;
+ if ('xr' in global.navigator) {
+ var $Try_1_Post = function () {
+ try {
+ return $If_3.call(this);
+ } catch ($boundEx) {
+ return $error($boundEx);
+ }
+ }.bind(this);var $Try_1_Catch = function (e) {
+ try {
+ return $Try_1_Post();
+ } catch ($boundEx) {
+ return $error($boundEx);
+ }
+ }.bind(this);
+ try {
+ return Promise.resolve(global.navigator.xr.requestDevice()).then(function ($await_6) {
+ try {
+ device = $await_6;
+ return $Try_1_Post();
+ } catch ($boundEx) {
+ return $Try_1_Catch($boundEx);
+ }
+ }.bind(this), $Try_1_Catch);
+ } catch (e) {
+ $Try_1_Catch(e);
+ }
+ }
+ function $If_3() {
+ return $return(device);
+ }
+ return $If_3.call(this);
+ }.bind(this));
+};
+var getVRDisplay = function getVRDisplay(global) {
+ return new Promise(function ($return, $error) {
+ var device, displays;
+ device = null;
+ if ('getVRDisplays' in global.navigator) {
+ var $Try_2_Post = function () {
+ try {
+ return $If_4.call(this);
+ } catch ($boundEx) {
+ return $error($boundEx);
+ }
+ }.bind(this);var $Try_2_Catch = function (e) {
+ try {
+ return $Try_2_Post();
+ } catch ($boundEx) {
+ return $error($boundEx);
+ }
+ }.bind(this);
+ try {
+ return Promise.resolve(global.navigator.getVRDisplays()).then(function ($await_7) {
+ try {
+ displays = $await_7;
+ if (displays && displays.length) {
+ device = new WebVRDevice(global, displays[0]);
+ }
+ return $Try_2_Post();
+ } catch ($boundEx) {
+ return $Try_2_Catch($boundEx);
+ }
+ }.bind(this), $Try_2_Catch);
+ } catch (e) {
+ $Try_2_Catch(e);
+ }
+ }
+ function $If_4() {
+ return $return(device);
+ }
+ return $If_4.call(this);
+ }.bind(this));
+};
+var requestDevice = function requestDevice(global, config) {
+ return new Promise(function ($return, $error) {
+ var device;
+ return Promise.resolve(getXRDevice(global)).then(function ($await_8) {
+ try {
+ device = $await_8;
+ if (device) {
+ return $return(device);
+ }
+ if (config.webvr) {
+ return Promise.resolve(getVRDisplay(global)).then(function ($await_9) {
+ try {
+ device = $await_9;
+ if (device) {
+ return $return(new XRDevice(device));
+ }
+ return $If_5.call(this);
+ } catch ($boundEx) {
+ return $error($boundEx);
+ }
+ }.bind(this), $error);
+ }
+ function $If_5() {
+ if (config.cardboard && isMobile(global)) {
+ if (!global.VRFrameData) {
+ global.VRFrameData = function () {
+ this.rightViewMatrix = new Float32Array(16);
+ this.leftViewMatrix = new Float32Array(16);
+ this.rightProjectionMatrix = new Float32Array(16);
+ this.leftProjectionMatrix = new Float32Array(16);
+ this.pose = null;
+ };
+ }
+ return $return(new XRDevice(new CardboardXRDevice(global)));
+ }
+ return $return(null);
+ }
+ return $If_5.call(this);
+ } catch ($boundEx) {
+ return $error($boundEx);
+ }
+ }.bind(this), $error);
+ }.bind(this));
+};
+
+var CONFIG_DEFAULTS = {
+ webvr: true,
+ cardboard: true
+};
+var partials = ['navigator', 'HTMLCanvasElement', 'WebGLRenderingContext'];
+var WebXRPolyfill = function () {
+ function WebXRPolyfill(global) {
+ var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+ classCallCheck(this, WebXRPolyfill);
+ this.global = global || _global;
+ this.config = Object.freeze(Object.assign({}, CONFIG_DEFAULTS, config));
+ this.nativeWebXR = 'xr' in this.global.navigator;
+ this.injected = false;
+ if (!this.nativeWebXR) {
+ this._injectPolyfill(this.global);
+ }
+ else if (this.config.cardboard && isMobile(this.global)) {
+ this._patchRequestDevice();
+ }
+ }
+ createClass(WebXRPolyfill, [{
+ key: '_injectPolyfill',
+ value: function _injectPolyfill(global) {
+ if (!partials.every(function (iface) {
+ return !!global[iface];
+ })) {
+ throw new Error('Global must have the following attributes : ' + partials);
+ }
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+ try {
+ for (var _iterator = Object.keys(API)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var className = _step.value;
+ if (global[className] !== undefined) {
+ console.warn(className + ' already defined on global.');
+ } else {
+ global[className] = API[className];
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+ {
+ var polyfilledCtx = extendContextCompatibleXRDevice(global.WebGLRenderingContext);
+ if (polyfilledCtx) {
+ extendGetContext(global.HTMLCanvasElement);
+ if (global.WebGL2RenderingContext) {
+ extendContextCompatibleXRDevice(global.WebGL2RenderingContext);
+ }
+ }
+ }
+ this.injected = true;
+ this._patchRequestDevice();
+ }
+ }, {
+ key: '_patchRequestDevice',
+ value: function _patchRequestDevice() {
+ var device = requestDevice(this.global, this.config);
+ this.xr = new XR(device);
+ Object.defineProperty(this.global.navigator, 'xr', {
+ value: this.xr,
+ configurable: true
+ });
+ }
+ }]);
+ return WebXRPolyfill;
+}();
+
+return WebXRPolyfill;
+
+})));