12342 lines
543 KiB
JavaScript
12342 lines
543 KiB
JavaScript
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
|
|
(function (process){
|
|
/**
|
|
* Tween.js - Licensed under the MIT license
|
|
* https://github.com/tweenjs/tween.js
|
|
* ----------------------------------------------
|
|
*
|
|
* See https://github.com/tweenjs/tween.js/graphs/contributors for the full list of contributors.
|
|
* Thank you all, you're awesome!
|
|
*/
|
|
|
|
var TWEEN = TWEEN || (function () {
|
|
|
|
var _tweens = [];
|
|
|
|
return {
|
|
|
|
getAll: function () {
|
|
|
|
return _tweens;
|
|
|
|
},
|
|
|
|
removeAll: function () {
|
|
|
|
_tweens = [];
|
|
|
|
},
|
|
|
|
add: function (tween) {
|
|
|
|
_tweens.push(tween);
|
|
|
|
},
|
|
|
|
remove: function (tween) {
|
|
|
|
var i = _tweens.indexOf(tween);
|
|
|
|
if (i !== -1) {
|
|
_tweens.splice(i, 1);
|
|
}
|
|
|
|
},
|
|
|
|
update: function (time, preserve) {
|
|
|
|
if (_tweens.length === 0) {
|
|
return false;
|
|
}
|
|
|
|
var i = 0;
|
|
|
|
time = time !== undefined ? time : TWEEN.now();
|
|
|
|
while (i < _tweens.length) {
|
|
|
|
if (_tweens[i].update(time) || preserve) {
|
|
i++;
|
|
} else {
|
|
_tweens.splice(i, 1);
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
};
|
|
|
|
})();
|
|
|
|
|
|
// Include a performance.now polyfill.
|
|
// In node.js, use process.hrtime.
|
|
if (typeof (window) === 'undefined' && typeof (process) !== 'undefined') {
|
|
TWEEN.now = function () {
|
|
var time = process.hrtime();
|
|
|
|
// Convert [seconds, nanoseconds] to milliseconds.
|
|
return time[0] * 1000 + time[1] / 1000000;
|
|
};
|
|
}
|
|
// In a browser, use window.performance.now if it is available.
|
|
else if (typeof (window) !== 'undefined' &&
|
|
window.performance !== undefined &&
|
|
window.performance.now !== undefined) {
|
|
// This must be bound, because directly assigning this function
|
|
// leads to an invocation exception in Chrome.
|
|
TWEEN.now = window.performance.now.bind(window.performance);
|
|
}
|
|
// Use Date.now if it is available.
|
|
else if (Date.now !== undefined) {
|
|
TWEEN.now = Date.now;
|
|
}
|
|
// Otherwise, use 'new Date().getTime()'.
|
|
else {
|
|
TWEEN.now = function () {
|
|
return new Date().getTime();
|
|
};
|
|
}
|
|
|
|
|
|
TWEEN.Tween = function (object) {
|
|
|
|
var _object = object;
|
|
var _valuesStart = {};
|
|
var _valuesEnd = {};
|
|
var _valuesStartRepeat = {};
|
|
var _duration = 1000;
|
|
var _repeat = 0;
|
|
var _repeatDelayTime;
|
|
var _yoyo = false;
|
|
var _isPlaying = false;
|
|
var _reversed = false;
|
|
var _delayTime = 0;
|
|
var _startTime = null;
|
|
var _easingFunction = TWEEN.Easing.Linear.None;
|
|
var _interpolationFunction = TWEEN.Interpolation.Linear;
|
|
var _chainedTweens = [];
|
|
var _onStartCallback = null;
|
|
var _onStartCallbackFired = false;
|
|
var _onUpdateCallback = null;
|
|
var _onCompleteCallback = null;
|
|
var _onStopCallback = null;
|
|
|
|
this.to = function (properties, duration) {
|
|
|
|
_valuesEnd = properties;
|
|
|
|
if (duration !== undefined) {
|
|
_duration = duration;
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
this.start = function (time) {
|
|
|
|
TWEEN.add(this);
|
|
|
|
_isPlaying = true;
|
|
|
|
_onStartCallbackFired = false;
|
|
|
|
_startTime = time !== undefined ? time : TWEEN.now();
|
|
_startTime += _delayTime;
|
|
|
|
for (var property in _valuesEnd) {
|
|
|
|
// Check if an Array was provided as property value
|
|
if (_valuesEnd[property] instanceof Array) {
|
|
|
|
if (_valuesEnd[property].length === 0) {
|
|
continue;
|
|
}
|
|
|
|
// Create a local copy of the Array with the start value at the front
|
|
_valuesEnd[property] = [_object[property]].concat(_valuesEnd[property]);
|
|
|
|
}
|
|
|
|
// If `to()` specifies a property that doesn't exist in the source object,
|
|
// we should not set that property in the object
|
|
if (_object[property] === undefined) {
|
|
continue;
|
|
}
|
|
|
|
// Save the starting value.
|
|
_valuesStart[property] = _object[property];
|
|
|
|
if ((_valuesStart[property] instanceof Array) === false) {
|
|
_valuesStart[property] *= 1.0; // Ensures we're using numbers, not strings
|
|
}
|
|
|
|
_valuesStartRepeat[property] = _valuesStart[property] || 0;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
this.stop = function () {
|
|
|
|
if (!_isPlaying) {
|
|
return this;
|
|
}
|
|
|
|
TWEEN.remove(this);
|
|
_isPlaying = false;
|
|
|
|
if (_onStopCallback !== null) {
|
|
_onStopCallback.call(_object, _object);
|
|
}
|
|
|
|
this.stopChainedTweens();
|
|
return this;
|
|
|
|
};
|
|
|
|
this.end = function () {
|
|
|
|
this.update(_startTime + _duration);
|
|
return this;
|
|
|
|
};
|
|
|
|
this.stopChainedTweens = function () {
|
|
|
|
for (var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++) {
|
|
_chainedTweens[i].stop();
|
|
}
|
|
|
|
};
|
|
|
|
this.delay = function (amount) {
|
|
|
|
_delayTime = amount;
|
|
return this;
|
|
|
|
};
|
|
|
|
this.repeat = function (times) {
|
|
|
|
_repeat = times;
|
|
return this;
|
|
|
|
};
|
|
|
|
this.repeatDelay = function (amount) {
|
|
|
|
_repeatDelayTime = amount;
|
|
return this;
|
|
|
|
};
|
|
|
|
this.yoyo = function (yoyo) {
|
|
|
|
_yoyo = yoyo;
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
this.easing = function (easing) {
|
|
|
|
_easingFunction = easing;
|
|
return this;
|
|
|
|
};
|
|
|
|
this.interpolation = function (interpolation) {
|
|
|
|
_interpolationFunction = interpolation;
|
|
return this;
|
|
|
|
};
|
|
|
|
this.chain = function () {
|
|
|
|
_chainedTweens = arguments;
|
|
return this;
|
|
|
|
};
|
|
|
|
this.onStart = function (callback) {
|
|
|
|
_onStartCallback = callback;
|
|
return this;
|
|
|
|
};
|
|
|
|
this.onUpdate = function (callback) {
|
|
|
|
_onUpdateCallback = callback;
|
|
return this;
|
|
|
|
};
|
|
|
|
this.onComplete = function (callback) {
|
|
|
|
_onCompleteCallback = callback;
|
|
return this;
|
|
|
|
};
|
|
|
|
this.onStop = function (callback) {
|
|
|
|
_onStopCallback = callback;
|
|
return this;
|
|
|
|
};
|
|
|
|
this.update = function (time) {
|
|
|
|
var property;
|
|
var elapsed;
|
|
var value;
|
|
|
|
if (time < _startTime) {
|
|
return true;
|
|
}
|
|
|
|
if (_onStartCallbackFired === false) {
|
|
|
|
if (_onStartCallback !== null) {
|
|
_onStartCallback.call(_object, _object);
|
|
}
|
|
|
|
_onStartCallbackFired = true;
|
|
}
|
|
|
|
elapsed = (time - _startTime) / _duration;
|
|
elapsed = elapsed > 1 ? 1 : elapsed;
|
|
|
|
value = _easingFunction(elapsed);
|
|
|
|
for (property in _valuesEnd) {
|
|
|
|
// Don't update properties that do not exist in the source object
|
|
if (_valuesStart[property] === undefined) {
|
|
continue;
|
|
}
|
|
|
|
var start = _valuesStart[property] || 0;
|
|
var end = _valuesEnd[property];
|
|
|
|
if (end instanceof Array) {
|
|
|
|
_object[property] = _interpolationFunction(end, value);
|
|
|
|
} else {
|
|
|
|
// Parses relative end values with start as base (e.g.: +10, -3)
|
|
if (typeof (end) === 'string') {
|
|
|
|
if (end.charAt(0) === '+' || end.charAt(0) === '-') {
|
|
end = start + parseFloat(end);
|
|
} else {
|
|
end = parseFloat(end);
|
|
}
|
|
}
|
|
|
|
// Protect against non numeric properties.
|
|
if (typeof (end) === 'number') {
|
|
_object[property] = start + (end - start) * value;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (_onUpdateCallback !== null) {
|
|
_onUpdateCallback.call(_object, value);
|
|
}
|
|
|
|
if (elapsed === 1) {
|
|
|
|
if (_repeat > 0) {
|
|
|
|
if (isFinite(_repeat)) {
|
|
_repeat--;
|
|
}
|
|
|
|
// Reassign starting values, restart by making startTime = now
|
|
for (property in _valuesStartRepeat) {
|
|
|
|
if (typeof (_valuesEnd[property]) === 'string') {
|
|
_valuesStartRepeat[property] = _valuesStartRepeat[property] + parseFloat(_valuesEnd[property]);
|
|
}
|
|
|
|
if (_yoyo) {
|
|
var tmp = _valuesStartRepeat[property];
|
|
|
|
_valuesStartRepeat[property] = _valuesEnd[property];
|
|
_valuesEnd[property] = tmp;
|
|
}
|
|
|
|
_valuesStart[property] = _valuesStartRepeat[property];
|
|
|
|
}
|
|
|
|
if (_yoyo) {
|
|
_reversed = !_reversed;
|
|
}
|
|
|
|
if (_repeatDelayTime !== undefined) {
|
|
_startTime = time + _repeatDelayTime;
|
|
} else {
|
|
_startTime = time + _delayTime;
|
|
}
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
if (_onCompleteCallback !== null) {
|
|
|
|
_onCompleteCallback.call(_object, _object);
|
|
}
|
|
|
|
for (var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++) {
|
|
// Make the chained tweens start exactly at the time they should,
|
|
// even if the `update()` method was called way past the duration of the tween
|
|
_chainedTweens[i].start(_startTime + _duration);
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
TWEEN.Easing = {
|
|
|
|
Linear: {
|
|
|
|
None: function (k) {
|
|
|
|
return k;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Quadratic: {
|
|
|
|
In: function (k) {
|
|
|
|
return k * k;
|
|
|
|
},
|
|
|
|
Out: function (k) {
|
|
|
|
return k * (2 - k);
|
|
|
|
},
|
|
|
|
InOut: function (k) {
|
|
|
|
if ((k *= 2) < 1) {
|
|
return 0.5 * k * k;
|
|
}
|
|
|
|
return - 0.5 * (--k * (k - 2) - 1);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Cubic: {
|
|
|
|
In: function (k) {
|
|
|
|
return k * k * k;
|
|
|
|
},
|
|
|
|
Out: function (k) {
|
|
|
|
return --k * k * k + 1;
|
|
|
|
},
|
|
|
|
InOut: function (k) {
|
|
|
|
if ((k *= 2) < 1) {
|
|
return 0.5 * k * k * k;
|
|
}
|
|
|
|
return 0.5 * ((k -= 2) * k * k + 2);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Quartic: {
|
|
|
|
In: function (k) {
|
|
|
|
return k * k * k * k;
|
|
|
|
},
|
|
|
|
Out: function (k) {
|
|
|
|
return 1 - (--k * k * k * k);
|
|
|
|
},
|
|
|
|
InOut: function (k) {
|
|
|
|
if ((k *= 2) < 1) {
|
|
return 0.5 * k * k * k * k;
|
|
}
|
|
|
|
return - 0.5 * ((k -= 2) * k * k * k - 2);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Quintic: {
|
|
|
|
In: function (k) {
|
|
|
|
return k * k * k * k * k;
|
|
|
|
},
|
|
|
|
Out: function (k) {
|
|
|
|
return --k * k * k * k * k + 1;
|
|
|
|
},
|
|
|
|
InOut: function (k) {
|
|
|
|
if ((k *= 2) < 1) {
|
|
return 0.5 * k * k * k * k * k;
|
|
}
|
|
|
|
return 0.5 * ((k -= 2) * k * k * k * k + 2);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Sinusoidal: {
|
|
|
|
In: function (k) {
|
|
|
|
return 1 - Math.cos(k * Math.PI / 2);
|
|
|
|
},
|
|
|
|
Out: function (k) {
|
|
|
|
return Math.sin(k * Math.PI / 2);
|
|
|
|
},
|
|
|
|
InOut: function (k) {
|
|
|
|
return 0.5 * (1 - Math.cos(Math.PI * k));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Exponential: {
|
|
|
|
In: function (k) {
|
|
|
|
return k === 0 ? 0 : Math.pow(1024, k - 1);
|
|
|
|
},
|
|
|
|
Out: function (k) {
|
|
|
|
return k === 1 ? 1 : 1 - Math.pow(2, - 10 * k);
|
|
|
|
},
|
|
|
|
InOut: function (k) {
|
|
|
|
if (k === 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (k === 1) {
|
|
return 1;
|
|
}
|
|
|
|
if ((k *= 2) < 1) {
|
|
return 0.5 * Math.pow(1024, k - 1);
|
|
}
|
|
|
|
return 0.5 * (- Math.pow(2, - 10 * (k - 1)) + 2);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Circular: {
|
|
|
|
In: function (k) {
|
|
|
|
return 1 - Math.sqrt(1 - k * k);
|
|
|
|
},
|
|
|
|
Out: function (k) {
|
|
|
|
return Math.sqrt(1 - (--k * k));
|
|
|
|
},
|
|
|
|
InOut: function (k) {
|
|
|
|
if ((k *= 2) < 1) {
|
|
return - 0.5 * (Math.sqrt(1 - k * k) - 1);
|
|
}
|
|
|
|
return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Elastic: {
|
|
|
|
In: function (k) {
|
|
|
|
if (k === 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (k === 1) {
|
|
return 1;
|
|
}
|
|
|
|
return -Math.pow(2, 10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI);
|
|
|
|
},
|
|
|
|
Out: function (k) {
|
|
|
|
if (k === 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (k === 1) {
|
|
return 1;
|
|
}
|
|
|
|
return Math.pow(2, -10 * k) * Math.sin((k - 0.1) * 5 * Math.PI) + 1;
|
|
|
|
},
|
|
|
|
InOut: function (k) {
|
|
|
|
if (k === 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (k === 1) {
|
|
return 1;
|
|
}
|
|
|
|
k *= 2;
|
|
|
|
if (k < 1) {
|
|
return -0.5 * Math.pow(2, 10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI);
|
|
}
|
|
|
|
return 0.5 * Math.pow(2, -10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI) + 1;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Back: {
|
|
|
|
In: function (k) {
|
|
|
|
var s = 1.70158;
|
|
|
|
return k * k * ((s + 1) * k - s);
|
|
|
|
},
|
|
|
|
Out: function (k) {
|
|
|
|
var s = 1.70158;
|
|
|
|
return --k * k * ((s + 1) * k + s) + 1;
|
|
|
|
},
|
|
|
|
InOut: function (k) {
|
|
|
|
var s = 1.70158 * 1.525;
|
|
|
|
if ((k *= 2) < 1) {
|
|
return 0.5 * (k * k * ((s + 1) * k - s));
|
|
}
|
|
|
|
return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Bounce: {
|
|
|
|
In: function (k) {
|
|
|
|
return 1 - TWEEN.Easing.Bounce.Out(1 - k);
|
|
|
|
},
|
|
|
|
Out: function (k) {
|
|
|
|
if (k < (1 / 2.75)) {
|
|
return 7.5625 * k * k;
|
|
} else if (k < (2 / 2.75)) {
|
|
return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;
|
|
} else if (k < (2.5 / 2.75)) {
|
|
return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;
|
|
} else {
|
|
return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;
|
|
}
|
|
|
|
},
|
|
|
|
InOut: function (k) {
|
|
|
|
if (k < 0.5) {
|
|
return TWEEN.Easing.Bounce.In(k * 2) * 0.5;
|
|
}
|
|
|
|
return TWEEN.Easing.Bounce.Out(k * 2 - 1) * 0.5 + 0.5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
TWEEN.Interpolation = {
|
|
|
|
Linear: function (v, k) {
|
|
|
|
var m = v.length - 1;
|
|
var f = m * k;
|
|
var i = Math.floor(f);
|
|
var fn = TWEEN.Interpolation.Utils.Linear;
|
|
|
|
if (k < 0) {
|
|
return fn(v[0], v[1], f);
|
|
}
|
|
|
|
if (k > 1) {
|
|
return fn(v[m], v[m - 1], m - f);
|
|
}
|
|
|
|
return fn(v[i], v[i + 1 > m ? m : i + 1], f - i);
|
|
|
|
},
|
|
|
|
Bezier: function (v, k) {
|
|
|
|
var b = 0;
|
|
var n = v.length - 1;
|
|
var pw = Math.pow;
|
|
var bn = TWEEN.Interpolation.Utils.Bernstein;
|
|
|
|
for (var i = 0; i <= n; i++) {
|
|
b += pw(1 - k, n - i) * pw(k, i) * v[i] * bn(n, i);
|
|
}
|
|
|
|
return b;
|
|
|
|
},
|
|
|
|
CatmullRom: function (v, k) {
|
|
|
|
var m = v.length - 1;
|
|
var f = m * k;
|
|
var i = Math.floor(f);
|
|
var fn = TWEEN.Interpolation.Utils.CatmullRom;
|
|
|
|
if (v[0] === v[m]) {
|
|
|
|
if (k < 0) {
|
|
i = Math.floor(f = m * (1 + k));
|
|
}
|
|
|
|
return fn(v[(i - 1 + m) % m], v[i], v[(i + 1) % m], v[(i + 2) % m], f - i);
|
|
|
|
} else {
|
|
|
|
if (k < 0) {
|
|
return v[0] - (fn(v[0], v[0], v[1], v[1], -f) - v[0]);
|
|
}
|
|
|
|
if (k > 1) {
|
|
return v[m] - (fn(v[m], v[m], v[m - 1], v[m - 1], f - m) - v[m]);
|
|
}
|
|
|
|
return fn(v[i ? i - 1 : 0], v[i], v[m < i + 1 ? m : i + 1], v[m < i + 2 ? m : i + 2], f - i);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Utils: {
|
|
|
|
Linear: function (p0, p1, t) {
|
|
|
|
return (p1 - p0) * t + p0;
|
|
|
|
},
|
|
|
|
Bernstein: function (n, i) {
|
|
|
|
var fc = TWEEN.Interpolation.Utils.Factorial;
|
|
|
|
return fc(n) / fc(i) / fc(n - i);
|
|
|
|
},
|
|
|
|
Factorial: (function () {
|
|
|
|
var a = [1];
|
|
|
|
return function (n) {
|
|
|
|
var s = 1;
|
|
|
|
if (a[n]) {
|
|
return a[n];
|
|
}
|
|
|
|
for (var i = n; i > 1; i--) {
|
|
s *= i;
|
|
}
|
|
|
|
a[n] = s;
|
|
return s;
|
|
|
|
};
|
|
|
|
})(),
|
|
|
|
CatmullRom: function (p0, p1, p2, p3, t) {
|
|
|
|
var v0 = (p2 - p0) * 0.5;
|
|
var v1 = (p3 - p1) * 0.5;
|
|
var t2 = t * t;
|
|
var t3 = t * t2;
|
|
|
|
return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (- 3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// UMD (Universal Module Definition)
|
|
(function (root) {
|
|
|
|
if (typeof define === 'function' && define.amd) {
|
|
|
|
// AMD
|
|
define([], function () {
|
|
return TWEEN;
|
|
});
|
|
|
|
} else if (typeof module !== 'undefined' && typeof exports === 'object') {
|
|
|
|
// Node.js
|
|
module.exports = TWEEN;
|
|
|
|
} else if (root !== undefined) {
|
|
|
|
// Global variable
|
|
root.TWEEN = TWEEN;
|
|
|
|
}
|
|
|
|
})(this);
|
|
|
|
}).call(this,_dereq_('_process'))
|
|
},{"_process":4}],2:[function(_dereq_,module,exports){
|
|
(function (process,global){
|
|
/*!
|
|
* @overview es6-promise - a tiny implementation of Promises/A+.
|
|
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
|
|
* @license Licensed under MIT license
|
|
* See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
|
|
* @version 3.3.1
|
|
*/
|
|
|
|
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
(global.ES6Promise = factory());
|
|
}(this, (function () { 'use strict';
|
|
|
|
function objectOrFunction(x) {
|
|
return typeof x === 'function' || typeof x === 'object' && x !== null;
|
|
}
|
|
|
|
function isFunction(x) {
|
|
return typeof x === 'function';
|
|
}
|
|
|
|
var _isArray = undefined;
|
|
if (!Array.isArray) {
|
|
_isArray = function (x) {
|
|
return Object.prototype.toString.call(x) === '[object Array]';
|
|
};
|
|
} else {
|
|
_isArray = Array.isArray;
|
|
}
|
|
|
|
var isArray = _isArray;
|
|
|
|
var len = 0;
|
|
var vertxNext = undefined;
|
|
var customSchedulerFn = undefined;
|
|
|
|
var asap = function asap(callback, arg) {
|
|
queue[len] = callback;
|
|
queue[len + 1] = arg;
|
|
len += 2;
|
|
if (len === 2) {
|
|
// If len is 2, that means that we need to schedule an async flush.
|
|
// If additional callbacks are queued before the queue is flushed, they
|
|
// will be processed by this flush that we are scheduling.
|
|
if (customSchedulerFn) {
|
|
customSchedulerFn(flush);
|
|
} else {
|
|
scheduleFlush();
|
|
}
|
|
}
|
|
};
|
|
|
|
function setScheduler(scheduleFn) {
|
|
customSchedulerFn = scheduleFn;
|
|
}
|
|
|
|
function setAsap(asapFn) {
|
|
asap = asapFn;
|
|
}
|
|
|
|
var browserWindow = typeof window !== 'undefined' ? window : undefined;
|
|
var browserGlobal = browserWindow || {};
|
|
var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
|
|
var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && ({}).toString.call(process) === '[object process]';
|
|
|
|
// test for web worker but not in IE10
|
|
var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
|
|
|
|
// node
|
|
function useNextTick() {
|
|
// node version 0.10.x displays a deprecation warning when nextTick is used recursively
|
|
// see https://github.com/cujojs/when/issues/410 for details
|
|
return function () {
|
|
return process.nextTick(flush);
|
|
};
|
|
}
|
|
|
|
// vertx
|
|
function useVertxTimer() {
|
|
return function () {
|
|
vertxNext(flush);
|
|
};
|
|
}
|
|
|
|
function useMutationObserver() {
|
|
var iterations = 0;
|
|
var observer = new BrowserMutationObserver(flush);
|
|
var node = document.createTextNode('');
|
|
observer.observe(node, { characterData: true });
|
|
|
|
return function () {
|
|
node.data = iterations = ++iterations % 2;
|
|
};
|
|
}
|
|
|
|
// web worker
|
|
function useMessageChannel() {
|
|
var channel = new MessageChannel();
|
|
channel.port1.onmessage = flush;
|
|
return function () {
|
|
return channel.port2.postMessage(0);
|
|
};
|
|
}
|
|
|
|
function useSetTimeout() {
|
|
// Store setTimeout reference so es6-promise will be unaffected by
|
|
// other code modifying setTimeout (like sinon.useFakeTimers())
|
|
var globalSetTimeout = setTimeout;
|
|
return function () {
|
|
return globalSetTimeout(flush, 1);
|
|
};
|
|
}
|
|
|
|
var queue = new Array(1000);
|
|
function flush() {
|
|
for (var i = 0; i < len; i += 2) {
|
|
var callback = queue[i];
|
|
var arg = queue[i + 1];
|
|
|
|
callback(arg);
|
|
|
|
queue[i] = undefined;
|
|
queue[i + 1] = undefined;
|
|
}
|
|
|
|
len = 0;
|
|
}
|
|
|
|
function attemptVertx() {
|
|
try {
|
|
var r = _dereq_;
|
|
var vertx = r('vertx');
|
|
vertxNext = vertx.runOnLoop || vertx.runOnContext;
|
|
return useVertxTimer();
|
|
} catch (e) {
|
|
return useSetTimeout();
|
|
}
|
|
}
|
|
|
|
var scheduleFlush = undefined;
|
|
// Decide what async method to use to triggering processing of queued callbacks:
|
|
if (isNode) {
|
|
scheduleFlush = useNextTick();
|
|
} else if (BrowserMutationObserver) {
|
|
scheduleFlush = useMutationObserver();
|
|
} else if (isWorker) {
|
|
scheduleFlush = useMessageChannel();
|
|
} else if (browserWindow === undefined && typeof _dereq_ === 'function') {
|
|
scheduleFlush = attemptVertx();
|
|
} else {
|
|
scheduleFlush = useSetTimeout();
|
|
}
|
|
|
|
function then(onFulfillment, onRejection) {
|
|
var _arguments = arguments;
|
|
|
|
var parent = this;
|
|
|
|
var child = new this.constructor(noop);
|
|
|
|
if (child[PROMISE_ID] === undefined) {
|
|
makePromise(child);
|
|
}
|
|
|
|
var _state = parent._state;
|
|
|
|
if (_state) {
|
|
(function () {
|
|
var callback = _arguments[_state - 1];
|
|
asap(function () {
|
|
return invokeCallback(_state, child, callback, parent._result);
|
|
});
|
|
})();
|
|
} else {
|
|
subscribe(parent, child, onFulfillment, onRejection);
|
|
}
|
|
|
|
return child;
|
|
}
|
|
|
|
/**
|
|
`Promise.resolve` returns a promise that will become resolved with the
|
|
passed `value`. It is shorthand for the following:
|
|
|
|
```javascript
|
|
let promise = new Promise(function(resolve, reject){
|
|
resolve(1);
|
|
});
|
|
|
|
promise.then(function(value){
|
|
// value === 1
|
|
});
|
|
```
|
|
|
|
Instead of writing the above, your code now simply becomes the following:
|
|
|
|
```javascript
|
|
let promise = Promise.resolve(1);
|
|
|
|
promise.then(function(value){
|
|
// value === 1
|
|
});
|
|
```
|
|
|
|
@method resolve
|
|
@static
|
|
@param {Any} value value that the returned promise will be resolved with
|
|
Useful for tooling.
|
|
@return {Promise} a promise that will become fulfilled with the given
|
|
`value`
|
|
*/
|
|
function resolve(object) {
|
|
/*jshint validthis:true */
|
|
var Constructor = this;
|
|
|
|
if (object && typeof object === 'object' && object.constructor === Constructor) {
|
|
return object;
|
|
}
|
|
|
|
var promise = new Constructor(noop);
|
|
_resolve(promise, object);
|
|
return promise;
|
|
}
|
|
|
|
var PROMISE_ID = Math.random().toString(36).substring(16);
|
|
|
|
function noop() {}
|
|
|
|
var PENDING = void 0;
|
|
var FULFILLED = 1;
|
|
var REJECTED = 2;
|
|
|
|
var GET_THEN_ERROR = new ErrorObject();
|
|
|
|
function selfFulfillment() {
|
|
return new TypeError("You cannot resolve a promise with itself");
|
|
}
|
|
|
|
function cannotReturnOwn() {
|
|
return new TypeError('A promises callback cannot return that same promise.');
|
|
}
|
|
|
|
function getThen(promise) {
|
|
try {
|
|
return promise.then;
|
|
} catch (error) {
|
|
GET_THEN_ERROR.error = error;
|
|
return GET_THEN_ERROR;
|
|
}
|
|
}
|
|
|
|
function tryThen(then, value, fulfillmentHandler, rejectionHandler) {
|
|
try {
|
|
then.call(value, fulfillmentHandler, rejectionHandler);
|
|
} catch (e) {
|
|
return e;
|
|
}
|
|
}
|
|
|
|
function handleForeignThenable(promise, thenable, then) {
|
|
asap(function (promise) {
|
|
var sealed = false;
|
|
var error = tryThen(then, thenable, function (value) {
|
|
if (sealed) {
|
|
return;
|
|
}
|
|
sealed = true;
|
|
if (thenable !== value) {
|
|
_resolve(promise, value);
|
|
} else {
|
|
fulfill(promise, value);
|
|
}
|
|
}, function (reason) {
|
|
if (sealed) {
|
|
return;
|
|
}
|
|
sealed = true;
|
|
|
|
_reject(promise, reason);
|
|
}, 'Settle: ' + (promise._label || ' unknown promise'));
|
|
|
|
if (!sealed && error) {
|
|
sealed = true;
|
|
_reject(promise, error);
|
|
}
|
|
}, promise);
|
|
}
|
|
|
|
function handleOwnThenable(promise, thenable) {
|
|
if (thenable._state === FULFILLED) {
|
|
fulfill(promise, thenable._result);
|
|
} else if (thenable._state === REJECTED) {
|
|
_reject(promise, thenable._result);
|
|
} else {
|
|
subscribe(thenable, undefined, function (value) {
|
|
return _resolve(promise, value);
|
|
}, function (reason) {
|
|
return _reject(promise, reason);
|
|
});
|
|
}
|
|
}
|
|
|
|
function handleMaybeThenable(promise, maybeThenable, then$$) {
|
|
if (maybeThenable.constructor === promise.constructor && then$$ === then && maybeThenable.constructor.resolve === resolve) {
|
|
handleOwnThenable(promise, maybeThenable);
|
|
} else {
|
|
if (then$$ === GET_THEN_ERROR) {
|
|
_reject(promise, GET_THEN_ERROR.error);
|
|
} else if (then$$ === undefined) {
|
|
fulfill(promise, maybeThenable);
|
|
} else if (isFunction(then$$)) {
|
|
handleForeignThenable(promise, maybeThenable, then$$);
|
|
} else {
|
|
fulfill(promise, maybeThenable);
|
|
}
|
|
}
|
|
}
|
|
|
|
function _resolve(promise, value) {
|
|
if (promise === value) {
|
|
_reject(promise, selfFulfillment());
|
|
} else if (objectOrFunction(value)) {
|
|
handleMaybeThenable(promise, value, getThen(value));
|
|
} else {
|
|
fulfill(promise, value);
|
|
}
|
|
}
|
|
|
|
function publishRejection(promise) {
|
|
if (promise._onerror) {
|
|
promise._onerror(promise._result);
|
|
}
|
|
|
|
publish(promise);
|
|
}
|
|
|
|
function fulfill(promise, value) {
|
|
if (promise._state !== PENDING) {
|
|
return;
|
|
}
|
|
|
|
promise._result = value;
|
|
promise._state = FULFILLED;
|
|
|
|
if (promise._subscribers.length !== 0) {
|
|
asap(publish, promise);
|
|
}
|
|
}
|
|
|
|
function _reject(promise, reason) {
|
|
if (promise._state !== PENDING) {
|
|
return;
|
|
}
|
|
promise._state = REJECTED;
|
|
promise._result = reason;
|
|
|
|
asap(publishRejection, promise);
|
|
}
|
|
|
|
function subscribe(parent, child, onFulfillment, onRejection) {
|
|
var _subscribers = parent._subscribers;
|
|
var length = _subscribers.length;
|
|
|
|
parent._onerror = null;
|
|
|
|
_subscribers[length] = child;
|
|
_subscribers[length + FULFILLED] = onFulfillment;
|
|
_subscribers[length + REJECTED] = onRejection;
|
|
|
|
if (length === 0 && parent._state) {
|
|
asap(publish, parent);
|
|
}
|
|
}
|
|
|
|
function publish(promise) {
|
|
var subscribers = promise._subscribers;
|
|
var settled = promise._state;
|
|
|
|
if (subscribers.length === 0) {
|
|
return;
|
|
}
|
|
|
|
var child = undefined,
|
|
callback = undefined,
|
|
detail = promise._result;
|
|
|
|
for (var i = 0; i < subscribers.length; i += 3) {
|
|
child = subscribers[i];
|
|
callback = subscribers[i + settled];
|
|
|
|
if (child) {
|
|
invokeCallback(settled, child, callback, detail);
|
|
} else {
|
|
callback(detail);
|
|
}
|
|
}
|
|
|
|
promise._subscribers.length = 0;
|
|
}
|
|
|
|
function ErrorObject() {
|
|
this.error = null;
|
|
}
|
|
|
|
var TRY_CATCH_ERROR = new ErrorObject();
|
|
|
|
function tryCatch(callback, detail) {
|
|
try {
|
|
return callback(detail);
|
|
} catch (e) {
|
|
TRY_CATCH_ERROR.error = e;
|
|
return TRY_CATCH_ERROR;
|
|
}
|
|
}
|
|
|
|
function invokeCallback(settled, promise, callback, detail) {
|
|
var hasCallback = isFunction(callback),
|
|
value = undefined,
|
|
error = undefined,
|
|
succeeded = undefined,
|
|
failed = undefined;
|
|
|
|
if (hasCallback) {
|
|
value = tryCatch(callback, detail);
|
|
|
|
if (value === TRY_CATCH_ERROR) {
|
|
failed = true;
|
|
error = value.error;
|
|
value = null;
|
|
} else {
|
|
succeeded = true;
|
|
}
|
|
|
|
if (promise === value) {
|
|
_reject(promise, cannotReturnOwn());
|
|
return;
|
|
}
|
|
} else {
|
|
value = detail;
|
|
succeeded = true;
|
|
}
|
|
|
|
if (promise._state !== PENDING) {
|
|
// noop
|
|
} else if (hasCallback && succeeded) {
|
|
_resolve(promise, value);
|
|
} else if (failed) {
|
|
_reject(promise, error);
|
|
} else if (settled === FULFILLED) {
|
|
fulfill(promise, value);
|
|
} else if (settled === REJECTED) {
|
|
_reject(promise, value);
|
|
}
|
|
}
|
|
|
|
function initializePromise(promise, resolver) {
|
|
try {
|
|
resolver(function resolvePromise(value) {
|
|
_resolve(promise, value);
|
|
}, function rejectPromise(reason) {
|
|
_reject(promise, reason);
|
|
});
|
|
} catch (e) {
|
|
_reject(promise, e);
|
|
}
|
|
}
|
|
|
|
var id = 0;
|
|
function nextId() {
|
|
return id++;
|
|
}
|
|
|
|
function makePromise(promise) {
|
|
promise[PROMISE_ID] = id++;
|
|
promise._state = undefined;
|
|
promise._result = undefined;
|
|
promise._subscribers = [];
|
|
}
|
|
|
|
function Enumerator(Constructor, input) {
|
|
this._instanceConstructor = Constructor;
|
|
this.promise = new Constructor(noop);
|
|
|
|
if (!this.promise[PROMISE_ID]) {
|
|
makePromise(this.promise);
|
|
}
|
|
|
|
if (isArray(input)) {
|
|
this._input = input;
|
|
this.length = input.length;
|
|
this._remaining = input.length;
|
|
|
|
this._result = new Array(this.length);
|
|
|
|
if (this.length === 0) {
|
|
fulfill(this.promise, this._result);
|
|
} else {
|
|
this.length = this.length || 0;
|
|
this._enumerate();
|
|
if (this._remaining === 0) {
|
|
fulfill(this.promise, this._result);
|
|
}
|
|
}
|
|
} else {
|
|
_reject(this.promise, validationError());
|
|
}
|
|
}
|
|
|
|
function validationError() {
|
|
return new Error('Array Methods must be provided an Array');
|
|
};
|
|
|
|
Enumerator.prototype._enumerate = function () {
|
|
var length = this.length;
|
|
var _input = this._input;
|
|
|
|
for (var i = 0; this._state === PENDING && i < length; i++) {
|
|
this._eachEntry(_input[i], i);
|
|
}
|
|
};
|
|
|
|
Enumerator.prototype._eachEntry = function (entry, i) {
|
|
var c = this._instanceConstructor;
|
|
var resolve$$ = c.resolve;
|
|
|
|
if (resolve$$ === resolve) {
|
|
var _then = getThen(entry);
|
|
|
|
if (_then === then && entry._state !== PENDING) {
|
|
this._settledAt(entry._state, i, entry._result);
|
|
} else if (typeof _then !== 'function') {
|
|
this._remaining--;
|
|
this._result[i] = entry;
|
|
} else if (c === Promise) {
|
|
var promise = new c(noop);
|
|
handleMaybeThenable(promise, entry, _then);
|
|
this._willSettleAt(promise, i);
|
|
} else {
|
|
this._willSettleAt(new c(function (resolve$$) {
|
|
return resolve$$(entry);
|
|
}), i);
|
|
}
|
|
} else {
|
|
this._willSettleAt(resolve$$(entry), i);
|
|
}
|
|
};
|
|
|
|
Enumerator.prototype._settledAt = function (state, i, value) {
|
|
var promise = this.promise;
|
|
|
|
if (promise._state === PENDING) {
|
|
this._remaining--;
|
|
|
|
if (state === REJECTED) {
|
|
_reject(promise, value);
|
|
} else {
|
|
this._result[i] = value;
|
|
}
|
|
}
|
|
|
|
if (this._remaining === 0) {
|
|
fulfill(promise, this._result);
|
|
}
|
|
};
|
|
|
|
Enumerator.prototype._willSettleAt = function (promise, i) {
|
|
var enumerator = this;
|
|
|
|
subscribe(promise, undefined, function (value) {
|
|
return enumerator._settledAt(FULFILLED, i, value);
|
|
}, function (reason) {
|
|
return enumerator._settledAt(REJECTED, i, reason);
|
|
});
|
|
};
|
|
|
|
/**
|
|
`Promise.all` accepts an array of promises, and returns a new promise which
|
|
is fulfilled with an array of fulfillment values for the passed promises, or
|
|
rejected with the reason of the first passed promise to be rejected. It casts all
|
|
elements of the passed iterable to promises as it runs this algorithm.
|
|
|
|
Example:
|
|
|
|
```javascript
|
|
let promise1 = resolve(1);
|
|
let promise2 = resolve(2);
|
|
let promise3 = resolve(3);
|
|
let promises = [ promise1, promise2, promise3 ];
|
|
|
|
Promise.all(promises).then(function(array){
|
|
// The array here would be [ 1, 2, 3 ];
|
|
});
|
|
```
|
|
|
|
If any of the `promises` given to `all` are rejected, the first promise
|
|
that is rejected will be given as an argument to the returned promises's
|
|
rejection handler. For example:
|
|
|
|
Example:
|
|
|
|
```javascript
|
|
let promise1 = resolve(1);
|
|
let promise2 = reject(new Error("2"));
|
|
let promise3 = reject(new Error("3"));
|
|
let promises = [ promise1, promise2, promise3 ];
|
|
|
|
Promise.all(promises).then(function(array){
|
|
// Code here never runs because there are rejected promises!
|
|
}, function(error) {
|
|
// error.message === "2"
|
|
});
|
|
```
|
|
|
|
@method all
|
|
@static
|
|
@param {Array} entries array of promises
|
|
@param {String} label optional string for labeling the promise.
|
|
Useful for tooling.
|
|
@return {Promise} promise that is fulfilled when all `promises` have been
|
|
fulfilled, or rejected if any of them become rejected.
|
|
@static
|
|
*/
|
|
function all(entries) {
|
|
return new Enumerator(this, entries).promise;
|
|
}
|
|
|
|
/**
|
|
`Promise.race` returns a new promise which is settled in the same way as the
|
|
first passed promise to settle.
|
|
|
|
Example:
|
|
|
|
```javascript
|
|
let promise1 = new Promise(function(resolve, reject){
|
|
setTimeout(function(){
|
|
resolve('promise 1');
|
|
}, 200);
|
|
});
|
|
|
|
let promise2 = new Promise(function(resolve, reject){
|
|
setTimeout(function(){
|
|
resolve('promise 2');
|
|
}, 100);
|
|
});
|
|
|
|
Promise.race([promise1, promise2]).then(function(result){
|
|
// result === 'promise 2' because it was resolved before promise1
|
|
// was resolved.
|
|
});
|
|
```
|
|
|
|
`Promise.race` is deterministic in that only the state of the first
|
|
settled promise matters. For example, even if other promises given to the
|
|
`promises` array argument are resolved, but the first settled promise has
|
|
become rejected before the other promises became fulfilled, the returned
|
|
promise will become rejected:
|
|
|
|
```javascript
|
|
let promise1 = new Promise(function(resolve, reject){
|
|
setTimeout(function(){
|
|
resolve('promise 1');
|
|
}, 200);
|
|
});
|
|
|
|
let promise2 = new Promise(function(resolve, reject){
|
|
setTimeout(function(){
|
|
reject(new Error('promise 2'));
|
|
}, 100);
|
|
});
|
|
|
|
Promise.race([promise1, promise2]).then(function(result){
|
|
// Code here never runs
|
|
}, function(reason){
|
|
// reason.message === 'promise 2' because promise 2 became rejected before
|
|
// promise 1 became fulfilled
|
|
});
|
|
```
|
|
|
|
An example real-world use case is implementing timeouts:
|
|
|
|
```javascript
|
|
Promise.race([ajax('foo.json'), timeout(5000)])
|
|
```
|
|
|
|
@method race
|
|
@static
|
|
@param {Array} promises array of promises to observe
|
|
Useful for tooling.
|
|
@return {Promise} a promise which settles in the same way as the first passed
|
|
promise to settle.
|
|
*/
|
|
function race(entries) {
|
|
/*jshint validthis:true */
|
|
var Constructor = this;
|
|
|
|
if (!isArray(entries)) {
|
|
return new Constructor(function (_, reject) {
|
|
return reject(new TypeError('You must pass an array to race.'));
|
|
});
|
|
} else {
|
|
return new Constructor(function (resolve, reject) {
|
|
var length = entries.length;
|
|
for (var i = 0; i < length; i++) {
|
|
Constructor.resolve(entries[i]).then(resolve, reject);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
`Promise.reject` returns a promise rejected with the passed `reason`.
|
|
It is shorthand for the following:
|
|
|
|
```javascript
|
|
let promise = new Promise(function(resolve, reject){
|
|
reject(new Error('WHOOPS'));
|
|
});
|
|
|
|
promise.then(function(value){
|
|
// Code here doesn't run because the promise is rejected!
|
|
}, function(reason){
|
|
// reason.message === 'WHOOPS'
|
|
});
|
|
```
|
|
|
|
Instead of writing the above, your code now simply becomes the following:
|
|
|
|
```javascript
|
|
let promise = Promise.reject(new Error('WHOOPS'));
|
|
|
|
promise.then(function(value){
|
|
// Code here doesn't run because the promise is rejected!
|
|
}, function(reason){
|
|
// reason.message === 'WHOOPS'
|
|
});
|
|
```
|
|
|
|
@method reject
|
|
@static
|
|
@param {Any} reason value that the returned promise will be rejected with.
|
|
Useful for tooling.
|
|
@return {Promise} a promise rejected with the given `reason`.
|
|
*/
|
|
function reject(reason) {
|
|
/*jshint validthis:true */
|
|
var Constructor = this;
|
|
var promise = new Constructor(noop);
|
|
_reject(promise, reason);
|
|
return promise;
|
|
}
|
|
|
|
function needsResolver() {
|
|
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
|
|
}
|
|
|
|
function needsNew() {
|
|
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
|
|
}
|
|
|
|
/**
|
|
Promise objects represent the eventual result of an asynchronous operation. The
|
|
primary way of interacting with a promise is through its `then` method, which
|
|
registers callbacks to receive either a promise's eventual value or the reason
|
|
why the promise cannot be fulfilled.
|
|
|
|
Terminology
|
|
-----------
|
|
|
|
- `promise` is an object or function with a `then` method whose behavior conforms to this specification.
|
|
- `thenable` is an object or function that defines a `then` method.
|
|
- `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
|
|
- `exception` is a value that is thrown using the throw statement.
|
|
- `reason` is a value that indicates why a promise was rejected.
|
|
- `settled` the final resting state of a promise, fulfilled or rejected.
|
|
|
|
A promise can be in one of three states: pending, fulfilled, or rejected.
|
|
|
|
Promises that are fulfilled have a fulfillment value and are in the fulfilled
|
|
state. Promises that are rejected have a rejection reason and are in the
|
|
rejected state. A fulfillment value is never a thenable.
|
|
|
|
Promises can also be said to *resolve* a value. If this value is also a
|
|
promise, then the original promise's settled state will match the value's
|
|
settled state. So a promise that *resolves* a promise that rejects will
|
|
itself reject, and a promise that *resolves* a promise that fulfills will
|
|
itself fulfill.
|
|
|
|
|
|
Basic Usage:
|
|
------------
|
|
|
|
```js
|
|
let promise = new Promise(function(resolve, reject) {
|
|
// on success
|
|
resolve(value);
|
|
|
|
// on failure
|
|
reject(reason);
|
|
});
|
|
|
|
promise.then(function(value) {
|
|
// on fulfillment
|
|
}, function(reason) {
|
|
// on rejection
|
|
});
|
|
```
|
|
|
|
Advanced Usage:
|
|
---------------
|
|
|
|
Promises shine when abstracting away asynchronous interactions such as
|
|
`XMLHttpRequest`s.
|
|
|
|
```js
|
|
function getJSON(url) {
|
|
return new Promise(function(resolve, reject){
|
|
let xhr = new XMLHttpRequest();
|
|
|
|
xhr.open('GET', url);
|
|
xhr.onreadystatechange = handler;
|
|
xhr.responseType = 'json';
|
|
xhr.setRequestHeader('Accept', 'application/json');
|
|
xhr.send();
|
|
|
|
function handler() {
|
|
if (this.readyState === this.DONE) {
|
|
if (this.status === 200) {
|
|
resolve(this.response);
|
|
} else {
|
|
reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
|
|
}
|
|
}
|
|
};
|
|
});
|
|
}
|
|
|
|
getJSON('/posts.json').then(function(json) {
|
|
// on fulfillment
|
|
}, function(reason) {
|
|
// on rejection
|
|
});
|
|
```
|
|
|
|
Unlike callbacks, promises are great composable primitives.
|
|
|
|
```js
|
|
Promise.all([
|
|
getJSON('/posts'),
|
|
getJSON('/comments')
|
|
]).then(function(values){
|
|
values[0] // => postsJSON
|
|
values[1] // => commentsJSON
|
|
|
|
return values;
|
|
});
|
|
```
|
|
|
|
@class Promise
|
|
@param {function} resolver
|
|
Useful for tooling.
|
|
@constructor
|
|
*/
|
|
function Promise(resolver) {
|
|
this[PROMISE_ID] = nextId();
|
|
this._result = this._state = undefined;
|
|
this._subscribers = [];
|
|
|
|
if (noop !== resolver) {
|
|
typeof resolver !== 'function' && needsResolver();
|
|
this instanceof Promise ? initializePromise(this, resolver) : needsNew();
|
|
}
|
|
}
|
|
|
|
Promise.all = all;
|
|
Promise.race = race;
|
|
Promise.resolve = resolve;
|
|
Promise.reject = reject;
|
|
Promise._setScheduler = setScheduler;
|
|
Promise._setAsap = setAsap;
|
|
Promise._asap = asap;
|
|
|
|
Promise.prototype = {
|
|
constructor: Promise,
|
|
|
|
/**
|
|
The primary way of interacting with a promise is through its `then` method,
|
|
which registers callbacks to receive either a promise's eventual value or the
|
|
reason why the promise cannot be fulfilled.
|
|
|
|
```js
|
|
findUser().then(function(user){
|
|
// user is available
|
|
}, function(reason){
|
|
// user is unavailable, and you are given the reason why
|
|
});
|
|
```
|
|
|
|
Chaining
|
|
--------
|
|
|
|
The return value of `then` is itself a promise. This second, 'downstream'
|
|
promise is resolved with the return value of the first promise's fulfillment
|
|
or rejection handler, or rejected if the handler throws an exception.
|
|
|
|
```js
|
|
findUser().then(function (user) {
|
|
return user.name;
|
|
}, function (reason) {
|
|
return 'default name';
|
|
}).then(function (userName) {
|
|
// If `findUser` fulfilled, `userName` will be the user's name, otherwise it
|
|
// will be `'default name'`
|
|
});
|
|
|
|
findUser().then(function (user) {
|
|
throw new Error('Found user, but still unhappy');
|
|
}, function (reason) {
|
|
throw new Error('`findUser` rejected and we're unhappy');
|
|
}).then(function (value) {
|
|
// never reached
|
|
}, function (reason) {
|
|
// if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
|
|
// If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
|
|
});
|
|
```
|
|
If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
|
|
|
|
```js
|
|
findUser().then(function (user) {
|
|
throw new PedagogicalException('Upstream error');
|
|
}).then(function (value) {
|
|
// never reached
|
|
}).then(function (value) {
|
|
// never reached
|
|
}, function (reason) {
|
|
// The `PedgagocialException` is propagated all the way down to here
|
|
});
|
|
```
|
|
|
|
Assimilation
|
|
------------
|
|
|
|
Sometimes the value you want to propagate to a downstream promise can only be
|
|
retrieved asynchronously. This can be achieved by returning a promise in the
|
|
fulfillment or rejection handler. The downstream promise will then be pending
|
|
until the returned promise is settled. This is called *assimilation*.
|
|
|
|
```js
|
|
findUser().then(function (user) {
|
|
return findCommentsByAuthor(user);
|
|
}).then(function (comments) {
|
|
// The user's comments are now available
|
|
});
|
|
```
|
|
|
|
If the assimliated promise rejects, then the downstream promise will also reject.
|
|
|
|
```js
|
|
findUser().then(function (user) {
|
|
return findCommentsByAuthor(user);
|
|
}).then(function (comments) {
|
|
// If `findCommentsByAuthor` fulfills, we'll have the value here
|
|
}, function (reason) {
|
|
// If `findCommentsByAuthor` rejects, we'll have the reason here
|
|
});
|
|
```
|
|
|
|
Simple Example
|
|
--------------
|
|
|
|
Synchronous Example
|
|
|
|
```javascript
|
|
let result;
|
|
|
|
try {
|
|
result = findResult();
|
|
// success
|
|
} catch(reason) {
|
|
// failure
|
|
}
|
|
```
|
|
|
|
Errback Example
|
|
|
|
```js
|
|
findResult(function(result, err){
|
|
if (err) {
|
|
// failure
|
|
} else {
|
|
// success
|
|
}
|
|
});
|
|
```
|
|
|
|
Promise Example;
|
|
|
|
```javascript
|
|
findResult().then(function(result){
|
|
// success
|
|
}, function(reason){
|
|
// failure
|
|
});
|
|
```
|
|
|
|
Advanced Example
|
|
--------------
|
|
|
|
Synchronous Example
|
|
|
|
```javascript
|
|
let author, books;
|
|
|
|
try {
|
|
author = findAuthor();
|
|
books = findBooksByAuthor(author);
|
|
// success
|
|
} catch(reason) {
|
|
// failure
|
|
}
|
|
```
|
|
|
|
Errback Example
|
|
|
|
```js
|
|
|
|
function foundBooks(books) {
|
|
|
|
}
|
|
|
|
function failure(reason) {
|
|
|
|
}
|
|
|
|
findAuthor(function(author, err){
|
|
if (err) {
|
|
failure(err);
|
|
// failure
|
|
} else {
|
|
try {
|
|
findBoooksByAuthor(author, function(books, err) {
|
|
if (err) {
|
|
failure(err);
|
|
} else {
|
|
try {
|
|
foundBooks(books);
|
|
} catch(reason) {
|
|
failure(reason);
|
|
}
|
|
}
|
|
});
|
|
} catch(error) {
|
|
failure(err);
|
|
}
|
|
// success
|
|
}
|
|
});
|
|
```
|
|
|
|
Promise Example;
|
|
|
|
```javascript
|
|
findAuthor().
|
|
then(findBooksByAuthor).
|
|
then(function(books){
|
|
// found books
|
|
}).catch(function(reason){
|
|
// something went wrong
|
|
});
|
|
```
|
|
|
|
@method then
|
|
@param {Function} onFulfilled
|
|
@param {Function} onRejected
|
|
Useful for tooling.
|
|
@return {Promise}
|
|
*/
|
|
then: then,
|
|
|
|
/**
|
|
`catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
|
|
as the catch block of a try/catch statement.
|
|
|
|
```js
|
|
function findAuthor(){
|
|
throw new Error('couldn't find that author');
|
|
}
|
|
|
|
// synchronous
|
|
try {
|
|
findAuthor();
|
|
} catch(reason) {
|
|
// something went wrong
|
|
}
|
|
|
|
// async with promises
|
|
findAuthor().catch(function(reason){
|
|
// something went wrong
|
|
});
|
|
```
|
|
|
|
@method catch
|
|
@param {Function} onRejection
|
|
Useful for tooling.
|
|
@return {Promise}
|
|
*/
|
|
'catch': function _catch(onRejection) {
|
|
return this.then(null, onRejection);
|
|
}
|
|
};
|
|
|
|
function polyfill() {
|
|
var local = undefined;
|
|
|
|
if (typeof global !== 'undefined') {
|
|
local = global;
|
|
} else if (typeof self !== 'undefined') {
|
|
local = self;
|
|
} else {
|
|
try {
|
|
local = Function('return this')();
|
|
} catch (e) {
|
|
throw new Error('polyfill failed because global object is unavailable in this environment');
|
|
}
|
|
}
|
|
|
|
var P = local.Promise;
|
|
|
|
if (P) {
|
|
var promiseToString = null;
|
|
try {
|
|
promiseToString = Object.prototype.toString.call(P.resolve());
|
|
} catch (e) {
|
|
// silently ignored
|
|
}
|
|
|
|
if (promiseToString === '[object Promise]' && !P.cast) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
local.Promise = Promise;
|
|
}
|
|
|
|
polyfill();
|
|
// Strange compat..
|
|
Promise.polyfill = polyfill;
|
|
Promise.Promise = Promise;
|
|
|
|
return Promise;
|
|
|
|
})));
|
|
|
|
}).call(this,_dereq_('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
},{"_process":4}],3:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var has = Object.prototype.hasOwnProperty;
|
|
|
|
//
|
|
// We store our EE objects in a plain object whose properties are event names.
|
|
// If `Object.create(null)` is not supported we prefix the event names with a
|
|
// `~` to make sure that the built-in object properties are not overridden or
|
|
// used as an attack vector.
|
|
// We also assume that `Object.create(null)` is available when the event name
|
|
// is an ES6 Symbol.
|
|
//
|
|
var prefix = typeof Object.create !== 'function' ? '~' : false;
|
|
|
|
/**
|
|
* Representation of a single EventEmitter function.
|
|
*
|
|
* @param {Function} fn Event handler to be called.
|
|
* @param {Mixed} context Context for function execution.
|
|
* @param {Boolean} [once=false] Only emit once
|
|
* @api private
|
|
*/
|
|
function EE(fn, context, once) {
|
|
this.fn = fn;
|
|
this.context = context;
|
|
this.once = once || false;
|
|
}
|
|
|
|
/**
|
|
* Minimal EventEmitter interface that is molded against the Node.js
|
|
* EventEmitter interface.
|
|
*
|
|
* @constructor
|
|
* @api public
|
|
*/
|
|
function EventEmitter() { /* Nothing to set */ }
|
|
|
|
/**
|
|
* Hold the assigned EventEmitters by name.
|
|
*
|
|
* @type {Object}
|
|
* @private
|
|
*/
|
|
EventEmitter.prototype._events = undefined;
|
|
|
|
/**
|
|
* Return an array listing the events for which the emitter has registered
|
|
* listeners.
|
|
*
|
|
* @returns {Array}
|
|
* @api public
|
|
*/
|
|
EventEmitter.prototype.eventNames = function eventNames() {
|
|
var events = this._events
|
|
, names = []
|
|
, name;
|
|
|
|
if (!events) return names;
|
|
|
|
for (name in events) {
|
|
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
|
|
}
|
|
|
|
if (Object.getOwnPropertySymbols) {
|
|
return names.concat(Object.getOwnPropertySymbols(events));
|
|
}
|
|
|
|
return names;
|
|
};
|
|
|
|
/**
|
|
* Return a list of assigned event listeners.
|
|
*
|
|
* @param {String} event The events that should be listed.
|
|
* @param {Boolean} exists We only need to know if there are listeners.
|
|
* @returns {Array|Boolean}
|
|
* @api public
|
|
*/
|
|
EventEmitter.prototype.listeners = function listeners(event, exists) {
|
|
var evt = prefix ? prefix + event : event
|
|
, available = this._events && this._events[evt];
|
|
|
|
if (exists) return !!available;
|
|
if (!available) return [];
|
|
if (available.fn) return [available.fn];
|
|
|
|
for (var i = 0, l = available.length, ee = new Array(l); i < l; i++) {
|
|
ee[i] = available[i].fn;
|
|
}
|
|
|
|
return ee;
|
|
};
|
|
|
|
/**
|
|
* Emit an event to all registered event listeners.
|
|
*
|
|
* @param {String} event The name of the event.
|
|
* @returns {Boolean} Indication if we've emitted an event.
|
|
* @api public
|
|
*/
|
|
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
|
|
var evt = prefix ? prefix + event : event;
|
|
|
|
if (!this._events || !this._events[evt]) return false;
|
|
|
|
var listeners = this._events[evt]
|
|
, len = arguments.length
|
|
, args
|
|
, i;
|
|
|
|
if ('function' === typeof listeners.fn) {
|
|
if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
|
|
|
|
switch (len) {
|
|
case 1: return listeners.fn.call(listeners.context), true;
|
|
case 2: return listeners.fn.call(listeners.context, a1), true;
|
|
case 3: return listeners.fn.call(listeners.context, a1, a2), true;
|
|
case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
|
|
case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
|
|
case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
|
|
}
|
|
|
|
for (i = 1, args = new Array(len -1); i < len; i++) {
|
|
args[i - 1] = arguments[i];
|
|
}
|
|
|
|
listeners.fn.apply(listeners.context, args);
|
|
} else {
|
|
var length = listeners.length
|
|
, j;
|
|
|
|
for (i = 0; i < length; i++) {
|
|
if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
|
|
|
|
switch (len) {
|
|
case 1: listeners[i].fn.call(listeners[i].context); break;
|
|
case 2: listeners[i].fn.call(listeners[i].context, a1); break;
|
|
case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
|
|
default:
|
|
if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
|
|
args[j - 1] = arguments[j];
|
|
}
|
|
|
|
listeners[i].fn.apply(listeners[i].context, args);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* Register a new EventListener for the given event.
|
|
*
|
|
* @param {String} event Name of the event.
|
|
* @param {Function} fn Callback function.
|
|
* @param {Mixed} [context=this] The context of the function.
|
|
* @api public
|
|
*/
|
|
EventEmitter.prototype.on = function on(event, fn, context) {
|
|
var listener = new EE(fn, context || this)
|
|
, evt = prefix ? prefix + event : event;
|
|
|
|
if (!this._events) this._events = prefix ? {} : Object.create(null);
|
|
if (!this._events[evt]) this._events[evt] = listener;
|
|
else {
|
|
if (!this._events[evt].fn) this._events[evt].push(listener);
|
|
else this._events[evt] = [
|
|
this._events[evt], listener
|
|
];
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Add an EventListener that's only called once.
|
|
*
|
|
* @param {String} event Name of the event.
|
|
* @param {Function} fn Callback function.
|
|
* @param {Mixed} [context=this] The context of the function.
|
|
* @api public
|
|
*/
|
|
EventEmitter.prototype.once = function once(event, fn, context) {
|
|
var listener = new EE(fn, context || this, true)
|
|
, evt = prefix ? prefix + event : event;
|
|
|
|
if (!this._events) this._events = prefix ? {} : Object.create(null);
|
|
if (!this._events[evt]) this._events[evt] = listener;
|
|
else {
|
|
if (!this._events[evt].fn) this._events[evt].push(listener);
|
|
else this._events[evt] = [
|
|
this._events[evt], listener
|
|
];
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Remove event listeners.
|
|
*
|
|
* @param {String} event The event we want to remove.
|
|
* @param {Function} fn The listener that we need to find.
|
|
* @param {Mixed} context Only remove listeners matching this context.
|
|
* @param {Boolean} once Only remove once listeners.
|
|
* @api public
|
|
*/
|
|
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
|
|
var evt = prefix ? prefix + event : event;
|
|
|
|
if (!this._events || !this._events[evt]) return this;
|
|
|
|
var listeners = this._events[evt]
|
|
, events = [];
|
|
|
|
if (fn) {
|
|
if (listeners.fn) {
|
|
if (
|
|
listeners.fn !== fn
|
|
|| (once && !listeners.once)
|
|
|| (context && listeners.context !== context)
|
|
) {
|
|
events.push(listeners);
|
|
}
|
|
} else {
|
|
for (var i = 0, length = listeners.length; i < length; i++) {
|
|
if (
|
|
listeners[i].fn !== fn
|
|
|| (once && !listeners[i].once)
|
|
|| (context && listeners[i].context !== context)
|
|
) {
|
|
events.push(listeners[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Reset the array, or remove it completely if we have no more listeners.
|
|
//
|
|
if (events.length) {
|
|
this._events[evt] = events.length === 1 ? events[0] : events;
|
|
} else {
|
|
delete this._events[evt];
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Remove all listeners or only the listeners for the specified event.
|
|
*
|
|
* @param {String} event The event want to remove all listeners for.
|
|
* @api public
|
|
*/
|
|
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
|
|
if (!this._events) return this;
|
|
|
|
if (event) delete this._events[prefix ? prefix + event : event];
|
|
else this._events = prefix ? {} : Object.create(null);
|
|
|
|
return this;
|
|
};
|
|
|
|
//
|
|
// Alias methods names because people roll like that.
|
|
//
|
|
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
|
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
|
|
|
|
//
|
|
// This function doesn't apply anymore.
|
|
//
|
|
EventEmitter.prototype.setMaxListeners = function setMaxListeners() {
|
|
return this;
|
|
};
|
|
|
|
//
|
|
// Expose the prefix.
|
|
//
|
|
EventEmitter.prefixed = prefix;
|
|
|
|
//
|
|
// Expose the module.
|
|
//
|
|
if ('undefined' !== typeof module) {
|
|
module.exports = EventEmitter;
|
|
}
|
|
|
|
},{}],4:[function(_dereq_,module,exports){
|
|
// shim for using process in browser
|
|
var process = module.exports = {};
|
|
|
|
// cached from whatever global is present so that test runners that stub it
|
|
// don't break things. But we need to wrap it in a try catch in case it is
|
|
// wrapped in strict mode code which doesn't define any globals. It's inside a
|
|
// function because try/catches deoptimize in certain engines.
|
|
|
|
var cachedSetTimeout;
|
|
var cachedClearTimeout;
|
|
|
|
function defaultSetTimout() {
|
|
throw new Error('setTimeout has not been defined');
|
|
}
|
|
function defaultClearTimeout () {
|
|
throw new Error('clearTimeout has not been defined');
|
|
}
|
|
(function () {
|
|
try {
|
|
if (typeof setTimeout === 'function') {
|
|
cachedSetTimeout = setTimeout;
|
|
} else {
|
|
cachedSetTimeout = defaultSetTimout;
|
|
}
|
|
} catch (e) {
|
|
cachedSetTimeout = defaultSetTimout;
|
|
}
|
|
try {
|
|
if (typeof clearTimeout === 'function') {
|
|
cachedClearTimeout = clearTimeout;
|
|
} else {
|
|
cachedClearTimeout = defaultClearTimeout;
|
|
}
|
|
} catch (e) {
|
|
cachedClearTimeout = defaultClearTimeout;
|
|
}
|
|
} ())
|
|
function runTimeout(fun) {
|
|
if (cachedSetTimeout === setTimeout) {
|
|
//normal enviroments in sane situations
|
|
return setTimeout(fun, 0);
|
|
}
|
|
// if setTimeout wasn't available but was latter defined
|
|
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
|
|
cachedSetTimeout = setTimeout;
|
|
return setTimeout(fun, 0);
|
|
}
|
|
try {
|
|
// when when somebody has screwed with setTimeout but no I.E. maddness
|
|
return cachedSetTimeout(fun, 0);
|
|
} catch(e){
|
|
try {
|
|
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
|
return cachedSetTimeout.call(null, fun, 0);
|
|
} catch(e){
|
|
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
|
|
return cachedSetTimeout.call(this, fun, 0);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
function runClearTimeout(marker) {
|
|
if (cachedClearTimeout === clearTimeout) {
|
|
//normal enviroments in sane situations
|
|
return clearTimeout(marker);
|
|
}
|
|
// if clearTimeout wasn't available but was latter defined
|
|
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
|
|
cachedClearTimeout = clearTimeout;
|
|
return clearTimeout(marker);
|
|
}
|
|
try {
|
|
// when when somebody has screwed with setTimeout but no I.E. maddness
|
|
return cachedClearTimeout(marker);
|
|
} catch (e){
|
|
try {
|
|
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
|
return cachedClearTimeout.call(null, marker);
|
|
} catch (e){
|
|
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
|
|
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
|
|
return cachedClearTimeout.call(this, marker);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
var queue = [];
|
|
var draining = false;
|
|
var currentQueue;
|
|
var queueIndex = -1;
|
|
|
|
function cleanUpNextTick() {
|
|
if (!draining || !currentQueue) {
|
|
return;
|
|
}
|
|
draining = false;
|
|
if (currentQueue.length) {
|
|
queue = currentQueue.concat(queue);
|
|
} else {
|
|
queueIndex = -1;
|
|
}
|
|
if (queue.length) {
|
|
drainQueue();
|
|
}
|
|
}
|
|
|
|
function drainQueue() {
|
|
if (draining) {
|
|
return;
|
|
}
|
|
var timeout = runTimeout(cleanUpNextTick);
|
|
draining = true;
|
|
|
|
var len = queue.length;
|
|
while(len) {
|
|
currentQueue = queue;
|
|
queue = [];
|
|
while (++queueIndex < len) {
|
|
if (currentQueue) {
|
|
currentQueue[queueIndex].run();
|
|
}
|
|
}
|
|
queueIndex = -1;
|
|
len = queue.length;
|
|
}
|
|
currentQueue = null;
|
|
draining = false;
|
|
runClearTimeout(timeout);
|
|
}
|
|
|
|
process.nextTick = function (fun) {
|
|
var args = new Array(arguments.length - 1);
|
|
if (arguments.length > 1) {
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
args[i - 1] = arguments[i];
|
|
}
|
|
}
|
|
queue.push(new Item(fun, args));
|
|
if (queue.length === 1 && !draining) {
|
|
runTimeout(drainQueue);
|
|
}
|
|
};
|
|
|
|
// v8 likes predictible objects
|
|
function Item(fun, array) {
|
|
this.fun = fun;
|
|
this.array = array;
|
|
}
|
|
Item.prototype.run = function () {
|
|
this.fun.apply(null, this.array);
|
|
};
|
|
process.title = 'browser';
|
|
process.browser = true;
|
|
process.env = {};
|
|
process.argv = [];
|
|
process.version = ''; // empty string to avoid regexp issues
|
|
process.versions = {};
|
|
|
|
function noop() {}
|
|
|
|
process.on = noop;
|
|
process.addListener = noop;
|
|
process.once = noop;
|
|
process.off = noop;
|
|
process.removeListener = noop;
|
|
process.removeAllListeners = noop;
|
|
process.emit = noop;
|
|
process.prependListener = noop;
|
|
process.prependOnceListener = noop;
|
|
|
|
process.listeners = function (name) { return [] }
|
|
|
|
process.binding = function (name) {
|
|
throw new Error('process.binding is not supported');
|
|
};
|
|
|
|
process.cwd = function () { return '/' };
|
|
process.chdir = function (dir) {
|
|
throw new Error('process.chdir is not supported');
|
|
};
|
|
process.umask = function() { return 0; };
|
|
|
|
},{}],5:[function(_dereq_,module,exports){
|
|
(function(){var g={};
|
|
(function(window){var k,aa=this;aa.we=!0;function n(a,b){var c=a.split("."),d=aa;c[0]in d||!d.execScript||d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||void 0===b?d[e]?d=d[e]:d=d[e]={}:d[e]=b}function ba(a){var b=p;function c(){}c.prototype=b.prototype;a.Be=b.prototype;a.prototype=new c;a.prototype.constructor=a;a.ye=function(a,c,f){return b.prototype[c].apply(a,Array.prototype.slice.call(arguments,2))}};/*
|
|
|
|
Copyright 2016 Google Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
function ca(a){this.c=Math.exp(Math.log(.5)/a);this.b=this.a=0}function da(a,b,c){var d=Math.pow(a.c,b);c=c*(1-d)+d*a.a;isNaN(c)||(a.a=c,a.b+=b)}function ea(a){return a.a/(1-Math.pow(a.c,a.b))};function fa(){this.c=new ca(2);this.f=new ca(5);this.a=0;this.b=5E5}fa.prototype.setDefaultEstimate=function(a){this.b=a};fa.prototype.getBandwidthEstimate=function(){return 128E3>this.a?this.b:Math.min(ea(this.c),ea(this.f))};function ga(){};function t(a,b,c,d){this.severity=a;this.category=b;this.code=c;this.data=Array.prototype.slice.call(arguments,3)}n("shaka.util.Error",t);t.prototype.toString=function(){return"shaka.util.Error "+JSON.stringify(this,null," ")};t.Severity={RECOVERABLE:1,CRITICAL:2};t.Category={NETWORK:1,TEXT:2,MEDIA:3,MANIFEST:4,STREAMING:5,DRM:6,PLAYER:7,CAST:8,STORAGE:9};
|
|
t.Code={UNSUPPORTED_SCHEME:1E3,BAD_HTTP_STATUS:1001,HTTP_ERROR:1002,TIMEOUT:1003,MALFORMED_DATA_URI:1004,UNKNOWN_DATA_URI_ENCODING:1005,REQUEST_FILTER_ERROR:1006,RESPONSE_FILTER_ERROR:1007,INVALID_TEXT_HEADER:2E3,INVALID_TEXT_CUE:2001,UNABLE_TO_DETECT_ENCODING:2003,BAD_ENCODING:2004,INVALID_XML:2005,INVALID_MP4_TTML:2007,INVALID_MP4_VTT:2008,BUFFER_READ_OUT_OF_BOUNDS:3E3,JS_INTEGER_OVERFLOW:3001,EBML_OVERFLOW:3002,EBML_BAD_FLOATING_POINT_SIZE:3003,MP4_SIDX_WRONG_BOX_TYPE:3004,MP4_SIDX_INVALID_TIMESCALE:3005,
|
|
MP4_SIDX_TYPE_NOT_SUPPORTED:3006,WEBM_CUES_ELEMENT_MISSING:3007,WEBM_EBML_HEADER_ELEMENT_MISSING:3008,WEBM_SEGMENT_ELEMENT_MISSING:3009,WEBM_INFO_ELEMENT_MISSING:3010,WEBM_DURATION_ELEMENT_MISSING:3011,WEBM_CUE_TRACK_POSITIONS_ELEMENT_MISSING:3012,WEBM_CUE_TIME_ELEMENT_MISSING:3013,MEDIA_SOURCE_OPERATION_FAILED:3014,MEDIA_SOURCE_OPERATION_THREW:3015,VIDEO_ERROR:3016,QUOTA_EXCEEDED_ERROR:3017,UNABLE_TO_GUESS_MANIFEST_TYPE:4E3,DASH_INVALID_XML:4001,DASH_NO_SEGMENT_INFO:4002,DASH_EMPTY_ADAPTATION_SET:4003,
|
|
DASH_EMPTY_PERIOD:4004,DASH_WEBM_MISSING_INIT:4005,DASH_UNSUPPORTED_CONTAINER:4006,DASH_PSSH_BAD_ENCODING:4007,DASH_NO_COMMON_KEY_SYSTEM:4008,DASH_MULTIPLE_KEY_IDS_NOT_SUPPORTED:4009,DASH_CONFLICTING_KEY_IDS:4010,UNPLAYABLE_PERIOD:4011,RESTRICTIONS_CANNOT_BE_MET:4012,NO_PERIODS:4014,HLS_PLAYLIST_HEADER_MISSING:4015,INVALID_HLS_TAG:4016,HLS_INVALID_PLAYLIST_HIERARCHY:4017,DASH_DUPLICATE_REPRESENTATION_ID:4018,HLS_MULTIPLE_MEDIA_INIT_SECTIONS_FOUND:4020,HLS_COULD_NOT_GUESS_MIME_TYPE:4021,HLS_MASTER_PLAYLIST_NOT_PROVIDED:4022,
|
|
HLS_REQUIRED_ATTRIBUTE_MISSING:4023,HLS_REQUIRED_TAG_MISSING:4024,HLS_COULD_NOT_GUESS_CODECS:4025,HLS_KEYFORMATS_NOT_SUPPORTED:4026,INVALID_STREAMS_CHOSEN:5005,NO_RECOGNIZED_KEY_SYSTEMS:6E3,REQUESTED_KEY_SYSTEM_CONFIG_UNAVAILABLE:6001,FAILED_TO_CREATE_CDM:6002,FAILED_TO_ATTACH_TO_VIDEO:6003,INVALID_SERVER_CERTIFICATE:6004,FAILED_TO_CREATE_SESSION:6005,FAILED_TO_GENERATE_LICENSE_REQUEST:6006,LICENSE_REQUEST_FAILED:6007,LICENSE_RESPONSE_REJECTED:6008,ENCRYPTED_CONTENT_WITHOUT_DRM_INFO:6010,NO_LICENSE_SERVER_GIVEN:6012,
|
|
OFFLINE_SESSION_REMOVED:6013,EXPIRED:6014,LOAD_INTERRUPTED:7E3,CAST_API_UNAVAILABLE:8E3,NO_CAST_RECEIVERS:8001,ALREADY_CASTING:8002,UNEXPECTED_CAST_ERROR:8003,CAST_CANCELED_BY_USER:8004,CAST_CONNECTION_TIMED_OUT:8005,CAST_RECEIVER_APP_UNAVAILABLE:8006,STORAGE_NOT_SUPPORTED:9E3,INDEXED_DB_ERROR:9001,OPERATION_ABORTED:9002,REQUESTED_ITEM_NOT_FOUND:9003,MALFORMED_OFFLINE_URI:9004,CANNOT_STORE_LIVE_OFFLINE:9005,STORE_ALREADY_IN_PROGRESS:9006,NO_INIT_DATA_FOR_OFFLINE:9007,LOCAL_PLAYER_INSTANCE_REQUIRED:9008};var ha=/^(?:([^:/?#.]+):)?(?:\/\/(?:([^/?#]*)@)?([^/#?]*?)(?::([0-9]+))?(?=[/#?]|$))?([^?#]+)?(?:\?([^#]*))?(?:#(.*))?$/;function ia(a){var b;a instanceof ia?(ja(this,a.aa),this.Ba=a.Ba,this.ca=a.ca,ka(this,a.Ja),this.W=a.W,la(this,ma(a.a)),this.ta=a.ta):a&&(b=String(a).match(ha))?(ja(this,b[1]||"",!0),this.Ba=na(b[2]||""),this.ca=na(b[3]||"",!0),ka(this,b[4]),this.W=na(b[5]||"",!0),la(this,b[6]||"",!0),this.ta=na(b[7]||"")):this.a=new oa(null)}k=ia.prototype;k.aa="";k.Ba="";k.ca="";k.Ja=null;k.W="";k.ta="";
|
|
k.toString=function(){var a=[],b=this.aa;b&&a.push(qa(b,ra,!0),":");if(b=this.ca){a.push("//");var c=this.Ba;c&&a.push(qa(c,ra,!0),"@");a.push(encodeURIComponent(b).replace(/%25([0-9a-fA-F]{2})/g,"%$1"));b=this.Ja;null!=b&&a.push(":",String(b))}if(b=this.W)this.ca&&"/"!=b.charAt(0)&&a.push("/"),a.push(qa(b,"/"==b.charAt(0)?sa:ta,!0));(b=this.a.toString())&&a.push("?",b);(b=this.ta)&&a.push("#",qa(b,ua));return a.join("")};
|
|
k.resolve=function(a){var b=new ia(this);"data"===b.aa&&(b=new ia);var c=!!a.aa;c?ja(b,a.aa):c=!!a.Ba;c?b.Ba=a.Ba:c=!!a.ca;c?b.ca=a.ca:c=null!=a.Ja;var d=a.W;if(c)ka(b,a.Ja);else if(c=!!a.W){if("/"!=d.charAt(0))if(this.ca&&!this.W)d="/"+d;else{var e=b.W.lastIndexOf("/");-1!=e&&(d=b.W.substr(0,e+1)+d)}if(".."==d||"."==d)d="";else if(-1!=d.indexOf("./")||-1!=d.indexOf("/.")){for(var e=!d.lastIndexOf("/",0),d=d.split("/"),f=[],g=0;g<d.length;){var h=d[g++];"."==h?e&&g==d.length&&f.push(""):".."==h?((1<
|
|
f.length||1==f.length&&""!=f[0])&&f.pop(),e&&g==d.length&&f.push("")):(f.push(h),e=!0)}d=f.join("/")}}c?b.W=d:c=""!==a.a.toString();c?la(b,ma(a.a)):c=!!a.ta;c&&(b.ta=a.ta);return b};function ja(a,b,c){a.aa=c?na(b,!0):b;a.aa&&(a.aa=a.aa.replace(/:$/,""))}function ka(a,b){if(b){b=Number(b);if(isNaN(b)||0>b)throw Error("Bad port number "+b);a.Ja=b}else a.Ja=null}function la(a,b,c){b instanceof oa?a.a=b:(c||(b=qa(b,va)),a.a=new oa(b))}
|
|
function na(a,b){return a?b?decodeURI(a):decodeURIComponent(a):""}function qa(a,b,c){return"string"==typeof a?(a=encodeURI(a).replace(b,wa),c&&(a=a.replace(/%25([0-9a-fA-F]{2})/g,"%$1")),a):null}function wa(a){a=a.charCodeAt(0);return"%"+(a>>4&15).toString(16)+(a&15).toString(16)}var ra=/[#\/\?@]/g,ta=/[\#\?:]/g,sa=/[\#\?]/g,va=/[\#\?@]/g,ua=/#/g;function oa(a){this.b=a||null}oa.prototype.a=null;oa.prototype.c=null;
|
|
oa.prototype.toString=function(){if(this.b)return this.b;if(!this.a)return"";var a=[],b;for(b in this.a)for(var c=encodeURIComponent(b),d=this.a[b],e=0;e<d.length;e++){var f=c;""!==d[e]&&(f+="="+encodeURIComponent(d[e]));a.push(f)}return this.b=a.join("&")};function ma(a){var b=new oa;b.b=a.b;if(a.a){var c={},d;for(d in a.a)c[d]=a.a[d].concat();b.a=c;b.c=a.c}return b};function xa(a,b){return a.reduce(function(a,b,e){return b["catch"](a.bind(null,e))}.bind(null,b),Promise.reject())}function x(a,b){return a.concat(b)}function y(){}function ya(a){return null!=a}function za(a){return function(b){return b!=a}}function Aa(a,b,c){return c.indexOf(a)==b};function z(a,b){if(!b.length)return a;var c=b.map(function(a){return new ia(a)});return a.map(function(a){return new ia(a)}).map(function(a){return c.map(a.resolve.bind(a))}).reduce(x,[]).map(function(a){return a.toString()})}function Ba(a,b){return{keySystem:a,licenseServerUri:"",distinctiveIdentifierRequired:!1,persistentStateRequired:!1,audioRobustness:"",videoRobustness:"",serverCertificate:null,initData:b||[],keyIds:[]}};function Ca(a,b,c,d,e){var f=e in d,g;for(g in b){var h=e+"."+g,l=f?d[e]:c[g],m=!!{".abr.manager":!0}[h]||!!{serverCertificate:!0}[g];if(f||g in a)void 0===b[g]?void 0===l||f?delete a[g]:a[g]=l:m?a[g]=b[g]:"object"==typeof a[g]&&"object"==typeof b[g]?Ca(a[g],b[g],l,d,h):typeof b[g]==typeof l&&(a[g]=b[g])}}function Da(a){return JSON.parse(JSON.stringify(a))};function A(){var a,b,c=new Promise(function(c,e){a=c;b=e});c.resolve=a;c.reject=b;return c};function B(a){this.f=!1;this.a=[];this.b=[];this.c=[];this.h=a||null}n("shaka.net.NetworkingEngine",B);B.RequestType={MANIFEST:0,SEGMENT:1,LICENSE:2,APP:3};var Ea={};B.registerScheme=function(a,b){Ea[a]=b};B.unregisterScheme=function(a){delete Ea[a]};B.prototype.Ld=function(a){this.b.push(a)};B.prototype.registerRequestFilter=B.prototype.Ld;B.prototype.oe=function(a){var b=this.b;a=b.indexOf(a);0<=a&&b.splice(a,1)};B.prototype.unregisterRequestFilter=B.prototype.oe;
|
|
B.prototype.Ic=function(){this.b=[]};B.prototype.clearAllRequestFilters=B.prototype.Ic;B.prototype.Md=function(a){this.c.push(a)};B.prototype.registerResponseFilter=B.prototype.Md;B.prototype.pe=function(a){var b=this.c;a=b.indexOf(a);0<=a&&b.splice(a,1)};B.prototype.unregisterResponseFilter=B.prototype.pe;B.prototype.Jc=function(){this.c=[]};B.prototype.clearAllResponseFilters=B.prototype.Jc;function Fa(){return{maxAttempts:2,baseDelay:1E3,backoffFactor:2,fuzzFactor:.5,timeout:0}}
|
|
function C(a,b){return{uris:a,method:"GET",body:null,headers:{},allowCrossSiteCredentials:!1,retryParameters:b}}B.prototype.m=function(){this.f=!0;this.b=[];this.c=[];for(var a=[],b=0;b<this.a.length;++b)a.push(this.a[b]["catch"](y));return Promise.all(a)};B.prototype.destroy=B.prototype.m;
|
|
B.prototype.request=function(a,b){if(this.f)return Promise.reject();b.method=b.method||"GET";b.headers=b.headers||{};b.retryParameters=b.retryParameters?Da(b.retryParameters):Fa();b.uris=Da(b.uris);var c=Date.now(),d=Promise.resolve();this.b.forEach(function(c){d=d.then(c.bind(null,a,b))});d=d["catch"](function(a){throw new t(2,1,1006,a);});d=d.then(function(){for(var d=Date.now()-c,f=b.retryParameters||{},g=f.maxAttempts||1,h=f.backoffFactor||2,f=null==f.baseDelay?1E3:f.baseDelay,l=this.g(a,b,0,
|
|
d),m=1;m<g;m++)l=l["catch"](function(c,e,f){if(f&&1==f.severity){f=new A;var g=b.retryParameters||{};window.setTimeout(f.resolve,c*(1+(2*Math.random()-1)*(null==g.fuzzFactor?.5:g.fuzzFactor)));return f.then(this.g.bind(this,a,b,e,d))}throw f;}.bind(this,f,m%b.uris.length)),f*=h;return l}.bind(this));this.a.push(d);return d.then(function(b){0<=this.a.indexOf(d)&&this.a.splice(this.a.indexOf(d),1);this.h&&!b.fromCache&&1==a&&this.h(b.timeMs,b.data.byteLength);return b}.bind(this))["catch"](function(a){a&&
|
|
(a.severity=2);0<=this.a.indexOf(d)&&this.a.splice(this.a.indexOf(d),1);return Promise.reject(a)}.bind(this))};B.prototype.request=B.prototype.request;
|
|
B.prototype.g=function(a,b,c,d){if(this.f)return Promise.reject();var e=new ia(b.uris[c]),f=e.aa;f||(f=location.protocol,f=f.slice(0,-1),ja(e,f),b.uris[c]=e.toString());f=Ea[f];if(!f)return Promise.reject(new t(2,1,1E3,e));var g=Date.now();return f(b.uris[c],b,a).then(function(b){void 0==b.timeMs&&(b.timeMs=Date.now()-g);var c=Date.now(),e=Promise.resolve();this.c.forEach(function(c){e=e.then(function(){return Promise.resolve(c(a,b))}.bind(this))});e=e["catch"](function(a){var b=2;a instanceof t&&
|
|
(b=a.severity);throw new t(b,1,1007,a);});return e.then(function(){b.timeMs+=Date.now()-c;b.timeMs+=d;return b})}.bind(this))};function Ga(a,b){for(var c=[],d=0;d<a.length;++d){for(var e=!1,f=0;f<c.length&&!(e=b?b(a[d],c[f]):a[d]===c[f]);++f);e||c.push(a[d])}return c}function Ha(a,b,c){for(var d=0;d<a.length;++d)if(c(a[d],b))return d;return-1};function Ia(){this.a={}}Ia.prototype.push=function(a,b){this.a.hasOwnProperty(a)?this.a[a].push(b):this.a[a]=[b]};Ia.prototype.get=function(a){return(a=this.a[a])?a.slice():null};Ia.prototype.remove=function(a,b){var c=this.a[a];if(c)for(var d=0;d<c.length;++d)c[d]==b&&(c.splice(d,1),--d)};function D(){this.a=new Ia}D.prototype.m=function(){Ja(this);this.a=null;return Promise.resolve()};function E(a,b,c,d){a.a&&(b=new Ka(b,c,d),a.a.push(c,b))}function La(a,b,c,d){E(a,b,c,function(a){this.ha(b,c);d(a)}.bind(a))}D.prototype.ha=function(a,b){if(this.a)for(var c=this.a.get(b)||[],d=0;d<c.length;++d){var e=c[d];e.target==a&&(e.ha(),this.a.remove(b,e))}};function Ja(a){if(a.a){var b=a.a,c=[],d;for(d in b.a)c.push.apply(c,b.a[d]);for(b=0;b<c.length;++b)c[b].ha();a.a.a={}}}
|
|
function Ka(a,b,c){this.target=a;this.type=b;this.a=c;this.target.addEventListener(b,c,!1)}Ka.prototype.ha=function(){this.target.removeEventListener(this.type,this.a,!1);this.a=this.target=null};function Ma(a){return!a||!Object.keys(a).length}function Na(a){return Object.keys(a).map(function(b){return a[b]})}function Oa(a,b){return Object.keys(a).reduce(function(c,d){c[d]=b(a[d],d);return c},{})}function Pa(a,b){return Object.keys(a).every(function(c){return b(c,a[c])})}function Qa(a,b){Object.keys(a).forEach(function(c){b(c,a[c])})};function F(a){if(!a)return"";a=new Uint8Array(a);239==a[0]&&187==a[1]&&191==a[2]&&(a=a.subarray(3));a=escape(Ra(a));try{return decodeURIComponent(a)}catch(b){throw new t(2,2,2004);}}n("shaka.util.StringUtils.fromUTF8",F);
|
|
function Sa(a,b,c){if(!a)return"";if(!c&&a.byteLength%2)throw new t(2,2,2004);if(a instanceof ArrayBuffer)var d=a;else c=new Uint8Array(a.byteLength),c.set(new Uint8Array(a)),d=c.buffer;a=Math.floor(a.byteLength/2);c=new Uint16Array(a);d=new DataView(d);for(var e=0;e<a;e++)c[e]=d.getUint16(2*e,b);return Ra(c)}n("shaka.util.StringUtils.fromUTF16",Sa);
|
|
function Ta(a){var b=new Uint8Array(a);if(239==b[0]&&187==b[1]&&191==b[2])return F(b);if(254==b[0]&&255==b[1])return Sa(b.subarray(2),!1);if(255==b[0]&&254==b[1])return Sa(b.subarray(2),!0);var c=function(a,b){return a.byteLength<=b||32<=a[b]&&126>=a[b]}.bind(null,b);if(b[0]||b[2]){if(!b[1]&&!b[3])return Sa(a,!0);if(c(0)&&c(1)&&c(2)&&c(3))return F(a)}else return Sa(a,!1);throw new t(2,2,2003);}n("shaka.util.StringUtils.fromBytesAutoDetect",Ta);
|
|
function Ua(a){a=unescape(encodeURIComponent(a));for(var b=new Uint8Array(a.length),c=0;c<a.length;++c)b[c]=a.charCodeAt(c);return b.buffer}n("shaka.util.StringUtils.toUTF8",Ua);function Ra(a){for(var b="",c=0;c<a.length;c+=16E3)b+=String.fromCharCode.apply(null,a.subarray(c,c+16E3));return b};function Va(a){this.a=null;this.b=function(){this.a=null;a()}.bind(this)}Va.prototype.cancel=function(){null!=this.a&&(clearTimeout(this.a),this.a=null)};function Wa(a){a.cancel();a.a=setTimeout(a.b,500)};function Xa(a,b){var c=void 0==b?!0:b,d=window.btoa(String.fromCharCode.apply(null,a)).replace(/\+/g,"-").replace(/\//g,"_");return c?d:d.replace(/=*$/,"")}n("shaka.util.Uint8ArrayUtils.toBase64",Xa);function Ya(a){a=window.atob(a.replace(/-/g,"+").replace(/_/g,"/"));for(var b=new Uint8Array(a.length),c=0;c<a.length;++c)b[c]=a.charCodeAt(c);return b}n("shaka.util.Uint8ArrayUtils.fromBase64",Ya);
|
|
function Za(a){for(var b=new Uint8Array(a.length/2),c=0;c<a.length;c+=2)b[c/2]=window.parseInt(a.substr(c,2),16);return b}n("shaka.util.Uint8ArrayUtils.fromHex",Za);function $a(a){for(var b="",c=0;c<a.length;++c){var d=a[c].toString(16);1==d.length&&(d="0"+d);b+=d}return b}n("shaka.util.Uint8ArrayUtils.toHex",$a);function ab(a,b){if(!a&&!b)return!0;if(!a||!b||a.length!=b.length)return!1;for(var c=0;c<a.length;++c)if(a[c]!=b[c])return!1;return!0}n("shaka.util.Uint8ArrayUtils.equal",ab);
|
|
n("shaka.util.Uint8ArrayUtils.concat",function(a){for(var b=0,c=0;c<arguments.length;++c)b+=arguments[c].length;for(var b=new Uint8Array(b),d=0,c=0;c<arguments.length;++c)b.set(arguments[c],d),d+=arguments[c].length;return b});function bb(a,b,c,d){this.j=this.i=this.v=null;this.J=!1;this.b=null;this.f=new D;this.a=[];this.o=[];this.l=new A;this.ka=a;this.h=null;this.g=function(a){this.l.reject(a);b(a)}.bind(this);this.A={};this.Ca=c;this.la=d;this.B=new Va(this.Kd.bind(this));this.ja=this.c=!1;this.G=[];this.ia=!1;this.O=setInterval(this.Jd.bind(this),1E3);this.l["catch"](function(){})}k=bb.prototype;
|
|
k.m=function(){this.c=!0;var a=this.a.map(function(a){return(a.ba.close()||Promise.resolve())["catch"](y)});this.l.reject();this.f&&a.push(this.f.m());this.j&&a.push(this.j.setMediaKeys(null)["catch"](y));this.O&&(clearInterval(this.O),this.O=null);this.B&&this.B.cancel();this.f=this.j=this.i=this.v=this.b=this.B=null;this.a=[];this.o=[];this.la=this.g=this.h=this.ka=null;return Promise.all(a)};k.configure=function(a){this.h=a};
|
|
k.init=function(a,b){var c={},d=[];this.ja=b;this.o=a.offlineSessionIds;cb(this,a,b||0<a.offlineSessionIds.length,c,d);return d.length?db(this,c,d):(this.J=!0,Promise.resolve())};
|
|
function eb(a,b){if(!a.i)return La(a.f,b,"encrypted",function(){this.g(new t(2,6,6010))}.bind(a)),Promise.resolve();a.j=b;La(a.f,a.j,"play",a.qd.bind(a));var c=a.j.setMediaKeys(a.i),c=c["catch"](function(a){return Promise.reject(new t(2,6,6003,a.message))}),d=null;a.b.serverCertificate&&(d=a.i.setServerCertificate(a.b.serverCertificate).then(function(){})["catch"](function(a){return Promise.reject(new t(2,6,6004,a.message))}));return Promise.all([c,d]).then(function(){if(this.c)return Promise.reject();
|
|
fb(this);this.b.initData.length||this.o.length||E(this.f,this.j,"encrypted",this.fd.bind(this))}.bind(a))["catch"](function(a){return this.c?Promise.resolve():Promise.reject(a)}.bind(a))}function gb(a,b){return Promise.all(b.map(function(a){return hb(this,a).then(function(a){if(a){for(var b=new A,c=0;c<this.a.length;c++)if(this.a[c].ba==a){this.a[c].ib=b;break}return Promise.all([a.remove(),b])}}.bind(this))}.bind(a)))}
|
|
function fb(a){var b=a.b?a.b.initData:[];b.forEach(function(a){ib(this,a.initDataType,a.initData)}.bind(a));a.o.forEach(function(a){hb(this,a)}.bind(a));b.length||a.o.length||a.l.resolve();return a.l}k.keySystem=function(){return this.b?this.b.keySystem:""};function jb(a){return a.a.map(function(a){return a.ba.sessionId})}k.ab=function(){var a=this.a.map(function(a){a=a.ba.expiration;return isNaN(a)?Infinity:a});return Math.min.apply(Math,a)};
|
|
function cb(a,b,c,d,e){var f=kb(a);b.periods.forEach(function(a){a.variants.forEach(function(a){f&&(a.drmInfos=[f]);a.drmInfos.forEach(function(b){lb(this,b);window.cast&&window.cast.__platform__&&"com.microsoft.playready"==b.keySystem&&(b.keySystem="com.chromecast.playready");var f=d[b.keySystem];f||(f={audioCapabilities:[],videoCapabilities:[],distinctiveIdentifier:"optional",persistentState:c?"required":"optional",sessionTypes:[c?"persistent-license":"temporary"],label:b.keySystem,drmInfos:[]},
|
|
d[b.keySystem]=f,e.push(b.keySystem));f.drmInfos.push(b);b.distinctiveIdentifierRequired&&(f.distinctiveIdentifier="required");b.persistentStateRequired&&(f.persistentState="required");var g=[];a.video&&g.push(a.video);a.audio&&g.push(a.audio);g.forEach(function(a){var c="video"==a.type?f.videoCapabilities:f.audioCapabilities,d=("video"==a.type?b.videoRobustness:b.audioRobustness)||"",e=a.mimeType;a.codecs&&(e+='; codecs="'+a.codecs+'"');c.push({robustness:d,contentType:e})}.bind(this))}.bind(this))}.bind(this))}.bind(a))}
|
|
function db(a,b,c){if(1==c.length&&""==c[0])return Promise.reject(new t(2,6,6E3));var d=new A,e=d;[!0,!1].forEach(function(a){c.forEach(function(c){var d=b[c];d.drmInfos.some(function(a){return!!a.licenseServerUri})==a&&(d.audioCapabilities.length||delete d.audioCapabilities,d.videoCapabilities.length||delete d.videoCapabilities,e=e["catch"](function(){return this.c?Promise.reject():navigator.requestMediaKeySystemAccess(c,[d])}.bind(this)))}.bind(this))}.bind(a));e=e["catch"](function(){return Promise.reject(new t(2,
|
|
6,6001))});e=e.then(function(a){if(this.c)return Promise.reject();var c=0<=navigator.userAgent.indexOf("Edge/"),d=a.getConfiguration();this.v=(d.audioCapabilities||[]).concat(d.videoCapabilities||[]).map(function(a){return a.contentType});c&&(this.v=null);c=b[a.keySystem];mb(this,a.keySystem,c,c.drmInfos);return this.b.licenseServerUri?a.createMediaKeys():Promise.reject(new t(2,6,6012))}.bind(a)).then(function(a){if(this.c)return Promise.reject();this.i=a;this.J=!0}.bind(a))["catch"](function(a){if(this.c)return Promise.resolve();
|
|
this.v=this.b=null;return a instanceof t?Promise.reject(a):Promise.reject(new t(2,6,6002,a.message))}.bind(a));d.reject();return e}
|
|
function lb(a,b){var c=b.keySystem;if(c){if(!b.licenseServerUri){var d=a.h.servers[c];d&&(b.licenseServerUri=d)}b.keyIds||(b.keyIds=[]);if(c=a.h.advanced[c])b.distinctiveIdentifierRequired||(b.distinctiveIdentifierRequired=c.distinctiveIdentifierRequired),b.persistentStateRequired||(b.persistentStateRequired=c.persistentStateRequired),b.videoRobustness||(b.videoRobustness=c.videoRobustness),b.audioRobustness||(b.audioRobustness=c.audioRobustness),b.serverCertificate||(b.serverCertificate=c.serverCertificate)}}
|
|
function kb(a){if(Ma(a.h.clearKeys))return null;var b=[],c=[],d;for(d in a.h.clearKeys){var e=a.h.clearKeys[d],f=Za(d),e=Za(e),f={kty:"oct",kid:Xa(f,!1),k:Xa(e,!1)};b.push(f);c.push(f.kid)}a=JSON.stringify({keys:b});c=JSON.stringify({kids:c});c=[{initData:new Uint8Array(Ua(c)),initDataType:"keyids"}];return{keySystem:"org.w3.clearkey",licenseServerUri:"data:application/json;base64,"+window.btoa(a),distinctiveIdentifierRequired:!1,persistentStateRequired:!1,audioRobustness:"",videoRobustness:"",serverCertificate:null,
|
|
initData:c,keyIds:[]}}function mb(a,b,c,d){var e=[],f=[],g=[],h=[];nb(d,e,f,g,h);a.b={keySystem:b,licenseServerUri:e[0],distinctiveIdentifierRequired:"required"==c.distinctiveIdentifier,persistentStateRequired:"required"==c.persistentState,audioRobustness:c.audioCapabilities?c.audioCapabilities[0].robustness:"",videoRobustness:c.videoCapabilities?c.videoCapabilities[0].robustness:"",serverCertificate:f[0],initData:g,keyIds:h}}
|
|
function nb(a,b,c,d,e){function f(a,b){return a.keyId&&a.keyId==b.keyId?!0:a.initDataType==b.initDataType&&ab(a.initData,b.initData)}a.forEach(function(a){-1==b.indexOf(a.licenseServerUri)&&b.push(a.licenseServerUri);a.serverCertificate&&-1==Ha(c,a.serverCertificate,ab)&&c.push(a.serverCertificate);a.initData&&a.initData.forEach(function(a){-1==Ha(d,a,f)&&d.push(a)});if(a.keyIds)for(var g=0;g<a.keyIds.length;++g)-1==e.indexOf(a.keyIds[g])&&e.push(a.keyIds[g])})}
|
|
k.fd=function(a){for(var b=new Uint8Array(a.initData),c=0;c<this.a.length;++c)if(ab(b,this.a[c].initData))return;ib(this,a.initDataType,b)};
|
|
function hb(a,b){try{var c=a.i.createSession("persistent-license")}catch(f){var d=new t(2,6,6005,f.message);a.g(d);return Promise.reject(d)}E(a.f,c,"message",a.kc.bind(a));E(a.f,c,"keystatuseschange",a.ec.bind(a));var e={initData:null,ba:c,loaded:!1,zb:Infinity,ib:null};a.a.push(e);return c.load(b).then(function(a){if(!this.c){if(a)return e.loaded=!0,this.a.every(function(a){return a.loaded})&&this.l.resolve(),c;this.a.splice(this.a.indexOf(e),1);this.g(new t(2,6,6013))}}.bind(a),function(a){this.c||
|
|
(this.a.splice(this.a.indexOf(e),1),this.g(new t(2,6,6005,a.message)))}.bind(a))}
|
|
function ib(a,b,c){try{var d=a.ja?a.i.createSession("persistent-license"):a.i.createSession()}catch(e){a.g(new t(2,6,6005,e.message));return}E(a.f,d,"message",a.kc.bind(a));E(a.f,d,"keystatuseschange",a.ec.bind(a));a.a.push({initData:c,ba:d,loaded:!1,zb:Infinity,ib:null});d.generateRequest(b,c.buffer)["catch"](function(a){if(!this.c){for(var b=0;b<this.a.length;++b)if(this.a[b].ba==d){this.a.splice(b,1);break}this.g(new t(2,6,6006,a.message))}}.bind(a))}
|
|
k.kc=function(a){this.h.delayLicenseRequestUntilPlayed&&this.j.paused&&!this.ia?this.G.push(a):ob(this,a)};
|
|
function ob(a,b){for(var c=b.target,d,e=0;e<a.a.length;e++)if(a.a[e].ba==c){d=a.a[e].ib;break}e=C([a.b.licenseServerUri],a.h.retryParameters);e.body=b.message;e.method="POST";"com.microsoft.playready"!=a.b.keySystem&&"com.chromecast.playready"!=a.b.keySystem||pb(e);a.ka.request(2,e).then(function(a){return this.c?Promise.reject():c.update(a.data).then(function(){d&&d.resolve()})}.bind(a),function(a){if(this.c)return Promise.resolve();a=new t(2,6,6007,a);this.g(a);d&&d.reject(a)}.bind(a))["catch"](function(a){if(this.c)return Promise.resolve();
|
|
a=new t(2,6,6008,a.message);this.g(a);d&&d.reject(a)}.bind(a))}function pb(a){var b=Sa(a.body,!0,!0);if(-1==b.indexOf("PlayReadyKeyMessage"))a.headers["Content-Type"]="text/xml; charset=utf-8";else{for(var b=(new DOMParser).parseFromString(b,"application/xml"),c=b.getElementsByTagName("HttpHeader"),d=0;d<c.length;++d)a.headers[c[d].querySelector("name").textContent]=c[d].querySelector("value").textContent;a.body=Ya(b.querySelector("Challenge").textContent).buffer}}
|
|
k.ec=function(a){a=a.target;var b;for(b=0;b<this.a.length&&this.a[b].ba!=a;++b);if(b!=this.a.length){var c=!1;a.keyStatuses.forEach(function(a,d){if("string"==typeof d){var e=d;d=a;a=e}if("com.microsoft.playready"==this.b.keySystem&&16==d.byteLength){var e=new DataView(d),f=e.getUint32(0,!0),l=e.getUint16(4,!0),m=e.getUint16(6,!0);e.setUint32(0,f,!1);e.setUint16(4,l,!1);e.setUint16(6,m,!1)}"com.microsoft.playready"==this.b.keySystem&&"status-pending"==a&&(a="usable");"status-pending"!=a&&(this.a[b].loaded=
|
|
!0,this.a.every(function(a){return a.loaded})&&this.l.resolve());"expired"==a&&(c=!0);e=$a(new Uint8Array(d));this.A[e]=a}.bind(this));var d=a.expiration-Date.now();(0>d||c&&1E3>d)&&!this.a[b].ib&&(this.a.splice(b,1),a.close());Wa(this.B)}};k.Kd=function(){function a(a,c){return"expired"==c}!Ma(this.A)&&Pa(this.A,a)&&this.g(new t(2,6,6014));this.Ca(this.A)};
|
|
function qb(){var a=[],b=[{contentType:'video/mp4; codecs="avc1.42E01E"'},{contentType:'video/webm; codecs="vp8"'}],c=[{videoCapabilities:b,persistentState:"required",sessionTypes:["persistent-license"]},{videoCapabilities:b}],d={};"org.w3.clearkey com.widevine.alpha com.microsoft.playready com.apple.fps.2_0 com.apple.fps.1_0 com.apple.fps com.adobe.primetime".split(" ").forEach(function(b){var e=navigator.requestMediaKeySystemAccess(b,c).then(function(a){var c=a.getConfiguration().sessionTypes;d[b]=
|
|
{persistentState:c?0<=c.indexOf("persistent-license"):!1};return a.createMediaKeys()})["catch"](function(){d[b]=null});a.push(e)});return Promise.all(a).then(function(){return d})}k.qd=function(){for(var a=0;a<this.G.length;a++)ob(this,this.G[a]);this.ia=!0;this.G=[]};function rb(a,b){var c=a.keySystem();return!b.drmInfos.length||b.drmInfos.some(function(a){return a.keySystem==c})}
|
|
function sb(a,b){if(!a.length)return b;if(!b.length)return a;for(var c=[],d=0;d<a.length;d++)for(var e=0;e<b.length;e++)if(a[d].keySystem==b[e].keySystem){var f=a[d],e=b[e],g=[],g=g.concat(f.initData||[]),g=g.concat(e.initData||[]),h=[],h=h.concat(f.keyIds),h=h.concat(e.keyIds);c.push({keySystem:f.keySystem,licenseServerUri:f.licenseServerUri||e.licenseServerUri,distinctiveIdentifierRequired:f.distinctiveIdentifierRequired||e.distinctiveIdentifierRequired,persistentStateRequired:f.persistentStateRequired||
|
|
e.persistentStateRequired,videoRobustness:f.videoRobustness||e.videoRobustness,audioRobustness:f.audioRobustness||e.audioRobustness,serverCertificate:f.serverCertificate||e.serverCertificate,initData:g,keyIds:h});break}return c}k.Jd=function(){this.a.forEach(function(a){var b=a.zb,c=a.ba.expiration;isNaN(c)&&(c=Infinity);c!=b&&(this.la(a.ba.sessionId,c),a.zb=c)}.bind(this))};function tb(a){this.f=null;this.c=a;this.h=0;this.g=Infinity;this.a=this.b=null}var ub={};function vb(a,b){ub[a]=b.length?wb.bind(null,b):b}n("shaka.media.TextEngine.registerParser",vb);n("shaka.media.TextEngine.unregisterParser",function(a){delete ub[a]});function xb(a,b,c){return a>=b?null:new VTTCue(a,b,c)}n("shaka.media.TextEngine.makeCue",xb);tb.prototype.m=function(){this.c&&yb(this,function(){return!0});this.c=this.f=null;return Promise.resolve()};
|
|
function zb(a,b,c,d){return Promise.resolve().then(function(){if(this.c)if(null==c||null==d)this.f.parseInit(b);else{for(var a=this.f.parseMedia(b,{periodStart:this.h,segmentStart:c,segmentEnd:d}),f=0;f<a.length&&!(a[f].startTime>=this.g);++f)this.c.addCue(a[f]);null==this.b&&(this.b=c);this.a=Math.min(d,this.g)}}.bind(a))}
|
|
tb.prototype.remove=function(a,b){return Promise.resolve().then(function(){this.c&&(yb(this,function(c){return c.startTime>=b||c.endTime<=a?!1:!0}),null==this.b||b<=this.b||a>=this.a||(a<=this.b&&b>=this.a?this.b=this.a=null:a<=this.b&&b<this.a?this.b=b:a>this.b&&b>=this.a&&(this.a=a)))}.bind(this))};function yb(a,b){for(var c=a.c.cues,d=[],e=0;e<c.length;++e)b(c[e])&&d.push(c[e]);for(e=0;e<d.length;++e)a.c.removeCue(d[e])}function wb(a){this.Na=a}
|
|
wb.prototype.parseInit=function(a){this.Na(a,0,null,null)};wb.prototype.parseMedia=function(a,b){return this.Na(a,b.periodStart,b.segmentStart,b.segmentEnd)};function Ab(a){return!a||1==a.length&&1E-6>a.end(0)-a.start(0)?null:a.length?a.end(a.length-1):null}function Bb(a,b){return!a||!a.length||1==a.length&&1E-6>a.end(0)-a.start(0)?!1:b>=a.start(0)&&b<=a.end(a.length-1)}function Cb(a,b){if(!a||!a.length||1==a.length&&1E-6>a.end(0)-a.start(0))return 0;for(var c=0,d=a.length-1;0<=d&&a.end(d)>b;--d)c+=a.end(d)-Math.max(a.start(d),b);return c};function Db(a,b,c){this.f=a;this.N=b;this.i=c;this.c={};this.a=null;this.b={};this.g=new D;this.h=!1}
|
|
function Eb(){var a={};'video/mp4; codecs="avc1.42E01E",video/mp4; codecs="avc3.42E01E",video/mp4; codecs="hvc1.1.6.L93.90",audio/mp4; codecs="mp4a.40.2",audio/mp4; codecs="ac-3",audio/mp4; codecs="ec-3",video/webm; codecs="vp8",video/webm; codecs="vp9",video/webm; codecs="av1",audio/webm; codecs="vorbis",audio/webm; codecs="opus",video/mp2t; codecs="avc1.42E01E",video/mp2t; codecs="avc3.42E01E",video/mp2t; codecs="hvc1.1.6.L93.90",video/mp2t; codecs="mp4a.40.2",video/mp2t; codecs="ac-3",video/mp2t; codecs="ec-3",video/mp2t; codecs="mp4a.40.2",text/vtt,application/mp4; codecs="wvtt",application/ttml+xml,application/mp4; codecs="stpp"'.split(",").forEach(function(b){a[b]=!!ub[b]||
|
|
MediaSource.isTypeSupported(b);var c=b.split(";")[0];a[c]=a[c]||a[b]});return a}k=Db.prototype;k.m=function(){this.h=!0;var a=[],b;for(b in this.b){var c=this.b[b],d=c[0];this.b[b]=c.slice(0,1);d&&a.push(d.p["catch"](y));for(d=1;d<c.length;++d)c[d].p["catch"](y),c[d].p.reject()}this.a&&a.push(this.a.m());return Promise.all(a).then(function(){this.g.m();this.a=this.i=this.N=this.f=this.g=null;this.c={};this.b={}}.bind(this))};
|
|
k.init=function(a){for(var b in a){var c=a[b];"text"==b?Fb(this,c):(c=this.N.addSourceBuffer(c),E(this.g,c,"error",this.je.bind(this,b)),E(this.g,c,"updateend",this.Ia.bind(this,b)),this.c[b]=c,this.b[b]=[])}};function Fb(a,b){a.a||(a.a=new tb(a.i));a.a.f=new ub[b]}function Gb(a,b){if("text"==b)var c=a.a.b;else c=Ib(a,b),c=!c||1==c.length&&1E-6>c.end(0)-c.start(0)?null:1==c.length&&0>c.start(0)?0:c.length?c.start(0):null;return c}function Ib(a,b){try{return a.c[b].buffered}catch(c){return null}}
|
|
function Jb(a,b,c,d,e){return"text"==b?zb(a.a,c,d,e):Kb(a,b,a.ie.bind(a,b,c))}k.remove=function(a,b,c){return"text"==a?this.a.remove(b,c):Kb(this,a,this.qc.bind(this,a,b,c))};function Lb(a,b){return"text"==b?a.a.remove(0,Infinity):Kb(a,b,a.qc.bind(a,b,0,a.N.duration))}function Mb(a,b,c,d){if("text"==b)return a.a.h=c,null!=d&&(a.a.g=d),Promise.resolve();null==d&&(d=Infinity);return Promise.all([Kb(a,b,a.Ec.bind(a,b)),Kb(a,b,a.Zd.bind(a,b,c)),Kb(a,b,a.Xd.bind(a,b,d))])}
|
|
k.endOfStream=function(a){return Nb(this,function(){a?this.N.endOfStream(a):this.N.endOfStream()}.bind(this))};k.pa=function(a){return Nb(this,function(){this.N.duration=a}.bind(this))};k.Y=function(){return this.N.duration};k.ie=function(a,b){this.c[a].appendBuffer(b)};k.qc=function(a,b,c){c<=b?this.Ia(a):this.c[a].remove(b,c)};k.Ec=function(a){var b=this.c[a].appendWindowEnd;this.c[a].abort();this.c[a].appendWindowEnd=b;this.Ia(a)};k.Oc=function(a){this.f.currentTime-=.001;this.Ia(a)};
|
|
k.Zd=function(a,b){this.c[a].timestampOffset=b;this.Ia(a)};k.Xd=function(a,b){this.c[a].appendWindowEnd=b+.04;this.Ia(a)};k.je=function(a){this.b[a][0].p.reject(new t(2,3,3014,this.f.error?this.f.error.code:0))};k.Ia=function(a){var b=this.b[a][0];b&&(b.p.resolve(),Ob(this,a))};
|
|
function Kb(a,b,c){if(a.h)return Promise.reject();c={start:c,p:new A};a.b[b].push(c);if(1==a.b[b].length)try{c.start()}catch(d){"QuotaExceededError"==d.name?c.p.reject(new t(2,3,3017,b)):c.p.reject(new t(2,3,3015,d)),Ob(a,b)}return c.p}
|
|
function Nb(a,b){if(a.h)return Promise.reject();var c=[],d;for(d in a.c){var e=new A,f={start:function(a){a.resolve()}.bind(null,e),p:e};a.b[d].push(f);c.push(e);1==a.b[d].length&&f.start()}return Promise.all(c).then(function(){var a;try{b()}catch(l){var c=Promise.reject(new t(2,3,3015,l))}for(a in this.c)Ob(this,a);return c}.bind(a),function(){return Promise.reject()}.bind(a))}function Ob(a,b){a.b[b].shift();var c=a.b[b][0];if(c)try{c.start()}catch(d){c.p.reject(new t(2,3,3015,d)),Ob(a,b)}};function Pb(a,b,c){return c==b||a>=Qb&&c==b.split("-")[0]||a>=Rb&&c.split("-")[0]==b.split("-")[0]?!0:!1}var Qb=1,Rb=2;function Sb(a){a=a.toLowerCase().split("-");var b=Tb[a[0]];b&&(a[0]=b);return a.join("-")}
|
|
var Tb={aar:"aa",abk:"ab",afr:"af",aka:"ak",alb:"sq",amh:"am",ara:"ar",arg:"an",arm:"hy",asm:"as",ava:"av",ave:"ae",aym:"ay",aze:"az",bak:"ba",bam:"bm",baq:"eu",bel:"be",ben:"bn",bih:"bh",bis:"bi",bod:"bo",bos:"bs",bre:"br",bul:"bg",bur:"my",cat:"ca",ces:"cs",cha:"ch",che:"ce",chi:"zh",chu:"cu",chv:"cv",cor:"kw",cos:"co",cre:"cr",cym:"cy",cze:"cs",dan:"da",deu:"de",div:"dv",dut:"nl",dzo:"dz",ell:"el",eng:"en",epo:"eo",est:"et",eus:"eu",ewe:"ee",fao:"fo",fas:"fa",fij:"fj",fin:"fi",fra:"fr",fre:"fr",
|
|
fry:"fy",ful:"ff",geo:"ka",ger:"de",gla:"gd",gle:"ga",glg:"gl",glv:"gv",gre:"el",grn:"gn",guj:"gu",hat:"ht",hau:"ha",heb:"he",her:"hz",hin:"hi",hmo:"ho",hrv:"hr",hun:"hu",hye:"hy",ibo:"ig",ice:"is",ido:"io",iii:"ii",iku:"iu",ile:"ie",ina:"ia",ind:"id",ipk:"ik",isl:"is",ita:"it",jav:"jv",jpn:"ja",kal:"kl",kan:"kn",kas:"ks",kat:"ka",kau:"kr",kaz:"kk",khm:"km",kik:"ki",kin:"rw",kir:"ky",kom:"kv",kon:"kg",kor:"ko",kua:"kj",kur:"ku",lao:"lo",lat:"la",lav:"lv",lim:"li",lin:"ln",lit:"lt",ltz:"lb",lub:"lu",
|
|
lug:"lg",mac:"mk",mah:"mh",mal:"ml",mao:"mi",mar:"mr",may:"ms",mkd:"mk",mlg:"mg",mlt:"mt",mon:"mn",mri:"mi",msa:"ms",mya:"my",nau:"na",nav:"nv",nbl:"nr",nde:"nd",ndo:"ng",nep:"ne",nld:"nl",nno:"nn",nob:"nb",nor:"no",nya:"ny",oci:"oc",oji:"oj",ori:"or",orm:"om",oss:"os",pan:"pa",per:"fa",pli:"pi",pol:"pl",por:"pt",pus:"ps",que:"qu",roh:"rm",ron:"ro",rum:"ro",run:"rn",rus:"ru",sag:"sg",san:"sa",sin:"si",slk:"sk",slo:"sk",slv:"sl",sme:"se",smo:"sm",sna:"sn",snd:"sd",som:"so",sot:"st",spa:"es",sqi:"sq",
|
|
srd:"sc",srp:"sr",ssw:"ss",sun:"su",swa:"sw",swe:"sv",tah:"ty",tam:"ta",tat:"tt",tel:"te",tgk:"tg",tgl:"tl",tha:"th",tib:"bo",tir:"ti",ton:"to",tsn:"tn",tso:"ts",tuk:"tk",tur:"tr",twi:"tw",uig:"ug",ukr:"uk",urd:"ur",uzb:"uz",ven:"ve",vie:"vi",vol:"vo",wel:"cy",wln:"wa",wol:"wo",xho:"xh",yid:"yi",yor:"yo",zha:"za",zho:"zh",zul:"zu"};function Ub(a,b,c){var d=a.video;return d&&(d.width<b.minWidth||d.width>b.maxWidth||d.width>c.width||d.height<b.minHeight||d.height>b.maxHeight||d.height>c.height||d.width*d.height<b.minPixels||d.width*d.height>b.maxPixels)||a.bandwidth<b.minBandwidth||a.bandwidth>b.maxBandwidth?!1:!0}function Vb(a,b,c){var d=!1;a.variants.forEach(function(a){var e=a.allowedByApplication;a.allowedByApplication=Ub(a,b,c);e!=a.allowedByApplication&&(d=!0)});return d}
|
|
function Wb(a,b,c){var d=b.video,e=b.audio;for(b=0;b<c.variants.length;++b){var f=c.variants[b],g=a,h=e,l=d;(g&&g.J&&!rb(g,f)?0:Xb(f.audio,g,h)&&Xb(f.video,g,l))||(c.variants.splice(b,1),--b)}for(b=0;b<c.textStreams.length;++b)a=c.textStreams[b],ub[Yb(a.mimeType,a.codecs)]||(c.textStreams.splice(b,1),--b)}
|
|
function Xb(a,b,c){if(!a)return!0;var d=null;b&&b.J&&(d=b.v);b=Yb(a.mimeType,a.codecs);return!ub[b]&&!MediaSource.isTypeSupported(b)||d&&a.encrypted&&0>d.indexOf(b)||c&&(a.mimeType!=c.mimeType||a.codecs.split(".")[0]!=c.codecs.split(".")[0])?!1:!0}
|
|
function Zb(a,b,c){var d=null;return $b(a.variants).map(function(a){var e;a.video&&a.audio?e=c==a.video.id&&b==a.audio.id:e=a.video&&c==a.video.id||a.audio&&b==a.audio.id;var g="";a.video&&(g+=a.video.codecs);a.audio&&(""!=g&&(g+=", "),g+=a.audio.codecs,d=a.audio.label);var h=a.audio?a.audio.codecs:null,l=a.video?a.video.codecs:null,m=null;a.video?m=a.video.mimeType:a.audio&&(m=a.audio.mimeType);var q=null;a.audio?q=a.audio.kind:a.video&&(q=a.video.kind);var r=Ga((a.audio?a.audio.roles:[]).concat(a.video?
|
|
a.video.roles:[]));return{id:a.id,active:e,type:"variant",bandwidth:a.bandwidth,language:a.language,label:d,kind:q||null,width:a.video?a.video.width:null,height:a.video?a.video.height:null,frameRate:a.video?a.video.frameRate:void 0,mimeType:m,codecs:g,audioCodec:h,videoCodec:l,primary:a.primary,roles:r,videoId:a.video?a.video.id:null,audioId:a.audio?a.audio.id:null}})}
|
|
function ac(a,b){return a.textStreams.map(function(a){return{id:a.id,active:b==a.id,type:"text",language:a.language,label:a.label,kind:a.kind,mimeType:a.mimeType,codecs:a.codecs||null,audioCodec:null,videoCodec:null,primary:a.primary,roles:a.roles}})}function bc(a,b){for(var c=0;c<a.variants.length;c++)if(a.variants[c].id==b.id)return a.variants[c];return null}function cc(a,b){for(var c=0;c<a.textStreams.length;c++)if(a.textStreams[c].id==b.id)return a.textStreams[c];return null}
|
|
function $b(a){return a.filter(function(a){return a.allowedByApplication&&a.allowedByKeySystem})}
|
|
function dc(a,b,c,d){var e=$b(a.variants),f=e.filter(function(a){return a.language==e[0].language});a=e.filter(function(a){return a.primary});a.length&&(f=a);if(b){var g=Sb(b);[Rb,Qb,0].forEach(function(a){var b=!1;e.forEach(function(d){g=Sb(g);var e=Sb(d.language);Pb(a,g,e)&&(b?f.push(d):(f=[d],b=!0),c&&(c.audio=!0))})})}var h=d||"";return h&&(b=f.filter(function(a){return a.audio&&-1<a.audio.roles.indexOf(h)||a.video&&-1<a.video.roles.indexOf(h)}),b.length)?b:f}
|
|
function ec(a,b,c,d){var e=a.textStreams,f=e;a=e.filter(function(a){return a.primary});a.length&&(f=a);if(b){var g=Sb(b);[Rb,Qb,0].forEach(function(a){var b=!1;e.forEach(function(d){var e=Sb(d.language);Pb(a,g,e)&&(b?f.push(d):(f=[d],b=!0),c&&(c.text=!0))})})}var h=d||"";return h&&(b=f.filter(function(a){return a&&-1<a.roles.indexOf(h)}),b.length)?b:f}function fc(a,b,c){for(var d=0;d<c.length;d++)if(c[d].audio==a&&c[d].video==b)return c[d];return null}
|
|
function gc(a,b,c){function d(a,b){return null==a?null==b:b.id==a}for(var e=0;e<c.length;e++)if(d(a,c[e].audio)&&d(b,c[e].video))return c[e];return null}function Yb(a,b){var c=a;b&&(c+='; codecs="'+b+'"');return c}function hc(a,b){for(var c=a.periods.length-1;0<c;--c)if(b>=a.periods[c].startTime)return c;return 0}
|
|
function ic(a,b){for(var c=0;c<a.periods.length;++c){var d=a.periods[c];if("text"==b.type)for(var e=0;e<d.textStreams.length;++e){if(d.textStreams[e]==b)return c}else for(e=0;e<d.variants.length;++e){var f=d.variants[e];if(f.audio==b||f.video==b||f.video&&f.video.trickModeVideo==b)return c}}return-1};function H(){this.f=null;this.b=!1;this.a=new fa;this.h=[];this.g=[];this.j=!1;this.c=null;this.i={minWidth:0,maxWidth:Infinity,minHeight:0,maxHeight:Infinity,minPixels:0,maxPixels:Infinity,minBandwidth:0,maxBandwidth:Infinity}}n("shaka.abr.SimpleAbrManager",H);H.prototype.stop=function(){this.f=null;this.b=!1;this.h=[];this.g=[];this.c=null};H.prototype.stop=H.prototype.stop;H.prototype.init=function(a){this.f=a};H.prototype.init=H.prototype.init;
|
|
H.prototype.chooseStreams=function(a){var b={};if(-1<a.indexOf("audio")||-1<a.indexOf("video")){var c=this.h;var d=jc(this.i,c);var e=this.a.getBandwidthEstimate();if(c.length&&!d.length)throw new t(2,4,4012);for(var c=d[0],f=0;f<d.length;++f){var g=d[f],h=(d[f+1]||{bandwidth:Infinity}).bandwidth/.85;e>=g.bandwidth/.95&&e<=h&&(c=g)}(d=c)&&d.video&&(b.video=d.video);d&&d.audio&&(b.audio=d.audio)}-1<a.indexOf("text")&&(b.text=this.g[0]);this.c=Date.now();return b};H.prototype.chooseStreams=H.prototype.chooseStreams;
|
|
H.prototype.enable=function(){this.b=!0};H.prototype.enable=H.prototype.enable;H.prototype.disable=function(){this.b=!1};H.prototype.disable=H.prototype.disable;H.prototype.segmentDownloaded=function(a,b){var c=this.a;if(!(16E3>b)){var d=8E3*b/a,e=a/1E3;c.a+=b;da(c.c,e,d);da(c.f,e,d)}if(null!=this.c&&this.b)a:{if(!this.j){if(!(128E3<=this.a.a))break a;this.j=!0}else if(8E3>Date.now()-this.c)break a;c=this.chooseStreams(["audio","video"]);this.a.getBandwidthEstimate();this.f(c)}};
|
|
H.prototype.segmentDownloaded=H.prototype.segmentDownloaded;H.prototype.getBandwidthEstimate=function(){return this.a.getBandwidthEstimate()};H.prototype.getBandwidthEstimate=H.prototype.getBandwidthEstimate;H.prototype.setDefaultEstimate=function(a){this.a.setDefaultEstimate(a)};H.prototype.setDefaultEstimate=H.prototype.setDefaultEstimate;H.prototype.setRestrictions=function(a){this.i=a};H.prototype.setRestrictions=H.prototype.setRestrictions;H.prototype.setVariants=function(a){this.h=a};
|
|
H.prototype.setVariants=H.prototype.setVariants;H.prototype.setTextStreams=function(a){this.g=a};H.prototype.setTextStreams=H.prototype.setTextStreams;function jc(a,b){return b.filter(function(b){return Ub(b,a,{width:Infinity,height:Infinity})}).sort(function(a,b){return a.bandwidth-b.bandwidth})};function I(a,b){var c=b||{},d;for(d in c)this[d]=c[d];this.defaultPrevented=this.cancelable=this.bubbles=!1;this.timeStamp=window.performance&&window.performance.now?window.performance.now():Date.now();this.type=a;this.isTrusted=!1;this.target=this.currentTarget=null;this.a=!1}I.prototype.preventDefault=function(){this.cancelable&&(this.defaultPrevented=!0)};I.prototype.stopImmediatePropagation=function(){this.a=!0};I.prototype.stopPropagation=function(){};var kc="ended play playing pause pausing ratechange seeked seeking timeupdate volumechange".split(" "),lc="buffered currentTime duration ended loop muted paused playbackRate seeking videoHeight videoWidth volume".split(" "),mc=["loop","playbackRate"],nc=["pause","play"],oc="adaptation buffering emsg error loading unloading texttrackvisibility timelineregionadded timelineregionenter timelineregionexit trackschanged".split(" "),pc="drmInfo getAudioLanguages getConfiguration getExpiration getManifestUri getPlaybackRate getPlayheadTimeAsDate getTextLanguages getTextTracks getTracks getStats getVariantTracks isBuffering isInProgress isLive isTextTrackVisible keySystem seekRange".split(" "),
|
|
qc=[["getConfiguration","configure"]],rc=[["isTextTrackVisible","setTextTrackVisibility"]],sc="addTextTrack cancelTrickPlay configure resetConfiguration selectAudioLanguage selectTextLanguage selectTextTrack selectTrack selectVariantTrack setTextTrackVisibility trickPlay".split(" "),uc=["load","unload"];
|
|
function vc(a){return JSON.stringify(a,function(a,c){if("manager"!=a&&"function"!=typeof c){if(c instanceof Event||c instanceof I){var b={},e;for(e in c){var f=c[e];f&&"object"==typeof f||e in Event||(b[e]=f)}return b}if(c instanceof TimeRanges)for(b={__type__:"TimeRanges",length:c.length,start:[],end:[]},e=0;e<c.length;++e)b.start.push(c.start(e)),b.end.push(c.end(e));else b="number"==typeof c?isNaN(c)?"NaN":isFinite(c)?c:0>c?"-Infinity":"Infinity":c;return b}})}
|
|
function wc(a){return JSON.parse(a,function(a,c){return"NaN"==c?NaN:"-Infinity"==c?-Infinity:"Infinity"==c?Infinity:c&&"object"==typeof c&&"TimeRanges"==c.__type__?xc(c):c})}function xc(a){return{length:a.length,start:function(b){return a.start[b]},end:function(b){return a.end[b]}}};function yc(a,b,c,d,e){this.J=a;this.l=b;this.B=c;this.G=d;this.v=e;this.c=this.j=this.h=!1;this.A="";this.a=this.i=null;this.b={video:{},player:{}};this.o=0;this.f={};this.g=null}k=yc.prototype;k.m=function(){zc(this);this.a&&(this.a.leave(function(){},function(){}),this.a=null);this.G=this.B=this.l=null;this.c=this.j=this.h=!1;this.g=this.f=this.b=this.i=null;return Promise.resolve()};k.V=function(){return this.c};k.Fb=function(){return this.A};
|
|
k.init=function(){if(window.chrome&&chrome.cast&&chrome.cast.isAvailable){delete window.__onGCastApiAvailable;this.h=!0;this.l();var a=new chrome.cast.SessionRequest(this.J),a=new chrome.cast.ApiConfig(a,this.gd.bind(this),this.sd.bind(this),"origin_scoped");chrome.cast.initialize(a,function(){},function(){})}else window.__onGCastApiAvailable=function(a){a&&this.init()}.bind(this)};k.Ib=function(a){this.i=a;this.c&&Ac(this,{type:"appData",appData:this.i})};
|
|
k.cast=function(a){if(!this.h)return Promise.reject(new t(1,8,8E3));if(!this.j)return Promise.reject(new t(1,8,8001));if(this.c)return Promise.reject(new t(1,8,8002));this.g=new A;chrome.cast.requestSession(this.Bb.bind(this,a),this.cc.bind(this));return this.g};k.$a=function(){this.c&&(zc(this),this.a&&(this.a.stop(function(){},function(){}),this.a=null))};
|
|
k.get=function(a,b){if("video"==a){if(0<=nc.indexOf(b))return this.pc.bind(this,a,b)}else if("player"==a){if(0<=sc.indexOf(b))return this.pc.bind(this,a,b);if(0<=uc.indexOf(b))return this.Od.bind(this,a,b);if(0<=pc.indexOf(b))return this.lc.bind(this,a,b)}return this.lc(a,b)};k.set=function(a,b,c){this.b[a][b]=c;Ac(this,{type:"set",targetName:a,property:b,value:c})};
|
|
k.Bb=function(a,b){this.a=b;this.a.addUpdateListener(this.dc.bind(this));this.a.addMessageListener("urn:x-cast:com.google.shaka.v2",this.md.bind(this));this.dc();Ac(this,{type:"init",initState:a,appData:this.i});this.g.resolve()};k.cc=function(a){var b=8003;switch(a.code){case "cancel":b=8004;break;case "timeout":b=8005;break;case "receiver_unavailable":b=8006}this.g.reject(new t(2,8,b,a))};k.lc=function(a,b){return this.b[a][b]};
|
|
k.pc=function(a,b){Ac(this,{type:"call",targetName:a,methodName:b,args:Array.prototype.slice.call(arguments,2)})};k.Od=function(a,b){var c=Array.prototype.slice.call(arguments,2),d=new A,e=this.o.toString();this.o++;this.f[e]=d;Ac(this,{type:"asyncCall",targetName:a,methodName:b,args:c,id:e});return d};k.gd=function(a){var b=this.v();this.g=new A;this.Bb(b,a)};k.sd=function(a){this.j="available"==a;this.l()};
|
|
k.dc=function(){var a=this.a?"connected"==this.a.status:!1;if(this.c&&!a){this.G();for(var b in this.b)this.b[b]={};zc(this)}this.A=(this.c=a)?this.a.receiver.friendlyName:"";this.l()};function zc(a){for(var b in a.f){var c=a.f[b];delete a.f[b];c.reject(new t(1,7,7E3))}}
|
|
k.md=function(a,b){var c=wc(b);switch(c.type){case "event":var d=c.targetName,e=c.event;this.B(d,new I(e.type,e));break;case "update":e=c.update;for(d in e){var c=this.b[d]||{};for(f in e[d])c[f]=e[d][f]}break;case "asyncComplete":d=c.id;var f=c.error;c=this.f[d];delete this.f[d];if(c)if(f){d=new t(f.severity,f.category,f.code);for(e in f)d[e]=f[e];c.reject(d)}else c.resolve()}};function Ac(a,b){var c=vc(b);a.a.sendMessage("urn:x-cast:com.google.shaka.v2",c,function(){},ga)};function p(){this.nb=new Ia;this.Ta=this}p.prototype.addEventListener=function(a,b){this.nb.push(a,b)};p.prototype.removeEventListener=function(a,b){this.nb.remove(a,b)};p.prototype.dispatchEvent=function(a){for(var b=this.nb.get(a.type)||[],c=0;c<b.length;++c){a.target=this.Ta;a.currentTarget=this.Ta;var d=b[c];try{d.handleEvent?d.handleEvent(a):d.call(this,a)}catch(e){}if(a.a)break}return a.defaultPrevented};function J(a,b,c){p.call(this);this.c=a;this.b=b;this.h=this.f=this.g=this.i=this.j=null;this.a=new yc(c,this.ee.bind(this),this.fe.bind(this),this.ge.bind(this),this.Vb.bind(this));Bc(this)}ba(J);n("shaka.cast.CastProxy",J);J.prototype.m=function(a){a&&this.a&&this.a.$a();a=[this.h?this.h.m():null,this.b?this.b.m():null,this.a?this.a.m():null];this.a=this.h=this.i=this.j=this.b=this.c=null;return Promise.all(a)};J.prototype.destroy=J.prototype.m;J.prototype.Zc=function(){return this.j};
|
|
J.prototype.getVideo=J.prototype.Zc;J.prototype.Tc=function(){return this.i};J.prototype.getPlayer=J.prototype.Tc;J.prototype.Fc=function(){return this.a?this.a.h&&this.a.j:!1};J.prototype.canCast=J.prototype.Fc;J.prototype.V=function(){return this.a?this.a.V():!1};J.prototype.isCasting=J.prototype.V;J.prototype.Fb=function(){return this.a?this.a.Fb():""};J.prototype.receiverName=J.prototype.Fb;J.prototype.cast=function(){var a=this.Vb();return this.a.cast(a).then(function(){return this.b.hb()}.bind(this))};
|
|
J.prototype.cast=J.prototype.cast;J.prototype.Ib=function(a){this.a.Ib(a)};J.prototype.setAppData=J.prototype.Ib;J.prototype.me=function(){var a=this.a;if(a.c){var b=a.v();chrome.cast.requestSession(a.Bb.bind(a,b),a.cc.bind(a))}};J.prototype.suggestDisconnect=J.prototype.me;J.prototype.$a=function(){this.a.$a()};J.prototype.forceDisconnect=J.prototype.$a;
|
|
function Bc(a){a.a.init();a.h=new D;kc.forEach(function(a){E(this.h,this.c,a,this.te.bind(this))}.bind(a));oc.forEach(function(a){E(this.h,this.b,a,this.Id.bind(this))}.bind(a));a.j={};for(var b in a.c)Object.defineProperty(a.j,b,{configurable:!1,enumerable:!0,get:a.se.bind(a,b),set:a.ue.bind(a,b)});a.i={};for(b in a.b)Object.defineProperty(a.i,b,{configurable:!1,enumerable:!0,get:a.Hd.bind(a,b)});a.g=new p;a.g.Ta=a.j;a.f=new p;a.f.Ta=a.i}k=J.prototype;
|
|
k.Vb=function(){var a={video:{},player:{},playerAfterLoad:{},manifest:this.b.Ya,startTime:null};this.c.pause();mc.forEach(function(b){a.video[b]=this.c[b]}.bind(this));this.c.ended||(a.startTime=this.c.currentTime);qc.forEach(function(b){var c=b[1];b=this.b[b[0]]();a.player[c]=b}.bind(this));rc.forEach(function(b){var c=b[1];b=this.b[b[0]]();a.playerAfterLoad[c]=b}.bind(this));return a};k.ee=function(){this.dispatchEvent(new I("caststatuschanged"))};
|
|
k.ge=function(){qc.forEach(function(a){var b=a[1];a=this.a.get("player",a[0])();this.b[b](a)}.bind(this));var a=this.a.get("player","getManifestUri")(),b=this.a.get("video","ended"),c=Promise.resolve(),d=this.c.autoplay,e=null;b||(e=this.a.get("video","currentTime"));a&&(this.c.autoplay=!1,c=this.b.load(a,e),c["catch"](function(a){this.b.dispatchEvent(new I("error",{detail:a}))}.bind(this)));var f={};mc.forEach(function(a){f[a]=this.a.get("video",a)}.bind(this));c.then(function(){mc.forEach(function(a){this.c[a]=
|
|
f[a]}.bind(this));rc.forEach(function(a){var b=a[1];a=this.a.get("player",a[0])();this.b[b](a)}.bind(this));this.c.autoplay=d;a&&this.c.play()}.bind(this))};
|
|
k.se=function(a){if("addEventListener"==a)return this.g.addEventListener.bind(this.g);if("removeEventListener"==a)return this.g.removeEventListener.bind(this.g);if(this.a.V()&&!Object.keys(this.a.b.video).length){var b=this.c[a];if("function"!=typeof b)return b}return this.a.V()?this.a.get("video",a):(b=this.c[a],"function"==typeof b&&(b=b.bind(this.c)),b)};k.ue=function(a,b){this.a.V()?this.a.set("video",a,b):this.c[a]=b};k.te=function(a){this.a.V()||this.g.dispatchEvent(new I(a.type,a))};
|
|
k.Hd=function(a){return"addEventListener"==a?this.f.addEventListener.bind(this.f):"removeEventListener"==a?this.f.removeEventListener.bind(this.f):"getNetworkingEngine"==a?this.b.Wb.bind(this.b):this.a.V()&&!Object.keys(this.a.b.video).length&&0<=pc.indexOf(a)||!this.a.V()?(a=this.b[a],a.bind(this.b)):this.a.get("player",a)};k.Id=function(a){this.a.V()||this.f.dispatchEvent(a)};k.fe=function(a,b){this.a.V()&&("video"==a?this.g.dispatchEvent(b):"player"==a&&this.f.dispatchEvent(b))};function K(a,b,c,d){p.call(this);this.a=a;this.b=b;this.j={video:a,player:b};this.l=c||function(){};this.o=d||function(a){return a};this.i=!1;this.f=!0;this.h=this.g=this.c=null;Cc(this)}ba(K);n("shaka.cast.CastReceiver",K);K.prototype.isConnected=function(){return this.i};K.prototype.isConnected=K.prototype.isConnected;K.prototype.ad=function(){return this.f};K.prototype.isIdle=K.prototype.ad;
|
|
K.prototype.m=function(){var a=this.b?this.b.m():Promise.resolve();null!=this.h&&window.clearTimeout(this.h);this.l=this.j=this.b=this.a=null;this.i=!1;this.f=!0;this.h=this.g=this.c=null;return a.then(function(){cast.receiver.CastReceiverManager.getInstance().stop()})};K.prototype.destroy=K.prototype.m;
|
|
function Cc(a){var b=cast.receiver.CastReceiverManager.getInstance();b.onSenderConnected=a.jc.bind(a);b.onSenderDisconnected=a.jc.bind(a);b.onSystemVolumeChanged=a.Mc.bind(a);a.g=b.getCastMessageBus("urn:x-cast:com.google.cast.media");a.g.onMessage=a.hd.bind(a);a.c=b.getCastMessageBus("urn:x-cast:com.google.shaka.v2");a.c.onMessage=a.vd.bind(a);b.start();kc.forEach(function(a){this.a.addEventListener(a,this.mc.bind(this,"video"))}.bind(a));oc.forEach(function(a){this.b.addEventListener(a,this.mc.bind(this,
|
|
"player"))}.bind(a));cast.__platform__&&cast.__platform__.canDisplayType('video/mp4; codecs="avc1.640028"; width=3840; height=2160')?a.b.Jb(3840,2160):a.b.Jb(1920,1080);a.b.addEventListener("loading",function(){this.f=!1;Dc(this)}.bind(a));a.a.addEventListener("playing",function(){this.f=!1;Dc(this)}.bind(a));a.a.addEventListener("pause",function(){Dc(this)}.bind(a));a.b.addEventListener("unloading",function(){this.f=!0;Dc(this)}.bind(a));a.a.addEventListener("ended",function(){window.setTimeout(function(){this.a&&
|
|
this.a.ended&&(this.f=!0,Dc(this))}.bind(this),5E3)}.bind(a))}k=K.prototype;k.jc=function(){this.i=!!cast.receiver.CastReceiverManager.getInstance().getSenders().length;Dc(this)};function Dc(a){Promise.resolve().then(function(){this.dispatchEvent(new I("caststatuschanged"));L(this,0)}.bind(a))}
|
|
function Ec(a,b,c){for(var d in b.player)a.b[d](b.player[d]);a.l(c);c=Promise.resolve();var e=a.a.autoplay;b.manifest&&(a.a.autoplay=!1,c=a.b.load(b.manifest,b.startTime),c["catch"](function(a){this.b.dispatchEvent(new I("error",{detail:a}))}.bind(a)));c.then(function(){var a;for(a in b.video){var c=b.video[a];this.a[a]=c}for(a in b.playerAfterLoad)c=b.playerAfterLoad[a],this.b[a](c);this.a.autoplay=e;b.manifest&&(this.a.play(),L(this,0))}.bind(a))}
|
|
k.mc=function(a,b){this.Cb();Fc(this,{type:"event",targetName:a,event:b},this.c)};k.Cb=function(){null!=this.h&&window.clearTimeout(this.h);this.h=window.setTimeout(this.Cb.bind(this),500);var a={video:{},player:{}};lc.forEach(function(b){a.video[b]=this.a[b]}.bind(this));pc.forEach(function(b){a.player[b]=this.b[b]()}.bind(this));var b=cast.receiver.CastReceiverManager.getInstance().getSystemVolume();b&&(a.video.volume=b.level,a.video.muted=b.muted);Fc(this,{type:"update",update:a},this.c)};
|
|
k.Mc=function(){var a=cast.receiver.CastReceiverManager.getInstance().getSystemVolume();a&&Fc(this,{type:"update",update:{video:{volume:a.level,muted:a.muted}}},this.c);Fc(this,{type:"event",targetName:"video",event:{type:"volumechange"}},this.c)};
|
|
k.vd=function(a){var b=wc(a.data);switch(b.type){case "init":Ec(this,b.initState,b.appData);this.Cb();break;case "appData":this.l(b.appData);break;case "set":var c=b.targetName,d=b.property,e=b.value;if("video"==c)if(b=cast.receiver.CastReceiverManager.getInstance(),"volume"==d){b.setSystemVolumeLevel(e);break}else if("muted"==d){b.setSystemVolumeMuted(e);break}this.j[c][d]=e;break;case "call":c=b.targetName;d=b.methodName;e=b.args;c=this.j[c];c[d].apply(c,e);break;case "asyncCall":c=b.targetName,
|
|
d=b.methodName,e=b.args,b=b.id,a=a.senderId,c=this.j[c],c[d].apply(c,e).then(this.vc.bind(this,a,b,null),this.vc.bind(this,a,b))}};
|
|
k.hd=function(a){var b=wc(a.data);switch(b.type){case "PLAY":this.a.play();L(this,0);break;case "PAUSE":this.a.pause();L(this,0);break;case "SEEK":a=b.currentTime;var c=b.resumeState;null!=a&&(this.a.currentTime=Number(a));c&&"PLAYBACK_START"==c?(this.a.play(),L(this,0)):c&&"PLAYBACK_PAUSE"==c&&(this.a.pause(),L(this,0));break;case "STOP":this.b.hb().then(function(){L(this,0)}.bind(this));break;case "GET_STATUS":L(this,Number(b.requestId));break;case "VOLUME":c=b.volume;a=c.level;var c=c.muted,d=
|
|
this.a.volume,e=this.a.muted;null!=a&&(this.a.volume=Number(a));null!=c&&(this.a.muted=c);d==this.a.volume&&e==this.a.muted||L(this,0);break;case "LOAD":c=b.media.contentId;a=b.currentTime;var f=this.o(c);this.a.autoplay=!0;this.b.load(f,a).then(function(){L(this,0,{contentId:f,streamType:this.b.$()?"LIVE":"BUFFERED",contentType:""})}.bind(this))["catch"](function(a){var c="LOAD_FAILED";7==a.category&&7E3==a.code&&(c="LOAD_CANCELLED");Fc(this,{requestId:Number(b.requestId),type:c},this.g)}.bind(this));
|
|
break;default:Fc(this,{requestId:Number(b.requestId),type:"INVALID_REQUEST",reason:"INVALID_COMMAND"},this.g)}};k.vc=function(a,b,c){Fc(this,{type:"asyncComplete",id:b,error:c},this.c,a)};function Fc(a,b,c,d){a.i&&(a=vc(b),d?c.getCastChannel(d).send(a):c.broadcast(a))}
|
|
function L(a,b,c){var d=Gc,d={mediaSessionId:0,playbackRate:a.a.playbackRate,playerState:a.f?d.IDLE:a.b.ka?d.Ac:a.a.paused?d.Bc:d.Cc,currentTime:a.a.currentTime,supportedMediaCommands:15,volume:{level:a.a.volume,muted:a.a.muted}};c&&(d.media=c);Fc(a,{requestId:b,type:"MEDIA_STATUS",status:[d]},a.g)}var Gc={IDLE:"IDLE",Cc:"PLAYING",Ac:"BUFFERING",Bc:"PAUSED"};function Hc(a,b){var c=M(a,b);return 1!=c.length?null:c[0]}function M(a,b){return Array.prototype.filter.call(a.childNodes,function(a){return a.tagName==b})}function Ic(a){var b=a.firstChild;return b&&b.nodeType==Node.TEXT_NODE?a.textContent.trim():null}function N(a,b,c,d){var e=null;a=a.getAttribute(b);null!=a&&(e=c(a));return null==e?void 0!=d?d:null:e}function Jc(a){if(!a)return null;a=Date.parse(a);return isNaN(a)?null:Math.floor(a/1E3)}
|
|
function Kc(a){if(!a)return null;a=/^P(?:([0-9]*)Y)?(?:([0-9]*)M)?(?:([0-9]*)D)?(?:T(?:([0-9]*)H)?(?:([0-9]*)M)?(?:([0-9.]*)S)?)?$/.exec(a);if(!a)return null;a=31536E3*Number(a[1]||null)+2592E3*Number(a[2]||null)+86400*Number(a[3]||null)+3600*Number(a[4]||null)+60*Number(a[5]||null)+Number(a[6]||null);return isFinite(a)?a:null}function Lc(a){var b=/([0-9]+)-([0-9]+)/.exec(a);if(!b)return null;a=Number(b[1]);if(!isFinite(a))return null;b=Number(b[2]);return isFinite(b)?{start:a,end:b}:null}
|
|
function Mc(a){a=Number(a);return a%1?null:a}function Nc(a){a=Number(a);return!(a%1)&&0<a?a:null}function Oc(a){a=Number(a);return!(a%1)&&0<=a?a:null}function Pc(a){var b;a=(b=a.match(/^(\d+)\/(\d+)$/))?Number(b[1]/b[2]):Number(a);return isNaN(a)?null:a};var Qc={"urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b":"org.w3.clearkey","urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed":"com.widevine.alpha","urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95":"com.microsoft.playready","urn:uuid:f239e769-efa3-4850-9c16-a903c6932efb":"com.adobe.primetime"};
|
|
function Rc(a,b,c){a=Sc(a);var d=null,e=null,f=[],g=[],h=a.map(function(a){return a.keyId}).filter(ya);if(0<h.length&&(e=h[0],h.some(za(e))))throw new t(2,4,4010);c||(g=a.filter(function(a){return"urn:mpeg:dash:mp4protection:2011"==a.sc?(d=a.init||d,!1):!0}),0<g.length&&(f=Tc(d,b,g),f.length||(f=[Ba("",d)])));0<a.length&&(c||!g.length)&&(f=Na(Qc).map(function(a){return Ba(a,d)}));e&&f.forEach(function(a){a.initData.forEach(function(a){a.keyId=e})});return{Sb:e,ze:d,drmInfos:f,Ub:!0}}
|
|
function Uc(a,b,c,d){var e=Rc(a,b,d);if(c.Ub){a=1==c.drmInfos.length&&!c.drmInfos[0].keySystem;b=!e.drmInfos.length;if(!c.drmInfos.length||a&&!b)c.drmInfos=e.drmInfos;c.Ub=!1}else if(0<e.drmInfos.length&&(c.drmInfos=c.drmInfos.filter(function(a){return e.drmInfos.some(function(b){return b.keySystem==a.keySystem})}),!c.drmInfos.length))throw new t(2,4,4008);return e.Sb||c.Sb}function Tc(a,b,c){return c.map(function(c){var d=Qc[c.sc];return d?[Ba(d,c.init||a)]:b(c.node)||[]}).reduce(x,[])}
|
|
function Sc(a){return a.map(function(a){var b=a.getAttribute("schemeIdUri"),d=a.getAttribute("cenc:default_KID"),e=M(a,"cenc:pssh").map(Ic);if(!b)return null;b=b.toLowerCase();if(d&&(d=d.replace(/-/g,"").toLowerCase(),0<=d.indexOf(" ")))throw new t(2,4,4009);var f=[];try{f=e.map(function(a){return{initDataType:"cenc",initData:Ya(a),keyId:null}})}catch(g){throw new t(2,4,4007);}return{node:a,sc:b,keyId:d,init:0<f.length?f:null}}).filter(ya)};function Vc(a,b,c,d,e){null!=e&&(e=Math.round(e));var f={RepresentationID:b,Number:c,Bandwidth:d,Time:e};return a.replace(/\$(RepresentationID|Number|Bandwidth|Time)?(?:%0([0-9]+)d)?\$/g,function(a,b,c){if("$$"==a)return"$";var d=f[b];if(null==d)return a;"RepresentationID"==b&&c&&(c=void 0);a=d.toString();c=window.parseInt(c,10)||1;return Array(Math.max(0,c-a.length)+1).join("0")+a})}
|
|
function Wc(a,b){var c=Xc(a,b,"timescale"),d=1;c&&(d=Nc(c)||1);c=Xc(a,b,"duration");(c=Nc(c||""))&&(c/=d);var e=Xc(a,b,"startNumber"),f=Xc(a,b,"presentationTimeOffset"),g=Oc(e||"");if(null==e||null==g)g=1;var h=Yc(a,b,"SegmentTimeline"),e=null;if(h){for(var e=d,l=Number(f),m=a.R.duration||Infinity,h=M(h,"S"),q=[],r=0,v=0;v<h.length;++v){var u=h[v],w=N(u,"t",Oc),G=N(u,"d",Oc),u=N(u,"r",Mc);null!=w&&(w-=l);if(!G)break;w=null!=w?w:r;u=u||0;if(0>u)if(v+1<h.length){u=N(h[v+1],"t",Oc);if(null==u)break;
|
|
else if(w>=u)break;u=Math.ceil((u-w)/G)-1}else{if(Infinity==m)break;else if(w/e>=m)break;u=Math.ceil((m*e-w)/G)-1}0<q.length&&w!=r&&(q[q.length-1].end=w/e);for(var pa=0;pa<=u;++pa)r=w+G,q.push({start:w/e,end:r/e,qe:w}),w=r}e=q}return{timescale:d,P:c,za:g,presentationTimeOffset:Number(f)/d||0,Pb:Number(f),F:e}}function Xc(a,b,c){return[b(a.w),b(a.S),b(a.T)].filter(ya).map(function(a){return a.getAttribute(c)}).reduce(function(a,b){return a||b})}
|
|
function Yc(a,b,c){return[b(a.w),b(a.S),b(a.T)].filter(ya).map(function(a){return Hc(a,c)}).reduce(function(a,b){return a||b})};function Zc(a,b,c){this.a=a;this.X=b;this.M=c}n("shaka.media.InitSegmentReference",Zc);function O(a,b,c,d,e,f){this.position=a;this.startTime=b;this.endTime=c;this.a=d;this.X=e;this.M=f}n("shaka.media.SegmentReference",O);function P(a,b){this.H=a;this.a=b==$c;this.u=0}n("shaka.util.DataViewReader",P);var $c=1;P.Endianness={ve:0,xe:$c};P.prototype.Z=function(){return this.u<this.H.byteLength};P.prototype.hasMoreData=P.prototype.Z;P.prototype.Vc=function(){return this.u};P.prototype.getPosition=P.prototype.Vc;P.prototype.Qc=function(){return this.H.byteLength};P.prototype.getLength=P.prototype.Qc;P.prototype.Eb=function(){try{var a=this.H.getUint8(this.u)}catch(b){ad()}this.u+=1;return a};P.prototype.readUint8=P.prototype.Eb;
|
|
P.prototype.oc=function(){try{var a=this.H.getUint16(this.u,this.a)}catch(b){ad()}this.u+=2;return a};P.prototype.readUint16=P.prototype.oc;P.prototype.D=function(){try{var a=this.H.getUint32(this.u,this.a)}catch(b){ad()}this.u+=4;return a};P.prototype.readUint32=P.prototype.D;P.prototype.nc=function(){try{var a=this.H.getInt32(this.u,this.a)}catch(b){ad()}this.u+=4;return a};P.prototype.readInt32=P.prototype.nc;
|
|
P.prototype.Pa=function(){try{if(this.a){var a=this.H.getUint32(this.u,!0);var b=this.H.getUint32(this.u+4,!0)}else b=this.H.getUint32(this.u,!1),a=this.H.getUint32(this.u+4,!1)}catch(c){ad()}if(2097151<b)throw new t(2,3,3001);this.u+=8;return b*Math.pow(2,32)+a};P.prototype.readUint64=P.prototype.Pa;P.prototype.Ka=function(a){this.u+a>this.H.byteLength&&ad();var b=this.H.buffer.slice(this.u,this.u+a);this.u+=a;return new Uint8Array(b)};P.prototype.readBytes=P.prototype.Ka;
|
|
P.prototype.I=function(a){this.u+a>this.H.byteLength&&ad();this.u+=a};P.prototype.skip=P.prototype.I;P.prototype.Db=function(){for(var a=this.u;this.Z()&&this.H.getUint8(this.u);)this.u+=1;a=this.H.buffer.slice(a,this.u);this.u+=1;return F(a)};P.prototype.readTerminatedString=P.prototype.Db;function ad(){throw new t(2,3,3E3);};function Q(){this.b=[];this.a=[]}n("shaka.util.Mp4Parser",Q);Q.prototype.C=function(a,b){var c=bd(a);this.b[c]=0;this.a[c]=b;return this};Q.prototype.box=Q.prototype.C;Q.prototype.da=function(a,b){var c=bd(a);this.b[c]=1;this.a[c]=b;return this};Q.prototype.fullBox=Q.prototype.da;Q.prototype.parse=function(a){for(a=new P(new DataView(a),0);a.Z();)this.eb(0,a)};Q.prototype.parse=Q.prototype.parse;
|
|
Q.prototype.eb=function(a,b){var c=b.u,d=b.D(),e=b.D();switch(d){case 0:d=b.H.byteLength-c;break;case 1:d=b.Pa()}var f=this.a[e];if(f){var g=null,h=null;1==this.b[e]&&(h=b.D(),g=h>>>24,h&=16777215);e=c+d-b.u;e=0<e?b.Ka(e).buffer:new ArrayBuffer(0);e=new P(new DataView(e),0);f({Na:this,version:g,Nc:h,s:e,size:d,start:c+a})}else b.I(c+d-b.u)};Q.prototype.parseNext=Q.prototype.eb;function R(a){for(;a.s.Z();)a.Na.eb(a.start,a.s)}Q.children=R;
|
|
function cd(a){for(var b=a.s.D();0<b;--b)a.Na.eb(a.start,a.s)}Q.sampleDescription=cd;function dd(a){return function(b){a(b.s.Ka(b.s.H.byteLength-b.s.u))}}Q.allData=dd;function bd(a){for(var b=0,c=0;c<a.length;c++)b=b<<8|a.charCodeAt(c);return b};function ed(a,b,c,d){var e,f=(new Q).da("sidx",function(a){e=fd(b,d,c,a)});a&&f.parse(a);if(e)return e;throw new t(2,3,3004);}
|
|
function fd(a,b,c,d){var e=[];d.s.I(4);var f=d.s.D();if(!f)throw new t(2,3,3005);if(d.version){var g=d.s.Pa();var h=d.s.Pa()}else g=d.s.D(),h=d.s.D();d.s.I(2);var l=d.s.oc();b=g-b;a=a+d.size+h;for(h=0;h<l;h++){var m=d.s.D();g=(m&2147483648)>>>31;var m=m&2147483647,q=d.s.D();d.s.I(4);if(1==g)throw new t(2,3,3006);e.push(new O(e.length,b/f,(b+q)/f,function(){return c},a,a+m-1));b+=q;a+=m}return e};function S(a){this.a=a}n("shaka.media.SegmentIndex",S);S.prototype.m=function(){this.a=null;return Promise.resolve()};S.prototype.destroy=S.prototype.m;S.prototype.find=function(a){for(var b=this.a.length-1;0<=b;--b){var c=this.a[b];if(a>=c.startTime&&a<c.endTime)return c.position}return this.a.length&&a<this.a[0].startTime?this.a[0].position:null};S.prototype.find=S.prototype.find;S.prototype.get=function(a){if(!this.a.length)return null;a-=this.a[0].position;return 0>a||a>=this.a.length?null:this.a[a]};
|
|
S.prototype.get=S.prototype.get;S.prototype.xb=function(a){for(var b,c,d=[],e=c=0;c<this.a.length&&e<a.length;){var f=this.a[c];b=a[e];f.startTime<b.startTime?(d.push(f),c++):(f.startTime>b.startTime||(.1<Math.abs(f.endTime-b.endTime)?d.push(b):d.push(f),c++),e++)}for(;c<this.a.length;)d.push(this.a[c++]);if(d.length)for(c=d[d.length-1].position+1;e<a.length;)b=a[e++],b=new O(c++,b.startTime,b.endTime,b.a,b.X,b.M),d.push(b);else d=a;this.a=d};S.prototype.merge=S.prototype.xb;
|
|
S.prototype.qb=function(a){for(var b=0;b<this.a.length&&!(this.a[b].endTime>a);++b);this.a.splice(0,b)};S.prototype.evict=S.prototype.qb;function gd(a,b){if(a.a.length){var c=a.a[a.a.length-1];c.startTime>b||(a.a[a.a.length-1]=new O(c.position,c.startTime,b,c.a,c.X,c.M))}};function hd(a){this.b=a;this.a=new P(a,0);id||(id=[new Uint8Array([255]),new Uint8Array([127,255]),new Uint8Array([63,255,255]),new Uint8Array([31,255,255,255]),new Uint8Array([15,255,255,255,255]),new Uint8Array([7,255,255,255,255,255]),new Uint8Array([3,255,255,255,255,255,255]),new Uint8Array([1,255,255,255,255,255,255,255])])}var id;hd.prototype.Z=function(){return this.a.Z()};
|
|
function jd(a){var b=kd(a);if(7<b.length)throw new t(2,3,3002);for(var c=0,d=0;d<b.length;d++)c=256*c+b[d];b=c;c=kd(a);a:{for(d=0;d<id.length;d++)if(ab(c,id[d])){d=!0;break a}d=!1}if(d)c=a.b.byteLength-a.a.u;else{if(8==c.length&&c[1]&224)throw new t(2,3,3001);for(var d=c[0]&(1<<8-c.length)-1,e=1;e<c.length;e++)d=256*d+c[e];c=d}c=a.a.u+c<=a.b.byteLength?c:a.b.byteLength-a.a.u;d=new DataView(a.b.buffer,a.b.byteOffset+a.a.u,c);a.a.I(c);return new ld(b,d)}
|
|
function kd(a){var b=a.a.Eb(),c;for(c=1;8>=c&&!(b&1<<8-c);c++);if(8<c)throw new t(2,3,3002);var d=new Uint8Array(c);d[0]=b;for(b=1;b<c;b++)d[b]=a.a.Eb();return d}function ld(a,b){this.id=a;this.a=b}function md(a){if(8<a.a.byteLength)throw new t(2,3,3002);if(8==a.a.byteLength&&a.a.getUint8(0)&224)throw new t(2,3,3001);for(var b=0,c=0;c<a.a.byteLength;c++)var d=a.a.getUint8(c),b=256*b+d;return b};function nd(){}
|
|
nd.prototype.parse=function(a,b,c,d){var e;b=new hd(new DataView(b));if(440786851!=jd(b).id)throw new t(2,3,3008);var f=jd(b);if(408125543!=f.id)throw new t(2,3,3009);b=f.a.byteOffset;f=new hd(f.a);for(e=null;f.Z();){var g=jd(f);if(357149030==g.id){e=g;break}}if(!e)throw new t(2,3,3010);f=new hd(e.a);e=1E6;for(g=null;f.Z();){var h=jd(f);if(2807729==h.id)e=md(h);else if(17545==h.id)if(g=h,4==g.a.byteLength)g=g.a.getFloat32(0);else if(8==g.a.byteLength)g=g.a.getFloat64(0);else throw new t(2,3,3003);
|
|
}if(null==g)throw new t(2,3,3011);f=e/1E9;e=g*f;a=jd(new hd(new DataView(a)));if(475249515!=a.id)throw new t(2,3,3007);return od(a,b,f,e,c,d)};function od(a,b,c,d,e,f){function g(){return e}var h=[];a=new hd(a.a);for(var l=-1,m=-1;a.Z();){var q=jd(a);if(187==q.id){var r=pd(q);r&&(q=c*(r.re-f),r=b+r.Nd,0<=l&&h.push(new O(h.length,l,q,g,m,r-1)),l=q,m=r)}}0<=l&&h.push(new O(h.length,l,d,g,m,null));return h}
|
|
function pd(a){var b=new hd(a.a);a=jd(b);if(179!=a.id)throw new t(2,3,3013);a=md(a);b=jd(b);if(183!=b.id)throw new t(2,3,3012);for(var b=new hd(b.a),c=0;b.Z();){var d=jd(b);if(241==d.id){c=md(d);break}}return{re:a,Nd:c}};function qd(a,b){var c=Yc(a,b,"Initialization");if(!c)return null;var d=a.w.U,e=c.getAttribute("sourceURL");e&&(d=z(a.w.U,[e]));var e=0,f=null;if(c=N(c,"range",Lc))e=c.start,f=c.end;return new Zc(function(){return d},e,f)}
|
|
function rd(a,b){var c=Xc(a,sd,"presentationTimeOffset"),d=qd(a,sd);var e=Number(c);var f=a.w.contentType,g=a.w.mimeType.split("/")[1];if("text"!=f&&"mp4"!=g&&"webm"!=g)throw new t(2,4,4006);if("webm"==g&&!d)throw new t(2,4,4005);var f=Yc(a,sd,"RepresentationIndex"),h=Xc(a,sd,"indexRange"),l=a.w.U,h=Lc(h||"");if(f){var m=f.getAttribute("sourceURL");m&&(l=z(a.w.U,[m]));h=N(f,"range",Lc,h)}if(!h)throw new t(2,4,4002);e=td(a,b,d,l,h.start,h.end,g,e);return{createSegmentIndex:e.createSegmentIndex,findSegmentPosition:e.findSegmentPosition,
|
|
getSegmentReference:e.getSegmentReference,initSegmentReference:d,presentationTimeOffset:Number(c)||0}}
|
|
function td(a,b,c,d,e,f,g,h){var l=a.presentationTimeline,m=!a.Da||!a.R.ub,q=a.R.duration,r=b,v=null;return{createSegmentIndex:function(){var a=[r(d,e,f),"webm"==g?r(c.a(),c.X,c.M):null];r=null;return Promise.all(a).then(function(a){var b=a[0];a=a[1]||null;b="mp4"==g?ed(b,e,d,h):(new nd).parse(b,a,d,h);l.Ha(0,b);v=new S(b);m&&gd(v,q)})},findSegmentPosition:function(a){return v.find(a)},getSegmentReference:function(a){return v.get(a)}}}function sd(a){return a.Qa};function ud(a,b){var c=qd(a,vd);var d=wd(a);var e=Wc(a,vd),f=e.za;f||(f=1);var g=0;e.P?g=e.P*(f-1):e.F&&0<e.F.length&&(g=e.F[0].start);d={P:e.P,startTime:g,za:f,presentationTimeOffset:e.presentationTimeOffset,F:e.F,Ga:d};if(!d.P&&!d.F&&1<d.Ga.length)throw new t(2,4,4002);if(!d.P&&!a.R.duration&&!d.F&&1==d.Ga.length)throw new t(2,4,4002);if(d.F&&!d.F.length)throw new t(2,4,4002);f=e=null;a.T.id&&a.w.id&&(f=a.T.id+","+a.w.id,e=b[f]);g=xd(a.R.duration,d.za,a.w.U,d);e?(e.xb(g),e.qb(a.presentationTimeline.ma()-
|
|
a.R.start)):(a.presentationTimeline.Ha(0,g),e=new S(g),f&&a.Da&&(b[f]=e));a.Da&&a.R.ub||gd(e,a.R.duration);return{createSegmentIndex:Promise.resolve.bind(Promise),findSegmentPosition:e.find.bind(e),getSegmentReference:e.get.bind(e),initSegmentReference:c,presentationTimeOffset:d.presentationTimeOffset}}function vd(a){return a.oa}
|
|
function xd(a,b,c,d){var e=d.Ga.length;d.F&&d.F.length!=d.Ga.length&&(e=Math.min(d.F.length,d.Ga.length));for(var f=[],g=d.startTime,h=0;h<e;h++){var l=d.Ga[h],m=z(c,[l.cd]);var q=null!=d.P?g+d.P:d.F?d.F[h].end:g+a;f.push(new O(h+b,g,q,function(a){return a}.bind(null,m),l.start,l.end));g=q}return f}
|
|
function wd(a){return[a.w.oa,a.S.oa,a.T.oa].filter(ya).map(function(a){return M(a,"SegmentURL")}).reduce(function(a,c){return 0<a.length?a:c}).map(function(b){b.getAttribute("indexRange")&&!a.$b&&(a.$b=!0);var c=b.getAttribute("media");b=N(b,"mediaRange",Lc,{start:0,end:null});return{cd:c,start:b.start,end:b.end}})};function yd(a,b,c,d){var e=zd(a);var f=Wc(a,Ad);var g=Xc(a,Ad,"media"),h=Xc(a,Ad,"index");f={P:f.P,timescale:f.timescale,za:f.za,presentationTimeOffset:f.presentationTimeOffset,Pb:f.Pb,F:f.F,wb:g,Ma:h};g=0+(f.Ma?1:0);g+=f.F?1:0;g+=f.P?1:0;if(!g)throw new t(2,4,4002);1!=g&&(f.Ma&&(f.F=null),f.P=null);if(!f.Ma&&!f.wb)throw new t(2,4,4002);if(f.Ma){c=a.w.mimeType.split("/")[1];if("mp4"!=c&&"webm"!=c)throw new t(2,4,4006);if("webm"==c&&!e)throw new t(2,4,4005);d=Vc(f.Ma,a.w.id,null,a.bandwidth||null,
|
|
null);d=z(a.w.U,[d]);a=td(a,b,e,d,0,null,c,f.presentationTimeOffset)}else f.P?(d||a.presentationTimeline.yb(f.P),a=Bd(a,f)):(d=b=null,a.T.id&&a.w.id&&(d=a.T.id+","+a.w.id,b=c[d]),g=Cd(a,f),b?(b.xb(g),b.qb(a.presentationTimeline.ma()-a.R.start)):(a.presentationTimeline.Ha(0,g),b=new S(g),d&&a.Da&&(c[d]=b)),a.Da&&a.R.ub||gd(b,a.R.duration),a={createSegmentIndex:Promise.resolve.bind(Promise),findSegmentPosition:b.find.bind(b),getSegmentReference:b.get.bind(b)});return{createSegmentIndex:a.createSegmentIndex,
|
|
findSegmentPosition:a.findSegmentPosition,getSegmentReference:a.getSegmentReference,initSegmentReference:e,presentationTimeOffset:f.presentationTimeOffset}}function Ad(a){return a.Ra}
|
|
function Bd(a,b){var c=a.R.duration,d=b.P,e=b.za,f=b.timescale,g=b.wb,h=a.bandwidth||null,l=a.w.id,m=a.w.U;return{createSegmentIndex:Promise.resolve.bind(Promise),findSegmentPosition:function(a){return 0>a||c&&a>=c?null:Math.floor(a/d)},getSegmentReference:function(a){var b=a*d;return 0>b||c&&b>=c?null:new O(a,b,b+d,function(){var c=Vc(g,l,a+e,h,b*f);return z(m,[c])},0,null)}}}
|
|
function Cd(a,b){for(var c=[],d=0;d<b.F.length;d++){var e=d+b.za;c.push(new O(e,b.F[d].start,b.F[d].end,function(a,b,c,d,e,q){a=Vc(a,b,e,c,q);return z(d,[a]).map(function(a){return a.toString()})}.bind(null,b.wb,a.w.id,a.bandwidth||null,a.w.U,e,b.F[d].qe+b.Pb),0,null))}return c}function zd(a){var b=Xc(a,Ad,"initialization");if(!b)return null;var c=a.w.id,d=a.bandwidth||null,e=a.w.U;return new Zc(function(){var a=Vc(b,c,null,d,null);return z(e,[a])},0,null)};var Dd={},Ed={};n("shaka.media.ManifestParser.registerParserByExtension",function(a,b){Ed[a]=b});n("shaka.media.ManifestParser.registerParserByMime",function(a,b){Dd[a]=b});function Fd(){var a={},b;for(b in Dd)a[b]=!0;for(b in Ed)a[b]=!0;["application/dash+xml","application/x-mpegurl","application/vnd.apple.mpegurl","application/vnd.ms-sstr+xml"].forEach(function(b){a[b]=!!Dd[b]});["mpd","m3u8","ism"].forEach(function(b){a[b]=!!Ed[b]});return a}
|
|
function Gd(a,b,c,d){var e=d;e||(d=(new ia(a)).W.split("/").pop().split("."),1<d.length&&(d=d.pop().toLowerCase(),e=Ed[d]));if(e)return Promise.resolve(e);c=C([a],c);c.method="HEAD";return b.request(0,c).then(function(b){(b=b.headers["content-type"])&&(b=b.toLowerCase());return(e=Dd[b])?e:Promise.reject(new t(2,4,4E3,a))},function(a){a.severity=2;return Promise.reject(a)})};function T(a,b){this.f=a;this.i=b;this.c=this.a=Infinity;this.b=1;this.h=0;this.g=!0}n("shaka.media.PresentationTimeline",T);T.prototype.Y=function(){return this.a};T.prototype.getDuration=T.prototype.Y;T.prototype.pa=function(a){this.a=a};T.prototype.setDuration=T.prototype.pa;T.prototype.Wc=function(){return this.f};T.prototype.getPresentationStartTime=T.prototype.Wc;T.prototype.wc=function(a){this.h=a};T.prototype.setClockOffset=T.prototype.wc;T.prototype.yc=function(a){this.g=a};
|
|
T.prototype.setStatic=T.prototype.yc;T.prototype.Xc=function(){return this.c};T.prototype.getSegmentAvailabilityDuration=T.prototype.Xc;T.prototype.xc=function(a){this.c=a};T.prototype.setSegmentAvailabilityDuration=T.prototype.xc;T.prototype.Ha=function(a,b){b.length&&(this.b=b.reduce(function(a,b){return Math.max(a,b.endTime-b.startTime)},this.b))};T.prototype.notifySegments=T.prototype.Ha;T.prototype.yb=function(a){this.b=Math.max(this.b,a)};T.prototype.notifyMaxSegmentDuration=T.prototype.yb;
|
|
T.prototype.$=function(){return Infinity==this.a&&!this.g};T.prototype.isLive=T.prototype.$;T.prototype.va=function(){return Infinity!=this.a&&!this.g};T.prototype.isInProgress=T.prototype.va;T.prototype.ma=function(){return this.Ea(0)};T.prototype.getSegmentAvailabilityStart=T.prototype.ma;T.prototype.Ea=function(a){if(Infinity==this.c)return 0;var b=this.ua();return Math.max(0,Math.min(b-this.c+a,b))};T.prototype.getSafeAvailabilityStart=T.prototype.Ea;
|
|
T.prototype.ua=function(){return this.$()||this.va()?Math.min(Math.max(0,(Date.now()+this.h)/1E3-this.b-this.f),this.a):this.a};T.prototype.getSegmentAvailabilityEnd=T.prototype.ua;T.prototype.bb=function(){return Math.max(0,this.ua()-(this.$()||this.va()?this.i:0))};T.prototype.getSeekRangeEnd=T.prototype.bb;function Hd(){this.a=this.b=null;this.g=[];this.c=null;this.i=[];this.h=1;this.j={};this.l=0;this.f=null}n("shaka.dash.DashParser",Hd);k=Hd.prototype;k.configure=function(a){this.b=a};k.start=function(a,b){this.g=[a];this.a=b;return Id(this).then(function(){this.a&&Jd(this,0);return this.c}.bind(this))};k.stop=function(){this.b=this.a=null;this.g=[];this.c=null;this.i=[];this.j={};null!=this.f&&(window.clearTimeout(this.f),this.f=null);return Promise.resolve()};k.update=function(){Id(this)["catch"](function(a){if(this.a)this.a.onError(a)}.bind(this))};
|
|
k.onExpirationUpdated=function(){};function Id(a){return a.a.networkingEngine.request(0,C(a.g,a.b.retryParameters)).then(function(a){if(this.a)return Kd(this,a.data,a.uri)}.bind(a))}
|
|
function Kd(a,b,c){var d=F(b),e=new DOMParser,f=null;b=null;try{f=e.parseFromString(d,"text/xml")}catch(v){}f&&"MPD"==f.documentElement.tagName&&(b=f.documentElement);b&&0<b.getElementsByTagName("parsererror").length&&(b=null);if(!b)throw new t(2,4,4001);c=[c];d=M(b,"Location").map(Ic).filter(ya);0<d.length&&(c=a.g=d);d=M(b,"BaseURL").map(Ic);c=z(c,d);var g=N(b,"minBufferTime",Kc);a.l=N(b,"minimumUpdatePeriod",Kc,-1);var h=N(b,"availabilityStartTime",Jc),d=N(b,"timeShiftBufferDepth",Kc),l=N(b,"suggestedPresentationDelay",
|
|
Kc),e=N(b,"maxSegmentDuration",Kc),f=b.getAttribute("type")||"static";if(a.c)var m=a.c.presentationTimeline;else{var q=Math.max(10,1.5*g);m=new T(h,null!=l?l:q)}var h=Ld(a,{Da:"static"!=f,presentationTimeline:m,T:null,R:null,S:null,w:null,bandwidth:void 0,$b:!1},c,b),l=h.duration,r=h.periods;m.yc("static"==f);m.pa(l||Infinity);m.xc(null!=d?d:Infinity);m.yb(e||1);if(a.c)return Promise.resolve();b=M(b,"UTCTiming");return Md(a,c,b,m.$()).then(function(a){this.a&&(m.wc(a),this.c={presentationTimeline:m,
|
|
periods:r,offlineSessionIds:[],minBufferTime:g||0})}.bind(a))}
|
|
function Ld(a,b,c,d){var e=N(d,"mediaPresentationDuration",Kc),f=[],g=0;d=M(d,"Period");for(var h=0;h<d.length;h++){var l=d[h],g=N(l,"start",Kc,g),m=N(l,"duration",Kc),q=null;if(h!=d.length-1){var r=N(d[h+1],"start",Kc);null!=r&&(q=r-g)}else null!=e&&(q=e-g);null==q&&(q=m);l=Nd(a,b,c,{start:g,duration:q,node:l,ub:null==q||h==d.length-1});f.push(l);m=b.T.id;a.i.every(za(m))&&(a.a.filterPeriod(l),a.i.push(m),a.c&&a.c.periods.push(l));if(null==q){g=null;break}g+=q}return null!=e?{periods:f,duration:e}:
|
|
{periods:f,duration:g}}
|
|
function Nd(a,b,c,d){b.T=Od(d.node,null,c);b.R=d;b.T.id||(b.T.id="__shaka_period_"+d.start);M(d.node,"EventStream").forEach(a.Fd.bind(a,d.start,d.duration));c=M(d.node,"AdaptationSet").map(a.Dd.bind(a,b)).filter(ya);var e=c.map(function(a){return a.Pd}).reduce(x,[]),f=e.filter(Aa);if(b.Da&&e.length!=f.length)throw new t(2,4,4018);var g=c.filter(function(a){return!a.Ob});c.filter(function(a){return a.Ob}).forEach(function(a){var b=a.streams[0],c=a.Ob;g.forEach(function(a){a.id==c&&a.streams.forEach(function(a){a.trickModeVideo=
|
|
b})})});e=Pd(g,"video");f=Pd(g,"audio");if(!e.length&&!f.length)throw new t(2,4,4004);f.length||(f=[null]);e.length||(e=[null]);b=[];for(c=0;c<f.length;c++)for(var h=0;h<e.length;h++)Qd(a,f[c],e[h],b);a=Pd(g,"text");e=[];for(c=0;c<a.length;c++)e.push.apply(e,a[c].streams);return{startTime:d.start,textStreams:e,variants:b}}function Pd(a,b){return a.filter(function(a){return a.contentType==b})}
|
|
function Qd(a,b,c,d){if(b||c)if(b&&c){var e=b.drmInfos;var f=c.drmInfos;if(e.length&&f.length?0<sb(e,f).length:1)for(var g=sb(b.drmInfos,c.drmInfos),e=0;e<b.streams.length;e++)for(var h=0;h<c.streams.length;h++)f=c.streams[h].bandwidth+b.streams[e].bandwidth,f={id:a.h++,language:b.language,primary:b.vb||c.vb,audio:b.streams[e],video:c.streams[h],bandwidth:f,drmInfos:g,allowedByApplication:!0,allowedByKeySystem:!0},d.push(f)}else for(g=b||c,e=0;e<g.streams.length;e++)f=g.streams[e].bandwidth,f={id:a.h++,
|
|
language:g.language||"und",primary:g.vb,audio:b?g.streams[e]:null,video:c?g.streams[e]:null,bandwidth:f,drmInfos:g.drmInfos,allowedByApplication:!0,allowedByKeySystem:!0},d.push(f)}
|
|
k.Dd=function(a,b){a.S=Od(b,a.T,null);var c=!1,d=M(b,"Role"),e=d.map(function(a){return a.getAttribute("value")}).filter(ya),f=void 0;"text"==a.S.contentType&&(f="subtitle");for(var g=0;g<d.length;g++){var h=d[g].getAttribute("schemeIdUri");if(null==h||"urn:mpeg:dash:role:2011"==h)switch(h=d[g].getAttribute("value"),h){case "main":c=!0;break;case "caption":case "subtitle":f=h}}var l=null,m=!1;M(b,"EssentialProperty").forEach(function(a){"http://dashif.org/guidelines/trickmode"==a.getAttribute("schemeIdUri")?
|
|
l=a.getAttribute("value"):m=!0});if(m)return null;var d=M(b,"ContentProtection"),q=Rc(d,this.b.dash.customScheme,this.b.dash.ignoreDrmInfo),d=Sb(b.getAttribute("lang")||"und"),h=b.getAttribute("label"),g=M(b,"Representation"),e=g.map(this.Gd.bind(this,a,q,f,d,h,c,e)).filter(function(a){return!!a});if(!e.length)throw new t(2,4,4003);a.S.contentType&&"application"!=a.S.contentType||(a.S.contentType=Rd(e[0].mimeType,e[0].codecs),e.forEach(function(b){b.type=a.S.contentType}));e.forEach(function(a){q.drmInfos.forEach(function(b){a.keyId&&
|
|
b.keyIds.push(a.keyId)})});f=g.map(function(a){return a.getAttribute("id")}).filter(ya);return{id:a.S.id||"__fake__"+this.h++,contentType:a.S.contentType,language:d,vb:c,streams:e,drmInfos:q.drmInfos,Ob:l,Pd:f}};
|
|
k.Gd=function(a,b,c,d,e,f,g,h){a.w=Od(h,a.S,null);if(!Sd(a.w))return null;a.bandwidth=N(h,"bandwidth",Nc)||void 0;var l=this.Qd.bind(this);if(a.w.Qa)l=rd(a,l);else if(a.w.oa)l=ud(a,this.j);else if(a.w.Ra)l=yd(a,l,this.j,!!this.c);else{var m=a.w.U,q=a.R.duration||0;l={createSegmentIndex:Promise.resolve.bind(Promise),findSegmentPosition:function(a){return 0<=a&&a<q?1:null},getSegmentReference:function(a){return 1!=a?null:new O(1,0,q,function(){return m},0,null)},initSegmentReference:null,presentationTimeOffset:0}}h=
|
|
M(h,"ContentProtection");h=Uc(h,this.b.dash.customScheme,b,this.b.dash.ignoreDrmInfo);return{id:this.h++,createSegmentIndex:l.createSegmentIndex,findSegmentPosition:l.findSegmentPosition,getSegmentReference:l.getSegmentReference,initSegmentReference:l.initSegmentReference,presentationTimeOffset:l.presentationTimeOffset,mimeType:a.w.mimeType,codecs:a.w.codecs,frameRate:a.w.frameRate,bandwidth:a.bandwidth,width:a.w.width,height:a.w.height,kind:c,encrypted:0<b.drmInfos.length,keyId:h,language:d,label:e,
|
|
type:a.S.contentType,primary:f,trickModeVideo:null,containsEmsgBoxes:a.w.containsEmsgBoxes,roles:g}};k.he=function(){this.f=null;var a=Date.now();Id(this).then(function(){this.a&&Jd(this,(Date.now()-a)/1E3)}.bind(this))["catch"](function(a){this.a&&(a.severity=1,this.a.onError(a),Jd(this,0))}.bind(this))};function Jd(a,b){0>a.l||(a.f=window.setTimeout(a.he.bind(a),1E3*Math.max(Math.max(3,a.l)-b,0)))}
|
|
function Od(a,b,c){b=b||{contentType:"",mimeType:"",codecs:"",containsEmsgBoxes:!1,frameRate:void 0};c=c||b.U;var d=M(a,"BaseURL").map(Ic),e=a.getAttribute("contentType")||b.contentType,f=a.getAttribute("mimeType")||b.mimeType,g=a.getAttribute("codecs")||b.codecs,h=N(a,"frameRate",Pc)||b.frameRate,l=!!M(a,"InbandEventStream").length;e||(e=Rd(f,g));return{U:z(c,d),Qa:Hc(a,"SegmentBase")||b.Qa,oa:Hc(a,"SegmentList")||b.oa,Ra:Hc(a,"SegmentTemplate")||b.Ra,width:N(a,"width",Oc)||b.width,height:N(a,"height",
|
|
Oc)||b.height,contentType:e,mimeType:f,codecs:g,frameRate:h,containsEmsgBoxes:l||b.containsEmsgBoxes,id:a.getAttribute("id")}}function Sd(a){var b=0+(a.Qa?1:0);b+=a.oa?1:0;b+=a.Ra?1:0;if(!b)return"text"==a.contentType||"application"==a.contentType?!0:!1;1!=b&&(a.Qa&&(a.oa=null),a.Ra=null);return!0}
|
|
function Td(a,b,c,d){b=z(b,[c]);b=C(b,a.b.retryParameters);b.method=d;return a.a.networkingEngine.request(0,b).then(function(a){if("HEAD"==d){if(!a.headers||!a.headers.date)return 0;a=a.headers.date}else a=F(a.data);a=Date.parse(a);return isNaN(a)?0:a-Date.now()})}
|
|
function Md(a,b,c,d){c=c.map(function(a){return{scheme:a.getAttribute("schemeIdUri"),value:a.getAttribute("value")}});var e=a.b.dash.clockSyncUri;d&&!c.length&&e&&c.push({scheme:"urn:mpeg:dash:utc:http-head:2014",value:e});return xa(c,function(a){var c=a.value;switch(a.scheme){case "urn:mpeg:dash:utc:http-head:2014":case "urn:mpeg:dash:utc:http-head:2012":return Td(this,b,c,"HEAD");case "urn:mpeg:dash:utc:http-xsdate:2014":case "urn:mpeg:dash:utc:http-iso:2014":case "urn:mpeg:dash:utc:http-xsdate:2012":case "urn:mpeg:dash:utc:http-iso:2012":return Td(this,
|
|
b,c,"GET");case "urn:mpeg:dash:utc:direct:2014":case "urn:mpeg:dash:utc:direct:2012":return a=Date.parse(c),isNaN(a)?0:a-Date.now();case "urn:mpeg:dash:utc:http-ntp:2014":case "urn:mpeg:dash:utc:ntp:2014":case "urn:mpeg:dash:utc:sntp:2014":return Promise.reject();default:return Promise.reject()}}.bind(a))["catch"](function(){return 0})}
|
|
k.Fd=function(a,b,c){var d=c.getAttribute("schemeIdUri")||"",e=c.getAttribute("value")||"",f=N(c,"timescale",Oc)||1;M(c,"Event").forEach(function(c){var g=N(c,"presentationTime",Oc)||0,l=N(c,"duration",Oc)||0,g=g/f+a,l=g+l/f;null!=b&&(g=Math.min(g,a+b),l=Math.min(l,a+b));c={schemeIdUri:d,value:e,startTime:g,endTime:l,id:c.getAttribute("id")||"",eventElement:c};this.a.onTimelineRegionAdded(c)}.bind(this))};
|
|
k.Qd=function(a,b,c){a=C(a,this.b.retryParameters);null!=b&&(a.headers.Range="bytes="+b+"-"+(null!=c?c:""));return this.a.networkingEngine.request(1,a).then(function(a){return a.data})};function Rd(a,b){return ub[Yb(a,b)]?"text":a.split("/")[0]}Ed.mpd=Hd;Dd["application/dash+xml"]=Hd;function Ud(a,b,c,d){this.uri=a;this.type=b;this.ga=c;this.segments=d||null}function Vd(a,b,c,d){this.id=a;this.name=b;this.a=c;this.value=d||null}Vd.prototype.toString=function(){function a(a){return a.name+'="'+a.value+'"'}return this.value?"#"+this.name+":"+this.value:0<this.a.length?"#"+this.name+":"+this.a.map(a).join(","):"#"+this.name};function Wd(a,b){this.name=a;this.value=b}Vd.prototype.getAttribute=function(a){var b=this.a.filter(function(b){return b.name==a});return b.length?b[0]:null};
|
|
function Xd(a,b,c){c=c||null;return(a=a.getAttribute(b))?a.value:c}function Yd(a,b){this.ga=b;this.uri=a};function Zd(a,b){return a.filter(function(a){return a.name==b})}function $d(a,b){var c=Zd(a,b);return c.length?c[0]:null}function ae(a,b,c){return a.filter(function(a){var d=a.getAttribute("TYPE");a=a.getAttribute("GROUP-ID");return d.value==b&&a.value==c})};function be(a){this.b=a;this.a=0}function ce(a,b){b.lastIndex=a.a;var c=(c=b.exec(a.b))?{position:c.index,length:c[0].length,Sd:c}:null;if(a.a==a.b.length||!c||c.position!=a.a)return null;a.a+=c.length;return c.Sd}function de(a){return a.a==a.b.length?null:(a=ce(a,/[^ \t\n]*/gm))?a[0]:null};function ee(){this.a=0}
|
|
function fe(a,b,c){b=F(b);b=b.replace(/\r\n|\r(?=[^\n]|$)/gm,"\n").trim();var d=b.split(/\n+/m);if(!/^#EXTM3U($|[ \t\n])/m.test(d[0]))throw new t(2,4,4015);b=0;for(var e=[],f=1;f<d.length;)if(/^#(?!EXT)/m.test(d[f]))f+=1;else{var g=d[f];g=ge(a.a++,g);if(0<=he.indexOf(g.name))b=1;else if(0<=ie.indexOf(g.name)){if(1!=b)throw new t(2,4,4017);d=d.splice(f,d.length-f);a=je(a,d);return new Ud(c,b,e,a)}e.push(g);f+=1;"EXT-X-STREAM-INF"==g.name&&(g.a.push(new Wd("URI",d[f])),f+=1)}return new Ud(c,b,e)}
|
|
function je(a,b){var c=[],d=[];b.forEach(function(a){/^(#EXT)/.test(a)?(a=ge(this.a++,a),d.push(a)):/^#(?!EXT)/m.test(a)||(c.push(new Yd(a.trim(),d)),d=[])}.bind(a));return c}function ge(a,b){var c=b.match(/^#(EXT[^:]*)(?::(.*))?$/);if(!c)throw new t(2,4,4016);var d=c[1],e=c[2],c=[];if(e&&0<=e.indexOf("="))for(var e=new be(e),f,g=/([^=]+)=(?:"([^"]*)"|([^",]*))(?:,|$)/g;f=ce(e,g);)c.push(new Wd(f[1],f[2]||f[3]));else if(e)return new Vd(a,d,c,e);return new Vd(a,d,c)}
|
|
var he="EXT-X-TARGETDURATION EXT-X-MEDIA-SEQUENCE EXT-X-DISCONTINUITY-SEQUENCE EXT-X-PLAYLIST-TYPE EXT-X-MAP EXT-X-I-FRAMES-ONLY".split(" "),ie="EXTINF EXT-X-BYTERANGE EXT-X-DISCONTINUITY EXT-X-PROGRAM-DATE-TIME EXT-X-KEY EXT-X-DATERANGE".split(" ");function ke(a){return new Promise(function(b){var c=ke.parse(a);b({uri:a,data:c.data,headers:{"content-type":c.contentType}})})}n("shaka.net.DataUriPlugin",ke);
|
|
ke.parse=function(a){var b=a.split(":");if(2>b.length||"data"!=b[0])throw new t(2,1,1004,a);b=b.slice(1).join(":").split(",");if(2>b.length)throw new t(2,1,1004,a);var c=b[0],b=window.decodeURIComponent(b.slice(1).join(",")),c=c.split(";"),d=null;1<c.length&&(d=c[1]);if("base64"==d)a=Ya(b).buffer;else{if(d)throw new t(2,1,1005,a);a=Ua(b)}return{data:a,contentType:c[0]}};Ea.data=ke;function le(){this.b=this.c=null;this.i=1;this.g={};this.f={};this.a=null;this.j="";this.h=new ee}n("shaka.hls.HlsParser",le);k=le.prototype;k.configure=function(a){this.b=a};k.start=function(a,b){this.c=b;this.j=a;return this.c.networkingEngine.request(0,C([a],this.b.retryParameters)).then(function(b){return ne(this,b.data,a)}.bind(this))};k.stop=function(){this.b=this.c=null;this.g={};return Promise.resolve()};k.update=function(){};k.onExpirationUpdated=function(){};
|
|
function ne(a,b,c){b=fe(a.h,b,c);if(0!=b.type)throw new t(2,4,4022);a.a=new T(null,0);return oe(a,b).then(function(a){this.c.filterPeriod(a);return{presentationTimeline:this.a,periods:[a],offlineSessionIds:[],minBufferTime:0}}.bind(a))}
|
|
function oe(a,b){var c=Zd(b.ga,"EXT-X-STREAM-INF").map(function(a){return pe(this,a,b)}.bind(a)),d=Zd(b.ga,"EXT-X-MEDIA").filter(function(a){return"SUBTITLES"==U(a,"TYPE")}.bind(a)).map(function(a){return qe(this,a,b)}.bind(a));return Promise.all(c).then(function(a){return Promise.all(d).then(function(b){var c=a.reduce(x,[]);re(this,c);return{startTime:0,variants:c,textStreams:b}}.bind(this))}.bind(a))}
|
|
function pe(a,b,c){var d=Number(U(b,"BANDWIDTH")),e=Xd(b,"CODECS","avc1.42E01E,mp4a.40.2").split(","),f=b.getAttribute("RESOLUTION"),g=null,h=null,l=Xd(b,"FRAME-RATE");if(f)var m=f.value.split("x"),g=m[0],h=m[1];var q=se(a,c);c=Zd(c.ga,"EXT-X-MEDIA");var r=Xd(b,"AUDIO"),v=Xd(b,"VIDEO");r?c=ae(c,"AUDIO",r):v&&(c=ae(c,"VIDEO",v));c=c.map(function(a){return te(this,a,e,q)}.bind(a));var u=[],w=[];return Promise.all(c).then(function(a){r?u=a:v&&(w=a);if(u.length||w.length)var c=u.length?"video":"audio";
|
|
else 1==e.length?c=f||l?"video":"audio":(c="video",e=[e.join(",")]);a=e;var d=U(b,"URI");return ue(this,d,a,c,q,"und",!1,null)}.bind(a)).then(function(a){"audio"==a.stream.type?u=[a]:w=[a];return ve(this,u,w,d,g,h,l)}.bind(a))}
|
|
function ve(a,b,c,d,e,f,g){c.forEach(function(a){if(a=a.stream)a.width=Number(e)||void 0,a.height=Number(f)||void 0,a.frameRate=Number(g)||void 0}.bind(a));b.length||(b=[null]);c.length||(c=[null]);for(var h=[],l=0;l<b.length;l++)for(var m=0;m<c.length;m++){var q=b[l]?b[l].stream:null,r=c[m]?c[m].stream:null,v=b[l]?b[l].drmInfos:null,u=c[m]?c[m].drmInfos:null;if(q&&r)if(v.length&&u.length?0<sb(v,u).length:1)var w=sb(v,u);else continue;else q?w=v:r&&(w=u);h.push(xe(a,q,r,d,w))}return h}
|
|
function xe(a,b,c,d,e){return{id:a.i++,language:b?b.language:"und",primary:!!b&&b.primary||!!c&&c.primary,audio:b,video:c,bandwidth:d,drmInfos:e,allowedByApplication:!0,allowedByKeySystem:!0}}function qe(a,b,c){U(b,"TYPE");c=se(a,c);return te(a,b,[],c).then(function(a){return a.stream})}
|
|
function te(a,b,c,d){if(a.g[b.id])return Promise.resolve().then(function(){return this.g[b.id]}.bind(a));var e=U(b,"TYPE").toLowerCase();"subtitles"==e&&(e="text");var f=Sb(Xd(b,"LANGUAGE","und")),g=Xd(b,"NAME"),h=b.getAttribute("DEFAULT"),l=b.getAttribute("AUTOSELECT"),m=U(b,"URI");return ue(a,m,c,e,d,f,!!h||!!l,g).then(function(a){return this.g[b.id]=a}.bind(a))}
|
|
function ue(a,b,c,d,e,f,g,h){b=z([a.j],[b])[0];return a.c.networkingEngine.request(0,C([b],a.b.retryParameters)).then(function(a){a=fe(this.h,a.data,a.uri);if(1!=a.type)throw new t(2,4,4017);e=se(this,a)||e;var b=null;"text"!=d&&(b=ye(a));var l=$d(a.ga,"EXT-X-MEDIA-SEQUENCE"),l=ze(this,a,l?Number(l.value):0);this.a.Ha(0,l);var r=l[l.length-1].endTime-l[0].startTime,v=this.a.Y();(Infinity==v||v<r)&&this.a.pa(r);var u=Ae(d,c),w=void 0;"text"==d&&(w="subtitle");var G=new S(l),pa=[];a.segments.forEach(function(a){a=
|
|
Zd(a.ga,"EXT-X-KEY");pa.push.apply(pa,a)});var Hb=!1,tc=[],me=null;pa.forEach(function(a){if("NONE"!=U(a,"METHOD")){Hb=!0;var b=U(a,"KEYFORMAT");if(a=(b=Be[b])?b(a):null)a.keyIds.length&&(me=a.keyIds[0]),tc.push(a)}});if(Hb&&!tc.length)throw new t(2,4,4026);return Ce(this,d,l[0].a()[0]).then(function(a){a={id:this.i++,createSegmentIndex:Promise.resolve.bind(Promise),findSegmentPosition:G.find.bind(G),getSegmentReference:G.get.bind(G),initSegmentReference:b,presentationTimeOffset:e||0,mimeType:a,codecs:u,
|
|
kind:w,encrypted:Hb,keyId:me,language:f,label:h||null,type:d,primary:g,trickModeVideo:null,containsEmsgBoxes:!1,frameRate:void 0,width:void 0,height:void 0,bandwidth:void 0,roles:[]};this.f[a.id]=G;return{stream:a,Ae:G,drmInfos:tc}}.bind(this))}.bind(a))}
|
|
function ye(a){var b=Zd(a.ga,"EXT-X-MAP");if(!b.length)return null;if(1<b.length)throw new t(2,4,4020);var b=b[0],c=U(b,"URI"),d=z([a.uri],[c])[0];a=0;c=null;if(b=Xd(b,"BYTERANGE"))a=b.split("@"),b=Number(a[0]),a=Number(a[1]),c=a+b-1;return new Zc(function(){return[d]},a,c)}
|
|
function ze(a,b,c){var d=b.segments,e=[];d.forEach(function(a){var f=a.ga,h=z([b.uri],[a.uri])[0],l=De(f).value.split(","),l=Number(l[0]),m;(a=d.indexOf(a))?m=e[a-1].endTime:m=0;var l=m+l,q=0,r=null;if(f=$d(f,"EXT-X-BYTERANGE"))f=f.value.split("@"),r=Number(f[0]),f[1]?q=Number(f[1]):q=e[a-1].M,r=q+r-1,a==d.length-1&&(r=null);e.push(new O(c+a,m,l,function(){return[h]},q,r))}.bind(a));return e}
|
|
function re(a,b){b.forEach(function(a){var b=this.a.Y(),c=a.video;a=a.audio;c&&this.f[c.id]&&gd(this.f[c.id],b);a&&this.f[a.id]&&gd(this.f[a.id],b)}.bind(a))}function Ae(a,b){if(1==b.length)return b[0];if("text"==a)return"";var c=Ee;"audio"==a&&(c=Fe);for(var d=0;d<c.length;d++)for(var e=0;e<b.length;e++)if(c[d].test(b[e].trim()))return b[e].trim();throw new t(2,4,4025,b);}
|
|
function Ce(a,b,c){var d=c.split("."),e=d[d.length-1];if("text"==b)return Promise.resolve("text/vtt");d=Ge;"video"==b&&(d=He);if(b=d[e])return Promise.resolve(b);c=C([c],a.b.retryParameters);c.method="HEAD";return a.c.networkingEngine.request(1,c).then(function(a){a=a.headers["content-type"];if(!a)throw new t(2,4,4021,e);return a})}function se(a,b){var c=$d(b.ga,"EXT-X-START");return c?Number(U(c,"TIME-OFFSET")):a.b.hls.defaultTimeOffset}
|
|
function U(a,b){var c=a.getAttribute(b);if(!c)throw new t(2,4,4023,b);return c.value}function De(a){a=$d(a,"EXTINF");if(!a)throw new t(2,4,4024,"EXTINF");return a}
|
|
var Ee=[/^(avc)/,/^(hvc)/,/^(vp[8-9])$/,/^(av1)$/,/^(mp4v)/],Fe=[/^(vorbis)/,/^(opus)/,/^(mp4a)/,/^(ac-3)$/,/^(ec-3)$/],Ge={mp4:"audio/mp4",m4s:"audio/mp4",m4i:"audio/mp4",m4a:"audio/mp4",ts:"video/mp2t"},He={mp4:"video/mp4",m4s:"video/mp4",m4i:"video/mp4",m4v:"video/mp4",ts:"video/mp2t"},Be={"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed":function(a){if("SAMPLE-AES-CENC"!=U(a,"METHOD"))return null;var b=U(a,"URI"),b=ke.parse(b),b=new Uint8Array(b.data),b=Ba("com.widevine.alpha",[{initDataType:"cenc",
|
|
initData:b}]);if(a=Xd(a,"KEYID"))b.keyIds=[a.substr(2).toLowerCase()];return b}};Ed.m3u8=le;Dd["application/x-mpegurl"]=le;Dd["application/vnd.apple.mpegurl"]=le;function Ie(){}Ie.prototype.parseInit=function(){};
|
|
Ie.prototype.parseMedia=function(a,b){var c=F(a),d=[],e=new DOMParser,f=null;try{f=e.parseFromString(c,"text/xml")}catch(Hb){throw new t(2,2,2005);}if(f){var g=f.getElementsByTagName("tt")[0];if(g){e=g.getAttribute("ttp:frameRate");f=g.getAttribute("ttp:subFrameRate");var h=g.getAttribute("ttp:frameRateMultiplier");var l=g.getAttribute("ttp:tickRate");c=g.getAttribute("xml:space")||"default"}else throw new t(2,2,2005);if("default"!=c&&"preserve"!=c)throw new t(2,2,2005);c="default"==c;e=new Je(e,
|
|
f,h,l);f=Ke(g.getElementsByTagName("styling")[0]);h=Ke(g.getElementsByTagName("layout")[0]);g=Ke(g.getElementsByTagName("body")[0]);for(l=0;l<g.length;l++){var m=g[l],q=b.periodStart,r=e;var v=f;var u=h,w=c;if(m.hasAttribute("begin")||m.hasAttribute("end")||!/^\s*$/.test(m.textContent)){Le(m,w);var w=Me(m.getAttribute("begin"),r),G=Me(m.getAttribute("end"),r),r=Me(m.getAttribute("dur"),r),pa=m.textContent;null==G&&null!=r&&(G=w+r);if(null==w||null==G)throw new t(2,2,2001);if(q=xb(w+q,G+q,pa)){w=Ne(m,
|
|
"region",u);u=q;if(G=Oe(m,w,v,"tts:extent"))if(r=Pe.exec(G))u.size=Number(r[1]);r=Oe(m,w,v,"tts:writingMode");G=!0;"tb"==r||"tblr"==r?u.vertical="lr":"tbrl"==r?u.vertical="rl":G=!1;if(r=Oe(m,w,v,"tts:origin"))if(r=Pe.exec(r))G?(u.position=Number(r[2]),u.line=Number(r[1])):(u.position=Number(r[1]),u.line=Number(r[2])),u.snapToLines=!1;if(v=Oe(m,w,v,"tts:textAlign"))u.align=v,"center"==v&&("center"!=u.align&&(u.align="middle"),u.position="auto"),u.positionAlign=Qe[v],u.lineAlign=Re[v];v=q}else v=null}else v=
|
|
null;v&&d.push(v)}}return d};var Se=/^(\d{2,}):(\d{2}):(\d{2}):(\d{2})\.?(\d+)?$/,Te=/^(?:(\d{2,}):)?(\d{2}):(\d{2})$/,Ue=/^(?:(\d{2,}):)?(\d{2}):(\d{2}\.\d{2,})$/,Ve=/^(\d*\.?\d*)f$/,We=/^(\d*\.?\d*)t$/,Xe=/^(?:(\d*\.?\d*)h)?(?:(\d*\.?\d*)m)?(?:(\d*\.?\d*)s)?(?:(\d*\.?\d*)ms)?$/,Pe=/^(\d{1,2}|100)% (\d{1,2}|100)%$/,Re={left:"start",center:"center",right:"end",start:"start",end:"end"},Qe={left:"line-left",center:"center",right:"line-right"};
|
|
function Ke(a){var b=[];if(!a)return b;for(var c=a.childNodes,d=0;d<c.length;d++){var e="span"==c[d].nodeName&&"p"==a.nodeName;c[d].nodeType!=Node.ELEMENT_NODE||"br"==c[d].nodeName||e||(e=Ke(c[d]),b=b.concat(e))}b.length||b.push(a);return b}function Le(a,b){for(var c=a.childNodes,d=0;d<c.length;d++)if("br"==c[d].nodeName&&0<d)c[d-1].textContent+="\n";else if(0<c[d].childNodes.length)Le(c[d],b);else if(b){var e=c[d].textContent.trim(),e=e.replace(/\s+/g," ");c[d].textContent=e}}
|
|
function Oe(a,b,c,d){for(var e=Ke(b),f=0;f<e.length;f++){var g=e[f].getAttribute(d);if(g)return g}e=Ne;return(a=e(b,"style",c)||e(a,"style",c))?a.getAttribute(d):null}function Ne(a,b,c){if(!a||1>c.length)return null;var d=null,e=a;for(a=null;e&&!(a=e.getAttribute(b))&&(e=e.parentNode,e instanceof Element););if(b=a)for(a=0;a<c.length;a++)if(c[a].getAttribute("xml:id")==b){d=c[a];break}return d}
|
|
function Me(a,b){var c=null;if(Se.test(a))var c=Se.exec(a),d=Number(c[1]),e=Number(c[2]),f=Number(c[3]),g=Number(c[4]),g=g+(Number(c[5])||0)/b.b,f=f+g/b.frameRate,c=f+60*e+3600*d;else Te.test(a)?c=Ye(Te,a):Ue.test(a)?c=Ye(Ue,a):Ve.test(a)?(c=Ve.exec(a),c=Number(c[1])/b.frameRate):We.test(a)?(c=We.exec(a),c=Number(c[1])/b.a):Xe.test(a)&&(c=Ye(Xe,a));return c}
|
|
function Ye(a,b){var c=a.exec(b);return c&&""!=c[0]?(Number(c[4])||0)/1E3+(Number(c[3])||0)+60*(Number(c[2])||0)+3600*(Number(c[1])||0):null}function Je(a,b,c,d){this.frameRate=Number(a)||30;this.b=Number(b)||1;this.a=Number(d);this.a||(this.a=a?this.frameRate*this.b:1);c&&(a=/^(\d+) (\d+)$/g.exec(c))&&(this.frameRate*=a[1]/a[2])}vb("application/ttml+xml",Ie);function Ze(){this.a=new Ie}Ze.prototype.parseInit=function(a){var b=!1;(new Q).C("moov",R).C("trak",R).C("mdia",R).C("minf",R).C("stbl",R).da("stsd",cd).C("stpp",function(){b=!0}).parse(a);if(!b)throw new t(2,2,2007);};Ze.prototype.parseMedia=function(a,b){var c=!1,d=[];(new Q).C("mdat",dd(function(a){c=!0;d=this.a.parseMedia(a.buffer,b)}.bind(this))).parse(a);if(!c)throw new t(2,2,2007);return d};vb('application/mp4; codecs="stpp"',Ze);function $e(){}$e.prototype.parseInit=function(){};
|
|
$e.prototype.parseMedia=function(a,b){var c=F(a),c=c.replace(/\r\n|\r(?=[^\n]|$)/gm,"\n"),c=c.split(/\n{2,}/m);if(!/^WEBVTT($|[ \t\n])/m.test(c[0]))throw new t(2,2,2E3);var d=b.segmentStart;if(0<=c[0].indexOf("X-TIMESTAMP-MAP")){var e=c[0].match(/LOCAL:((?:(\d{1,}):)?(\d{2}):(\d{2})\.(\d{3}))/m),f=c[0].match(/MPEGTS:(\d+)/m);e&&f&&(d=af(new be(e[1])),d=b.periodStart+(Number(f[1])/9E4-d))}f=[];for(e=1;e<c.length;e++){var g=c[e].split("\n"),h=d;if(1==g.length&&!g[0]||/^NOTE($|[ \t])/.test(g[0]))var l=
|
|
null;else{l=null;0>g[0].indexOf("--\x3e")&&(l=g[0],g.splice(0,1));var m=new be(g[0]),q=af(m),r=ce(m,/[ \t]+--\x3e[ \t]+/g),v=af(m);if(null==q||!r||null==v)throw new t(2,2,2001);if(g=xb(q+h,v+h,g.slice(1).join("\n").trim())){ce(m,/[ \t]+/gm);for(h=de(m);h;)bf(g,h),ce(m,/[ \t]+/gm),h=de(m);null!=l&&(g.id=l);l=g}else l=null}l&&f.push(l)}return f};
|
|
function bf(a,b){var c;if(c=/^align:(start|middle|center|end|left|right)$/.exec(b))a.align=c[1],"center"==c[1]&&"center"!=a.align&&(a.position="auto",a.align="middle");else if(c=/^vertical:(lr|rl)$/.exec(b))a.vertical=c[1];else if(c=/^size:(\d{1,2}|100)%$/.exec(b))a.size=Number(c[1]);else if(c=/^position:(\d{1,2}|100)%(?:,(line-left|line-right|center|start|end))?$/.exec(b))a.position=Number(c[1]),c[2]&&(a.positionAlign=c[2]);else if(c=/^line:(\d{1,2}|100)%(?:,(start|end|center))?$/.exec(b))a.snapToLines=
|
|
!1,a.line=Number(c[1]),c[2]&&(a.lineAlign=c[2]);else if(c=/^line:(-?\d+)(?:,(start|end|center))?$/.exec(b))a.snapToLines=!0,a.line=Number(c[1]),c[2]&&(a.lineAlign=c[2])}function af(a){a=ce(a,/(?:(\d{1,}):)?(\d{2}):(\d{2})\.(\d{3})/g);if(!a)return null;var b=Number(a[2]),c=Number(a[3]);return 59<b||59<c?null:Number(a[4])/1E3+c+60*b+3600*(Number(a[1])||0)}vb("text/vtt",$e);vb('text/vtt; codecs="vtt"',$e);function cf(){this.a=null}cf.prototype.parseInit=function(a){var b=!1;(new Q).C("moov",R).C("trak",R).C("mdia",R).da("mdhd",function(a){0==a.version?(a.s.I(4),a.s.I(4),this.a=a.s.D(),a.s.I(4)):(a.s.I(8),a.s.I(8),this.a=a.s.D(),a.s.I(8));a.s.I(4)}.bind(this)).C("minf",R).C("stbl",R).da("stsd",cd).C("wvtt",function(){b=!0}).parse(a);if(!this.a)throw new t(2,2,2008);if(!b)throw new t(2,2,2008);};
|
|
cf.prototype.parseMedia=function(a,b){var c=0,d=[],e=[],f=[],g=!1,h=!1,l=!1;(new Q).C("moof",R).C("traf",R).da("tfdt",function(a){g=!0;c=a.version?a.s.Pa():a.s.D()}).da("trun",function(a){h=!0;var b=a.version,c=a.Nc;a=a.s;var e=a.D();c&1&&a.I(4);c&4&&a.I(4);for(var f=[],g=0;g<e;g++){var l={duration:null,Nb:null};c&256&&(l.duration=a.D());c&512&&a.I(4);c&1024&&a.I(4);c&2048&&(l.Nb=b?a.nc():a.D());f.push(l)}d=f}).C("vtte",function(){e.push(null)}).C("vttc",dd(function(a){e.push(a.buffer)})).C("mdat",
|
|
function(a){l=!0;R(a)}).parse(a);if(!l&&!g&&!h)throw new t(2,2,2008);for(var m=c,q=0;q<d.length;q++){var r=d[q],v=e[q];if(r.duration){var u=r.Nb?c+r.Nb:m,m=u+r.duration;v&&f.push(df(v,b.periodStart+u/this.a,b.periodStart+m/this.a))}}return f};function df(a,b,c){var d,e,f;(new Q).C("payl",dd(function(a){d=F(a)})).C("iden",dd(function(a){e=F(a)})).C("sttg",dd(function(a){f=F(a)})).parse(a);return d?ef(d,e,f,b,c):null}
|
|
function ef(a,b,c,d,e){(a=xb(d,e,a))&&b&&(a.id=b);if(a&&c)for(b=new be(c),c=de(b);c;)bf(a,c),ce(b,/[ \t]+/gm),c=de(b);return a}vb('application/mp4; codecs="wvtt"',cf);function ff(a,b,c,d,e,f){this.a=a;this.c=b;this.l=c;this.A=d;this.J=e;this.G=f;this.b=new D;this.h=!1;this.g=1;this.j=this.f=null;this.B=a.readyState;this.i=!1;this.O=this.v=-1;this.o=!1;0<a.readyState?this.fc():La(this.b,a,"loadedmetadata",this.fc.bind(this));b=this.hc.bind(this);E(this.b,a,"ratechange",this.rd.bind(this));E(this.b,a,"waiting",b);this.j=setInterval(b,250)}k=ff.prototype;
|
|
k.m=function(){var a=this.b.m();this.b=null;null!=this.f&&(window.clearInterval(this.f),this.f=null);null!=this.j&&(window.clearInterval(this.j),this.j=null);this.G=this.J=this.l=this.c=this.a=null;return a};function gf(a,b){0<a.a.readyState?a.a.currentTime=hf(a,b):a.A=b}function jf(a){return 0<a.a.readyState?hf(a,a.a.currentTime):kf(a)}function kf(a){if(a.A)return hf(a,a.A);a=a.c.presentationTimeline;return Infinity>a.Y()?a.ma():a.bb()}k.rb=function(){return this.g};
|
|
function lf(a,b){null!=a.f&&(window.clearInterval(a.f),a.f=null);a.g=b;a.a.playbackRate=a.h||0>b?0:b;!a.h&&0>b&&(a.f=window.setInterval(function(){this.a.currentTime+=b/4}.bind(a),250))}k.Ab=function(){this.o=!0;this.hc()};k.rd=function(){this.a.playbackRate!=(this.h||0>this.g?0:this.g)&&lf(this,this.a.playbackRate)};
|
|
k.fc=function(){var a=kf(this);.001>Math.abs(this.a.currentTime-a)?(E(this.b,this.a,"seeking",this.ic.bind(this)),E(this.b,this.a,"playing",this.gc.bind(this))):(La(this.b,this.a,"seeking",this.td.bind(this)),this.a.currentTime=a)};k.td=function(){E(this.b,this.a,"seeking",this.ic.bind(this));E(this.b,this.a,"playing",this.gc.bind(this))};
|
|
k.hc=function(){if(this.a.readyState){this.a.readyState!=this.B&&(this.i=!1,this.B=this.a.readyState);var a=this.l.smallGapLimit,b=this.a.currentTime,c=this.a.buffered;a:{if(c&&c.length&&!(1==c.length&&1E-6>c.end(0)-c.start(0))){var d=.1;/(Edge|Trident)\//.test(navigator.userAgent)&&(d=.5);for(var e=0;e<c.length;e++)if(c.start(e)>b&&(!e||c.end(e-1)-b<=d)){d=e;break a}}d=null}if(null==d){if(3>this.a.readyState&&0<this.a.playbackRate)if(this.O!=b)this.O=b,this.v=Date.now();else if(this.v<Date.now()-
|
|
1E3)for(this.v=Date.now()+5E3,d=0;d<c.length;d++)if(b>=c.start(d)&&b<c.end(d)-.5){this.a.currentTime=this.a.currentTime;break}}else if(d||this.o)if(e=c.start(d),!(e>=this.c.presentationTimeline.bb())){var f=e-b,a=f<=a,g=!1;a||this.i||(this.i=!0,f=new I("largegap",{currentTime:b,gapSize:f}),f.cancelable=!0,this.G(f),this.l.jumpLargeGaps&&!f.defaultPrevented&&(g=!0));if(a||g)d&&c.end(d-1),mf(this,b,e)}}};
|
|
k.ic=function(){this.o=!1;var a=this.a.currentTime,b=nf(this,a);.001<Math.abs(b-a)?mf(this,a,b):(this.i=!1,this.J())};k.gc=function(){var a=this.a.currentTime,b=nf(this,a);.001<Math.abs(b-a)&&mf(this,a,b)};function nf(a,b){var c=Bb.bind(null,a.a.buffered),d=1*Math.max(a.c.minBufferTime||0,a.l.rebufferingGoal),e=a.c.presentationTimeline,f=e.ua(),g=e.Ea(d),h=e.Ea(5),d=e.Ea(d+5);return b>f?f:b<e.Ea(0)?c(h)?h:d:b>=g||c(b)?b:d}
|
|
function mf(a,b,c){a.a.currentTime=c;var d=0,e=function(){!this.a||10<=d++||this.a.currentTime!=b||(this.a.currentTime=c,setTimeout(e,100))}.bind(a);setTimeout(e,100)}function hf(a,b){var c=a.c.presentationTimeline.ma();if(b<c)return c;c=a.c.presentationTimeline.ua();return b>c?c:b};function of(a,b,c,d,e,f){this.a=a;this.g=b;this.A=c;this.l=d;this.h=e;this.B=f;this.c=[];this.j=new D;this.b=!1;this.i=-1;this.f=null;pf(this)}of.prototype.m=function(){var a=this.j?this.j.m():Promise.resolve();this.j=null;qf(this);this.B=this.h=this.l=this.A=this.g=this.a=null;this.c=[];return a};
|
|
of.prototype.v=function(a){if(!this.c.some(function(b){return b.info.schemeIdUri==a.schemeIdUri&&b.info.startTime==a.startTime&&b.info.endTime==a.endTime})){var b={info:a,status:1};this.c.push(b);var c=new I("timelineregionadded",{detail:rf(a)});this.h(c);this.o(!0,b)}};function rf(a){var b=Da(a);b.eventElement=a.eventElement;return b}
|
|
of.prototype.o=function(a,b){var c=b.info.startTime>this.a.currentTime?1:b.info.endTime<this.a.currentTime?3:2,d=2==b.status,e=2==c;if(c!=b.status){if(!a||d||e)d||this.h(new I("timelineregionenter",{detail:rf(b.info)})),e||this.h(new I("timelineregionexit",{detail:rf(b.info)}));b.status=c}};function pf(a){qf(a);a.f=window.setTimeout(a.G.bind(a),250)}function qf(a){a.f&&(window.clearTimeout(a.f),a.f=null)}
|
|
of.prototype.G=function(){this.f=null;pf(this);var a=hc(this.g,this.a.currentTime);a!=this.i&&(-1!=this.i&&this.B(),this.i=a);var a=Cb(this.a.buffered,this.a.currentTime),b=Ab(this.a.buffered)>=this.g.presentationTimeline.ua()-.1||this.a.ended;if(this.b){var c=1*Math.max(this.g.minBufferTime||0,this.A.rebufferingGoal);(b||a>=c)&&0!=this.b&&(this.b=!1,this.l(!1))}else!b&&.5>a&&1!=this.b&&(this.b=!0,this.l(!0));this.c.forEach(this.o.bind(this,!1))};function sf(a,b){this.a=b;this.b=a;this.g=null;this.i=1;this.o=Promise.resolve();this.h=[];this.j={};this.c={};this.f=this.l=this.v=!1}k=sf.prototype;k.m=function(){for(var a in this.c)tf(this.c[a]);this.g=this.c=this.j=this.h=this.o=this.b=this.a=null;this.f=!0;return Promise.resolve()};k.configure=function(a){this.g=a};k.init=function(){var a=this.a.bc(this.b.periods[hc(this.b,jf(this.a.Oa))]);return Ma(a)?Promise.reject(new t(2,5,5005)):uf(this,a).then(function(){this.a&&this.a.jd&&this.a.jd()}.bind(this))};
|
|
function V(a){return a.b.periods[hc(a.b,jf(a.a.Oa))]}function vf(a){return Oa(a.c,function(a){return a.na||a.stream})}function wf(a,b){var c={};c.text=b;return uf(a,c)}function xf(a,b){var c=a.c.video;if(c){var d=c.stream;if(d)if(b){var e=d.trickModeVideo;if(e){var f=c.na;f||(yf(a,"video",e,!1),c.na=d)}}else if(f=c.na)c.na=null,yf(a,"video",f,!0)}}
|
|
function yf(a,b,c,d){var e=a.c[b];if(!e&&"text"==b&&a.g.ignoreTextStreamFailures)wf(a,c);else if(e){var f=ic(a.b,c);d&&f!=e.wa?zf(a):(e.na&&(c.trickModeVideo?(e.na=c,c=c.trickModeVideo):e.na=null),"text"==b&&Fb(a.a.K,Yb(c.mimeType,c.codecs)),(b=a.h[f])&&b.La&&(b=a.j[c.id])&&b.La&&e.stream!=c&&(e.stream=c,e.cb=!0,d&&(e.sa?e.kb=!0:e.xa?(e.ra=!0,e.kb=!0):(tf(e),Af(a,e,!0)))))}}
|
|
function Bf(a){var b=jf(a.a.Oa);Object.keys(a.c).every(function(a){var c=this.a.K;"text"==a?(a=c.a,a=b>=a.b&&b<a.a):(a=Ib(c,a),a=Bb(a,b));return a}.bind(a))||zf(a)}function zf(a){for(var b in a.c){var c=a.c[b];c.sa||c.ra||(c.xa?c.ra=!0:null==Gb(a.a.K,b)?null==c.qa&&Cf(a,c,0):(tf(c),Af(a,c,!1)))}}
|
|
function uf(a,b,c){var d=hc(a.b,jf(a.a.Oa)),e=Oa(b,function(a){return Yb(a.mimeType,a.codecs)});a.a.K.init(e);Df(a);e=Na(b);return Ef(a,e).then(function(){if(!this.f)for(var a in b){var e=b[a];this.c[a]||(this.c[a]={stream:e,type:a,Fa:null,ea:null,na:null,cb:!0,wa:d,endOfStream:!1,xa:!1,qa:null,ra:!1,kb:!1,sa:!1,Gb:!1,tb:!1,rc:c||0},Cf(this,this.c[a],0))}}.bind(a))}
|
|
function Ff(a,b){var c=a.h[b];if(c)return c.L;c={L:new A,La:!1};a.h[b]=c;var d=a.b.periods[b].variants.map(function(a){var b=[];a.audio&&b.push(a.audio);a.video&&b.push(a.video);a.video&&a.video.trickModeVideo&&b.push(a.video.trickModeVideo);return b}).reduce(x,[]).filter(Aa);d.push.apply(d,a.b.periods[b].textStreams);a.o=a.o.then(function(){if(!this.f)return Ef(this,d)}.bind(a)).then(function(){this.f||(this.h[b].L.resolve(),this.h[b].La=!0)}.bind(a))["catch"](function(a){this.f||(this.h[b].L.reject(),
|
|
delete this.h[b],this.a.onError(a))}.bind(a));return c.L}
|
|
function Ef(a,b){b.map(function(a){return a.id}).filter(Aa);for(var c=[],d=0;d<b.length;++d){var e=b[d];var f=a.j[e.id];f?c.push(f.L):(a.j[e.id]={L:new A,La:!1},c.push(e.createSegmentIndex()))}return Promise.all(c).then(function(){if(!this.f)for(var a=0;a<b.length;++a){var c=this.j[b[a].id];c.La||(c.L.resolve(),c.La=!0)}}.bind(a))["catch"](function(a){if(!this.f)return this.j[e.id].L.reject(),delete this.j[e.id],Promise.reject(a)}.bind(a))}
|
|
function Df(a){var b=a.b.presentationTimeline.Y();Infinity>b?a.a.K.pa(b):a.a.K.pa(Math.pow(2,32))}k.ke=function(a){if(!this.f&&!a.xa&&null!=a.qa&&!a.sa)if(a.qa=null,a.ra)Af(this,a,a.kb);else{try{var b=Gf(this,a);null!=b&&(Cf(this,a,b),a.tb=!1)}catch(c){this.a.onError(c);return}b=Na(this.c);Hf(this,a);b.every(function(a){return a.endOfStream})&&this.a.K.endOfStream().then(function(){this.b.presentationTimeline.pa(this.a.K.Y())}.bind(this))}};
|
|
function Gf(a,b){var c=jf(a.a.Oa),d=b.Fa&&b.ea?a.b.periods[ic(a.b,b.Fa)].startTime+b.ea.endTime:Math.max(c,b.rc);b.rc=0;var e=ic(a.b,b.stream),f=hc(a.b,d);var g=a.a.K;var h=b.type;"text"==h?(g=g.a,g=null==g.a||g.a<c?0:g.a-Math.max(c,g.b)):(g=Ib(g,h),g=Cb(g,c));h=Math.max(a.i*Math.max(a.b.minBufferTime||0,a.g.rebufferingGoal),a.i*a.g.bufferingGoal);if(d>=a.b.presentationTimeline.Y())return b.endOfStream=!0,null;b.endOfStream=!1;b.wa=f;if(f!=e)return null;if(g>=h)return.5;d=a.a.K;f=b.type;d="text"==
|
|
f?d.a.a:Ab(Ib(d,f));b.ea&&b.stream==b.Fa?(f=b.ea.position+1,d=If(a,b,e,f)):(f=b.ea?b.stream.findSegmentPosition(Math.max(0,a.b.periods[ic(a.b,b.Fa)].startTime+b.ea.endTime-a.b.periods[e].startTime)):b.stream.findSegmentPosition(Math.max(0,(d||c)-a.b.periods[e].startTime)),null==f?d=null:(g=null,null==d&&(g=If(a,b,e,Math.max(0,f-1))),d=g||If(a,b,e,f)));if(!d)return 1;Jf(a,b,c,e,d);return null}
|
|
function If(a,b,c,d){c=a.b.periods[c];b=b.stream.getSegmentReference(d);if(!b)return null;a=a.b.presentationTimeline;d=a.ua();return c.startTime+b.endTime<a.ma()||c.startTime+b.startTime>d?null:b}
|
|
function Jf(a,b,c,d,e){var f=a.b.periods[d],g=b.stream,h=a.b.periods[d+1],l=null,l=h?h.startTime:a.b.presentationTimeline.Y();d=Kf(a,b,d,l);b.xa=!0;b.cb=!1;h=Lf(a,e);Promise.all([d,h]).then(function(a){if(!this.f&&!this.l)return Mf(this,b,c,f,g,e,a[1])}.bind(a)).then(function(){this.f||this.l||(b.xa=!1,b.Gb=!1,b.ra||this.a.Ab(),Cf(this,b,0),Nf(this,g))}.bind(a))["catch"](function(a){this.f||this.l||(b.xa=!1,this.b.presentationTimeline.$()&&this.g.infiniteRetriesForLiveStreams&&(1001==a.code||1002==
|
|
a.code||1003==a.code)?"text"==b.type&&this.g.ignoreTextStreamFailures&&1001==a.code?delete this.c.text:(a.severity=1,this.a.onError(a),Cf(this,b,4)):3017==a.code?Of(this,b,a):"text"==b.type&&this.g.ignoreTextStreamFailures?delete this.c.text:(b.tb=!0,a.severity=2,this.a.onError(a)))}.bind(a))}function Of(a,b,c){if(!Na(a.c).some(function(a){return a!=b&&a.Gb})){var d=Math.round(100*a.i);if(20<d)a.i-=.2;else if(4<d)a.i-=.04;else{b.tb=!0;a.l=!0;a.a.onError(c);return}b.Gb=!0}Cf(a,b,4)}
|
|
function Kf(a,b,c,d){if(!b.cb)return Promise.resolve();c=Mb(a.a.K,b.type,a.b.periods[c].startTime-b.stream.presentationTimeOffset,d);if(!b.stream.initSegmentReference)return c;a=Lf(a,b.stream.initSegmentReference).then(function(a){if(!this.f)return Jb(this.a.K,b.type,a,null,null)}.bind(a))["catch"](function(a){b.cb=!0;return Promise.reject(a)});return Promise.all([c,a])}
|
|
function Mf(a,b,c,d,e,f,g){e.containsEmsgBoxes&&(new Q).da("emsg",a.Ed.bind(a,d,f)).parse(g);return Pf(a,b,c).then(function(){if(!this.f)return Jb(this.a.K,b.type,g,f.startTime+d.startTime,f.endTime+d.startTime)}.bind(a)).then(function(){if(!this.f)return b.Fa=e,b.ea=f,Promise.resolve()}.bind(a))}
|
|
k.Ed=function(a,b,c){var d=c.s.Db(),e=c.s.Db(),f=c.s.D(),g=c.s.D(),h=c.s.D(),l=c.s.D();c=c.s.Ka(c.s.H.byteLength-c.s.u);a=a.startTime+b.startTime+g/f;if("urn:mpeg:dash:event:2012"==d)this.a.kd();else this.a.onEvent(new I("emsg",{detail:{startTime:a,endTime:a+h/f,schemeIdUri:d,value:e,timescale:f,presentationTimeDelta:g,eventDuration:h,id:l,messageData:c}}))};
|
|
function Pf(a,b,c){var d=Gb(a.a.K,b.type);if(null==d)return Promise.resolve();c=c-d-a.g.bufferBehind;return 0>=c?Promise.resolve():a.a.K.remove(b.type,d,d+c).then(function(){}.bind(a))}function Nf(a,b){if(!a.v&&(a.v=Na(a.c).every(function(a){return"text"==a.type?!0:!a.ra&&!a.sa&&a.ea}),a.v)){var c=ic(a.b,b);a.h[c]||Ff(a,c).then(function(){this.a.ac()}.bind(a))["catch"](y);for(c=0;c<a.b.periods.length;++c)Ff(a,c)["catch"](y);a.a.wd&&a.a.wd()}}
|
|
function Hf(a,b){if(b.wa!=ic(a.b,b.stream)){var c=b.wa,d=Na(a.c);d.every(function(a){return a.wa==c})&&d.every(Qf)&&Ff(a,c).then(function(){if(!this.f&&d.every(function(a){var b=ic(this.b,a.stream);return Qf(a)&&a.wa==c&&b!=c}.bind(this))){var a=this.b.periods[c],b=this.a.bc(a),g;for(g in this.c)if(!b[g]&&"text"!=g){this.a.onError(new t(2,5,5005));return}for(g in b)if(!this.c[g])if("text"==g)uf(this,{text:b.text},a.startTime),delete b[g];else{this.a.onError(new t(2,5,5005));return}for(g in this.c)(a=
|
|
b[g])?(yf(this,g,a,!1),Cf(this,this.c[g],0)):delete this.c[g];this.a.ac()}}.bind(a))["catch"](y)}}function Qf(a){return!a.xa&&null==a.qa&&!a.ra&&!a.sa}function Lf(a,b){var c=C(b.a(),a.g.retryParameters);if(b.X||null!=b.M){var d="bytes="+b.X+"-";null!=b.M&&(d+=b.M);c.headers.Range=d}return a.a.dd.request(1,c).then(function(a){return a.data})}
|
|
function Af(a,b,c){b.ra=!1;b.kb=!1;b.sa=!0;Lb(a.a.K,b.type).then(function(){if(!this.f&&c){var a=this.a.K,e=b.type;return"text"==e?Promise.resolve():Kb(a,e,a.Oc.bind(a,e))}}.bind(a)).then(function(){this.f||(b.Fa=null,b.ea=null,b.sa=!1,b.endOfStream=!1,Cf(this,b,0))}.bind(a))}function Cf(a,b,c){b.qa=window.setTimeout(a.ke.bind(a,b),1E3*c)}function tf(a){null!=a.qa&&(window.clearTimeout(a.qa),a.qa=null)};function Rf(a,b){return new Promise(function(c,d){var e=new XMLHttpRequest;e.open(b.method,a,!0);e.responseType="arraybuffer";e.timeout=b.retryParameters.timeout;e.withCredentials=b.allowCrossSiteCredentials;e.onload=function(b){b=b.target;var e=b.getAllResponseHeaders().split("\r\n").reduce(function(a,b){var c=b.split(": ");a[c[0].toLowerCase()]=c.slice(1).join(": ");return a},{});if(200<=b.status&&299>=b.status&&202!=b.status)b.responseURL&&(a=b.responseURL),c({uri:a,data:b.response,headers:e,fromCache:!!e["x-shaka-from-cache"]});
|
|
else{var f=null;try{f=Ta(b.response)}catch(m){}d(new t(401==b.status||403==b.status?2:1,1,1001,a,b.status,f,e))}};e.onerror=function(){d(new t(1,1,1002,a))};e.ontimeout=function(){d(new t(1,1,1003,a))};for(var f in b.headers)e.setRequestHeader(f,b.headers[f]);e.send(b.body)})}n("shaka.net.HttpPlugin",Rf);Ea.http=Rf;Ea.https=Rf;function Sf(){this.a=null;this.b=[];this.c={}}k=Sf.prototype;k.init=function(a,b){return Tf(this,a,b).then(function(){var b=Object.keys(a);return Promise.all(b.map(function(a){return Uf(this,a).then(function(b){this.c[a]=b}.bind(this))}.bind(this)))}.bind(this))};k.m=function(){return Promise.all(this.b.map(function(a){try{a.transaction.abort()}catch(b){}return a.L["catch"](y)})).then(function(){this.a&&(this.a.close(),this.a=null)}.bind(this))};
|
|
k.get=function(a,b){var c;return Vf(this,a,"readonly",function(a){c=a.get(b)}).then(function(){return c.result})};k.forEach=function(a,b){return Vf(this,a,"readonly",function(a){a.openCursor().onsuccess=function(a){if(a=a.target.result)b(a.value),a["continue"]()}})};function Wf(a,b,c){return Vf(a,b,"readwrite",function(a){a.put(c)})}k.remove=function(a,b){return Vf(this,a,"readwrite",function(a){a["delete"](b)})};
|
|
function Xf(a,b,c){return Vf(a,"segment","readwrite",function(a){for(var d=0;d<b.length;d++)a["delete"](b[d]).onsuccess=c||function(){}})}function Uf(a,b){var c=0;return Vf(a,b,"readonly",function(a){a.openCursor(null,"prev").onsuccess=function(a){(a=a.target.result)&&(c=a.key+1)}}).then(function(){return c})}
|
|
function Vf(a,b,c,d){var e={transaction:a.a.transaction([b],c),L:new A};e.transaction.oncomplete=function(){this.b.splice(this.b.indexOf(e),1);e.L.resolve()}.bind(a);e.transaction.onabort=function(a){this.b.splice(this.b.indexOf(e),1);Yf(e.transaction,e.L,a)}.bind(a);e.transaction.onerror=function(a){a.preventDefault()}.bind(a);b=e.transaction.objectStore(b);d(b);a.b.push(e);return e.L}
|
|
function Tf(a,b,c){var d=window.indexedDB.open("shaka_offline_db",1),e=!1,f=new A;d.onupgradeneeded=function(a){e=!0;a=a.target.result;for(var c in b)a.createObjectStore(c,{keyPath:b[c]})};d.onsuccess=function(a){c&&!e?(a.target.result.close(),setTimeout(function(){Tf(this,b,c-1).then(f.resolve,f.reject)}.bind(this),1E3)):(this.a=a.target.result,f.resolve())}.bind(a);d.onerror=Yf.bind(null,d,f);return f}
|
|
function Yf(a,b,c){a.error?b.reject(new t(2,9,9001,a.error)):b.reject(new t(2,9,9002));c.preventDefault()};var Zf={manifest:"key",segment:"key"};function $f(a){var b=ag(a.periods[0],[],new T(null,0)),c=Zb(b,null,null),b=ac(b,null);c.push.apply(c,b);return{offlineUri:"offline:"+a.key,originalManifestUri:a.originalManifestUri,duration:a.duration,size:a.size,expiration:void 0==a.expiration?Infinity:a.expiration,tracks:c,appMetadata:a.appMetadata}}
|
|
function ag(a,b,c){var d=a.streams.filter(function(a){return"text"==a.contentType}),e=a.streams.filter(function(a){return"audio"==a.contentType}),f=a.streams.filter(function(a){return"video"==a.contentType});b=bg(e,f,b);d=d.map(cg);a.streams.forEach(function(a){a=dg(a);c.Ha(0,a)});return{startTime:a.startTime,variants:b,textStreams:d}}function dg(a){return a.segments.map(function(a,c){return new O(c,a.startTime,a.endTime,function(){return[a.uri]},0,null)})}
|
|
function bg(a,b,c){var d=[];if(!a.length&&!b.length)return d;a.length?b.length||(b=[null]):a=[null];for(var e=0,f=0;f<a.length;f++)for(var g=0;g<b.length;g++)if(eg(a[f],b[g])){var h=a[f];var l=b[g],m=c;h={id:e++,language:h?h.language:"",primary:!!h&&h.primary||!!l&&l.primary,audio:cg(h),video:cg(l),bandwidth:0,drmInfos:m,allowedByApplication:!0,allowedByKeySystem:!0};d.push(h)}return d}
|
|
function eg(a,b){if(!(a&&b&&a.variantIds&&b.variantIds))return!0;for(var c=0;c<a.variantIds.length;c++)if(b.variantIds.some(function(b){return b==a.variantIds[c]}))return!0;return!1}
|
|
function cg(a){if(!a)return null;var b=dg(a),b=new S(b);return{id:a.id,createSegmentIndex:Promise.resolve.bind(Promise),findSegmentPosition:b.find.bind(b),getSegmentReference:b.get.bind(b),initSegmentReference:a.initSegmentUri?new Zc(function(){return[a.initSegmentUri]},0,null):null,presentationTimeOffset:a.presentationTimeOffset,mimeType:a.mimeType,codecs:a.codecs,width:a.width||void 0,height:a.height||void 0,frameRate:a.frameRate||void 0,kind:a.kind,encrypted:a.encrypted,keyId:a.keyId,language:a.language,
|
|
label:a.label||null,type:a.contentType,primary:a.primary,trickModeVideo:null,containsEmsgBoxes:!1,roles:[]}}function fg(){return window.indexedDB?new Sf:null};function gg(a,b,c,d){this.b={};this.l=[];this.o=d;this.j=a;this.v=b;this.A=c;this.i=this.a=null;this.f=this.g=this.h=this.c=0}gg.prototype.m=function(){var a=this.j,b=this.l,c=this.i||Promise.resolve(),c=c.then(function(){return Xf(a,b)});this.b={};this.l=[];this.i=this.a=this.A=this.v=this.j=this.o=null;return c};function hg(a,b,c,d,e){a.b[b]=a.b[b]||[];a.b[b].push({uris:c.a(),X:c.X,M:c.M,Rb:d,Hb:e})}
|
|
function ig(a,b){a.c=0;a.h=0;a.g=0;a.f=0;Na(a.b).forEach(function(a){a.forEach(function(a){null!=a.M?this.c+=a.M-a.X+1:this.g+=a.Rb}.bind(this))}.bind(a));a.a=b;a.a.size=a.c;var c=Na(a.b).map(function(a){var b=0,c=function(){if(!this.o)return Promise.reject(new t(2,9,9002));if(b>=a.length)return Promise.resolve();var d=a[b++];return jg(this,d).then(c)}.bind(this);return c()}.bind(a));a.b={};a.i=Promise.all(c).then(function(){return Wf(this.j,"manifest",b)}.bind(a)).then(function(){this.l=[]}.bind(a));
|
|
return a.i}
|
|
function jg(a,b){var c=C(b.uris,a.A);if(b.X||null!=b.M)c.headers.Range="bytes="+b.X+"-"+(null==b.M?"":b.M);var d;return a.v.request(1,c).then(function(a){if(!this.a)return Promise.reject(new t(2,9,9002));d=a.data.byteLength;this.l.push(b.Hb.key);b.Hb.data=a.data;return Wf(this.j,"segment",b.Hb)}.bind(a)).then(function(){if(!this.a)return Promise.reject(new t(2,9,9002));null==b.M?(this.a.size+=d,this.f+=b.Rb):this.h+=d;var a=(this.h+this.f)/(this.c+this.g),c=$f(this.a);this.o.progressCallback(c,a)}.bind(a))}
|
|
;function kg(){this.a=-1}k=kg.prototype;k.configure=function(){};k.start=function(a){var b=/^offline:([0-9]+)$/.exec(a);if(!b)return Promise.reject(new t(2,1,9004,a));var c=Number(b[1]),d=fg();this.a=c;return d?d.init(Zf).then(function(){return d.get("manifest",c)}).then(function(a){if(!a)throw new t(2,9,9003,c);return lg(a)}).then(function(a){return d.m().then(function(){return a})},function(a){return d.m().then(function(){throw a;})}):Promise.reject(new t(2,9,9E3))};k.stop=function(){return Promise.resolve()};
|
|
k.update=function(){};k.onExpirationUpdated=function(a,b){var c=fg();c.init(Zf).then(function(){return c.get("manifest",this.a)}.bind(this)).then(function(d){if(d&&!(0>d.sessionIds.indexOf(a))&&(void 0==d.expiration||d.expiration>b))return d.expiration=b,Wf(c,"manifest",d)})["catch"](function(){}).then(function(){return c.m()})};
|
|
function lg(a){var b=new T(null,0);b.pa(a.duration);var c=a.drmInfo?[a.drmInfo]:[];return{presentationTimeline:b,minBufferTime:10,offlineSessionIds:a.sessionIds,periods:a.periods.map(function(a){return ag(a,c,b)})}}Dd["application/x-offline-manifest"]=kg;function mg(a){if(/^offline:([0-9]+)$/.exec(a)){var b={uri:a,data:new ArrayBuffer(0),headers:{"content-type":"application/x-offline-manifest"}};return Promise.resolve(b)}if(b=/^offline:[0-9]+\/[0-9]+\/([0-9]+)$/.exec(a)){var c=Number(b[1]),d=fg();return d?d.init(Zf).then(function(){return d.get("segment",c)}).then(function(b){return d.m().then(function(){if(!b)throw new t(2,9,9003,c);return{uri:a,data:b.data,headers:{}}})}):Promise.reject(new t(2,9,9E3))}return Promise.reject(new t(2,1,9004,a))}
|
|
n("shaka.offline.OfflineScheme",mg);Ea.offline=mg;function ng(){this.a=Promise.resolve();this.b=this.c=this.f=!1;this.i=new Promise(function(a){this.g=a}.bind(this))}ng.prototype.then=function(a){this.a=this.a.then(a).then(function(a){return this.b?(this.g(),Promise.reject(this.h)):Promise.resolve(a)}.bind(this));return this};function og(a){a.f||(a.a=a.a.then(function(a){this.c=!0;return Promise.resolve(a)}.bind(a),function(a){this.c=!0;return this.b?(this.g(),Promise.reject(this.h)):Promise.reject(a)}.bind(a)));a.f=!0;return a.a}
|
|
ng.prototype.cancel=function(a){if(this.c)return Promise.resolve();this.b=!0;this.h=a;return this.i};function W(a,b){p.call(this);this.O=!1;this.f=a;this.A=null;this.l=new D;this.Qb=new H;this.Ya=this.c=this.h=this.a=this.v=this.g=this.Wa=this.ja=this.N=this.j=this.o=null;this.Dc=1E9;this.Va=[];this.ka=!1;this.Za=!0;this.la=this.J=null;this.G={};this.Xa=[];this.B={};this.b=pg(this);this.ob={width:Infinity,height:Infinity};this.i=qg();this.Ua=0;this.ia=this.b.preferredAudioLanguage;this.Ca=this.b.preferredTextLanguage;this.lb=this.mb="";b&&b(this);this.o=new B(this.de.bind(this));this.Wa=rg(this);
|
|
for(var c=0;c<this.f.textTracks.length;++c){var d=this.f.textTracks[c];d.mode="disabled";"Shaka Player TextTrack"==d.label&&(this.A=d)}this.A||(this.A=this.f.addTextTrack("subtitles","Shaka Player TextTrack"));this.A.mode="hidden";E(this.l,this.f,"error",this.yd.bind(this))}ba(W);n("shaka.Player",W);
|
|
W.prototype.m=function(){this.O=!0;var a=Promise.resolve();this.J&&(a=this.J.cancel(new t(2,7,7E3)));return a.then(function(){var a=Promise.all([this.la,sg(this),this.l?this.l.m():null,this.o?this.o.m():null]);this.b=this.o=this.Qb=this.l=this.A=this.f=null;return a}.bind(this))};W.prototype.destroy=W.prototype.m;W.version="v2.1.4";var tg={};W.registerSupportPlugin=function(a,b){tg[a]=b};
|
|
W.isBrowserSupported=function(){return!!window.Promise&&!!window.Uint8Array&&!!Array.prototype.forEach&&!!window.MediaSource&&!!window.MediaSource.isTypeSupported&&!!window.MediaKeys&&!!window.navigator&&!!window.navigator.requestMediaKeySystemAccess&&!!window.MediaKeySystemAccess&&!!window.MediaKeySystemAccess.prototype.getConfiguration};W.probeSupport=function(){return qb().then(function(a){var b=Fd(),c=Eb();a={manifest:b,media:c,drm:a};for(var d in tg)a[d]=tg[d]();return a})};
|
|
W.prototype.load=function(a,b,c){var d=this.hb(),e=new ng;this.J=e;this.dispatchEvent(new I("loading"));var f=Date.now();return og(e.then(function(){return d}).then(function(){this.i=qg();E(this.l,this.f,"playing",this.Sa.bind(this));E(this.l,this.f,"pause",this.Sa.bind(this));E(this.l,this.f,"ended",this.Sa.bind(this));return Gd(a,this.o,this.b.manifest.retryParameters,c)}.bind(this)).then(function(b){this.h=new b;this.h.configure(this.b.manifest);b={networkingEngine:this.o,filterPeriod:this.fb.bind(this),
|
|
onTimelineRegionAdded:this.xd.bind(this),onEvent:this.gb.bind(this),onError:this.ya.bind(this)};return 2<this.h.start.length?this.h.start(a,this.o,b.filterPeriod,b.onError,b.onEvent):this.h.start(a,b)}.bind(this)).then(function(b){if(0==b.periods.length)throw new t(2,4,4014);this.c=b;this.Ya=a;this.j=new bb(this.o,this.ya.bind(this),this.be.bind(this),this.ae.bind(this));this.j.configure(this.b.drm);return this.j.init(b,!1)}.bind(this)).then(function(){this.c.periods.forEach(this.fb.bind(this));this.Ua=
|
|
Date.now()/1E3;this.ia=this.b.preferredAudioLanguage;this.Ca=this.b.preferredTextLanguage;return Promise.all([eb(this.j,this.f),this.Wa])}.bind(this)).then(function(){this.b.abr.manager.init(this.Lb.bind(this));this.g=new ff(this.f,this.c,this.b.streaming,b||null,this.ce.bind(this),this.gb.bind(this));this.v=new of(this.f,this.c,this.b.streaming,this.zc.bind(this),this.gb.bind(this),this.$d.bind(this));this.ja=new Db(this.f,this.N,this.A);this.a=new sf(this.c,{Oa:this.g,K:this.ja,dd:this.o,bc:this.ed.bind(this),
|
|
ac:this.Gc.bind(this),onError:this.ya.bind(this),onEvent:this.gb.bind(this),kd:this.ld.bind(this),Ab:this.ud.bind(this)});this.a.configure(this.b.streaming);ug(this);return this.a.init()}.bind(this)).then(function(){if(this.b.streaming.startAtSegmentBoundary){var a=vg(this,jf(this.g));gf(this.g,a)}this.c.periods.forEach(this.fb.bind(this));wg(this);xg(this);var a=V(this.a),b=dc(a,this.ia);this.b.abr.manager.setVariants(b);a.variants.some(function(a){return a.primary});this.Xa.forEach(this.v.v.bind(this.v));
|
|
this.Xa=[];La(this.l,this.f,"loadeddata",function(){this.i.loadLatency=(Date.now()-f)/1E3}.bind(this));this.J=null}.bind(this)))["catch"](function(a){this.J==e&&(this.J=null,this.dispatchEvent(new I("unloading")));return Promise.reject(a)}.bind(this))};W.prototype.load=W.prototype.load;
|
|
function ug(a){function b(a){return(a.video?a.video.codecs.split(".")[0]:"")+"-"+(a.audio?a.audio.codecs.split(".")[0]:"")}var c={};a.c.periods.forEach(function(a){a.variants.forEach(function(a){var d=b(a);d in c||(c[d]=[]);c[d].push(a)})});var d=null,e=Infinity;Qa(c,function(a,b){var c=0,f=0;b.forEach(function(a){c+=a.bandwidth;++f});var g=c/f;g<e&&(d=a,e=g)});a.c.periods.forEach(function(a){a.variants=a.variants.filter(function(a){return b(a)==d?!0:!1})})}
|
|
function rg(a){a.N=new MediaSource;var b=new A;E(a.l,a.N,"sourceopen",b.resolve);a.f.src=window.URL.createObjectURL(a.N);return b}W.prototype.configure=function(a){a.abr&&a.abr.manager&&a.abr.manager!=this.b.abr.manager&&(this.b.abr.manager.stop(),a.abr.manager.init(this.Lb.bind(this)));Ca(this.b,a,pg(this),yg(),"");zg(this)};W.prototype.configure=W.prototype.configure;
|
|
function zg(a){a.h&&a.h.configure(a.b.manifest);a.j&&a.j.configure(a.b.drm);if(a.a){a.a.configure(a.b.streaming);try{a.c.periods.forEach(a.fb.bind(a))}catch(b){a.ya(b)}Ag(a,V(a.a))}a.b.abr.enabled&&!a.Za?a.b.abr.manager.enable():a.b.abr.manager.disable();a.b.abr.manager.setDefaultEstimate(a.b.abr.defaultBandwidthEstimate);a.b.abr.manager.setRestrictions(a.b.abr.restrictions)}W.prototype.getConfiguration=function(){var a=pg(this);Ca(a,this.b,pg(this),yg(),"");return a};
|
|
W.prototype.getConfiguration=W.prototype.getConfiguration;W.prototype.Rd=function(){var a=pg(this);a.abr&&a.abr.manager&&a.abr.manager!=this.b.abr.manager&&(this.b.abr.manager.stop(),a.abr.manager.init(this.Lb.bind(this)));this.b=pg(this);zg(this)};W.prototype.resetConfiguration=W.prototype.Rd;W.prototype.Sc=function(){return this.f};W.prototype.getMediaElement=W.prototype.Sc;W.prototype.Wb=function(){return this.o};W.prototype.getNetworkingEngine=W.prototype.Wb;W.prototype.Rc=function(){return this.Ya};
|
|
W.prototype.getManifestUri=W.prototype.Rc;W.prototype.$=function(){return this.c?this.c.presentationTimeline.$():!1};W.prototype.isLive=W.prototype.$;W.prototype.va=function(){return this.c?this.c.presentationTimeline.va():!1};W.prototype.isInProgress=W.prototype.va;W.prototype.Td=function(){var a=0,b=0;this.c&&(b=this.c.presentationTimeline,a=b.ma(),b=b.bb());return{start:a,end:b}};W.prototype.seekRange=W.prototype.Td;W.prototype.keySystem=function(){return this.j?this.j.keySystem():""};
|
|
W.prototype.keySystem=W.prototype.keySystem;W.prototype.drmInfo=function(){return this.j?this.j.b:null};W.prototype.drmInfo=W.prototype.drmInfo;W.prototype.ab=function(){return this.j?this.j.ab():Infinity};W.prototype.getExpiration=W.prototype.ab;W.prototype.$c=function(){return this.ka};W.prototype.isBuffering=W.prototype.$c;
|
|
W.prototype.hb=function(){if(this.O)return Promise.resolve();this.dispatchEvent(new I("unloading"));var a=Promise.resolve();this.J&&(a=this.J.cancel(new t(2,7,7E3)));return a.then(function(){this.la||(this.la=Bg(this).then(function(){this.la=null}.bind(this)));return this.la}.bind(this))};W.prototype.unload=W.prototype.hb;W.prototype.rb=function(){return this.g?this.g.rb():0};W.prototype.getPlaybackRate=W.prototype.rb;W.prototype.ne=function(a){this.g&&lf(this.g,a);this.a&&xf(this.a,1!=a)};
|
|
W.prototype.trickPlay=W.prototype.ne;W.prototype.Hc=function(){this.g&&lf(this.g,1);this.a&&xf(this.a,!1)};W.prototype.cancelTrickPlay=W.prototype.Hc;W.prototype.getTracks=function(){return this.Yb().concat(this.Xb())};W.prototype.getTracks=W.prototype.getTracks;W.prototype.Wd=function(a,b){"text"==a.type?this.tc(a):(this.configure({abr:{enabled:!1}}),this.uc(a,b))};W.prototype.selectTrack=W.prototype.Wd;
|
|
W.prototype.Yb=function(){if(!this.c)return[];var a=hc(this.c,jf(this.g)),b=this.B[a]||{};return Zb(this.c.periods[a],b.audio,b.video)};W.prototype.getVariantTracks=W.prototype.Yb;W.prototype.Xb=function(){if(!this.c)return[];var a=hc(this.c,jf(this.g));return ac(this.c.periods[a],(this.B[a]||{}).text).filter(function(a){return 0>this.Va.indexOf(a.id)}.bind(this))};W.prototype.getTextTracks=W.prototype.Xb;
|
|
W.prototype.tc=function(a){if(this.a&&(a=cc(V(this.a),a))){Cg(this,a,!1);var b={};b.text=a;Dg(this,b,!0)}};W.prototype.selectTextTrack=W.prototype.tc;
|
|
W.prototype.uc=function(a,b){if(this.a){var c={},d=bc(V(this.a),a),e=vf(this.a);if(d){if(!d.allowedByApplication||!d.allowedByKeySystem)return;d.audio&&(Eg(this,d.audio),d.audio!=e.audio&&(c.audio=d.audio));d.video&&(Eg(this,d.video),d.video!=e.video&&(c.video=d.video))}Na(c).forEach(function(a){Cg(this,a,!1)}.bind(this));(d=e.text)&&(c.text=d);Dg(this,c,b)}};W.prototype.selectVariantTrack=W.prototype.uc;
|
|
W.prototype.Pc=function(){return this.a?$b(V(this.a).variants).map(function(a){return a.language}).filter(Aa):[]};W.prototype.getAudioLanguages=W.prototype.Pc;W.prototype.Yc=function(){return this.a?V(this.a).textStreams.map(function(a){return a.language}).filter(Aa):[]};W.prototype.getTextLanguages=W.prototype.Yc;W.prototype.Ud=function(a,b){if(this.a){var c=V(this.a);this.ia=a;this.mb=b||"";Ag(this,c)}};W.prototype.selectAudioLanguage=W.prototype.Ud;
|
|
W.prototype.Vd=function(a,b){if(this.a){var c=V(this.a);this.Ca=a;this.lb=b||"";Ag(this,c)}};W.prototype.selectTextLanguage=W.prototype.Vd;W.prototype.bd=function(){return"showing"==this.A.mode};W.prototype.isTextTrackVisible=W.prototype.bd;W.prototype.Yd=function(a){this.A.mode=a?"showing":"hidden";Fg(this)};W.prototype.setTextTrackVisibility=W.prototype.Yd;W.prototype.Uc=function(){return this.c?new Date(1E3*this.c.presentationTimeline.f+1E3*this.f.currentTime):null};
|
|
W.prototype.getPlayheadTimeAsDate=W.prototype.Uc;
|
|
W.prototype.getStats=function(){Gg(this);this.Sa();var a=null,b=null,c=this.f&&this.f.getVideoPlaybackQuality?this.f.getVideoPlaybackQuality():{};this.g&&this.c&&(a=hc(this.c,jf(this.g)),b=this.B[a],b=gc(b.audio,b.video,this.c.periods[a].variants),a=b.video||{});a||(a={});b||(b={});return{width:a.width||0,height:a.height||0,streamBandwidth:b.bandwidth||0,decodedFrames:Number(c.totalVideoFrames),droppedFrames:Number(c.droppedVideoFrames),estimatedBandwidth:this.b.abr.manager.getBandwidthEstimate(),loadLatency:this.i.loadLatency,
|
|
playTime:this.i.playTime,bufferingTime:this.i.bufferingTime,switchHistory:Da(this.i.switchHistory),stateHistory:Da(this.i.stateHistory)}};W.prototype.getStats=W.prototype.getStats;
|
|
W.prototype.addTextTrack=function(a,b,c,d,e,f){if(!this.a)return Promise.reject();for(var g=V(this.a),h,l=0;l<this.c.periods.length;l++)if(this.c.periods[l]==g){if(l==this.c.periods.length-1){if(h=this.c.presentationTimeline.Y()-g.startTime,Infinity==h)return Promise.reject()}else h=this.c.periods[l+1].startTime-g.startTime;break}var m={id:this.Dc++,createSegmentIndex:Promise.resolve.bind(Promise),findSegmentPosition:function(){return 1},getSegmentReference:function(b){return 1!=b?null:new O(1,0,
|
|
h,function(){return[a]},0,null)},initSegmentReference:null,presentationTimeOffset:0,mimeType:d,codecs:e||"",kind:c,encrypted:!1,keyId:null,language:b,label:f||null,type:"text",primary:!1,trickModeVideo:null,containsEmsgBoxes:!1,roles:[]};this.Va.push(m.id);g.textStreams.push(m);return wf(this.a,m).then(function(){if(!this.O){var a=this.c.periods.indexOf(g),d=vf(this.a);d.text&&(this.B[a].text=d.text.id);this.Va.splice(this.Va.indexOf(m.id),1);Ag(this,g);wg(this);return{id:m.id,active:!1,type:"text",
|
|
bandwidth:0,language:b,label:f||null,kind:c,width:null,height:null}}}.bind(this))};W.prototype.addTextTrack=W.prototype.addTextTrack;W.prototype.Jb=function(a,b){this.ob.width=a;this.ob.height=b};W.prototype.setMaxHardwareResolution=W.prototype.Jb;function Cg(a,b,c){a.i.switchHistory.push({timestamp:Date.now()/1E3,id:b.id,type:b.type,fromAdaptation:c});Eg(a,b)}function Eg(a,b){var c=ic(a.c,b);a.B[c]||(a.B[c]={});a.B[c][b.type]=b.id}
|
|
function sg(a){a.l&&(a.l.ha(a.N,"sourceopen"),a.l.ha(a.f,"loadeddata"),a.l.ha(a.f,"playing"),a.l.ha(a.f,"pause"),a.l.ha(a.f,"ended"));a.f&&(a.f.removeAttribute("src"),a.f.load());var b=Promise.all([a.b?a.b.abr.manager.stop():null,a.j?a.j.m():null,a.ja?a.ja.m():null,a.g?a.g.m():null,a.v?a.v.m():null,a.a?a.a.m():null,a.h?a.h.stop():null]);a.j=null;a.ja=null;a.g=null;a.v=null;a.a=null;a.h=null;a.c=null;a.Ya=null;a.Wa=null;a.N=null;a.Xa=[];a.B={};a.G={};a.i=qg();return b}
|
|
function Bg(a){return a.h?sg(a).then(function(){this.O||(this.zc(!1),this.Wa=rg(this))}.bind(a)):Promise.resolve()}function yg(){return{".drm.servers":"",".drm.clearKeys":"",".drm.advanced":{distinctiveIdentifierRequired:!1,persistentStateRequired:!1,videoRobustness:"",audioRobustness:"",serverCertificate:null}}}
|
|
function pg(a){return{drm:{retryParameters:Fa(),servers:{},clearKeys:{},advanced:{},delayLicenseRequestUntilPlayed:!1},manifest:{retryParameters:Fa(),dash:{customScheme:function(a){if(a)return null},clockSyncUri:"",ignoreDrmInfo:!1},hls:{defaultTimeOffset:0}},streaming:{retryParameters:Fa(),infiniteRetriesForLiveStreams:!0,rebufferingGoal:2,bufferingGoal:10,bufferBehind:30,ignoreTextStreamFailures:!1,startAtSegmentBoundary:!1,smallGapLimit:.5,jumpLargeGaps:!1},abr:{manager:a.Qb,enabled:!0,defaultBandwidthEstimate:5E5,
|
|
restrictions:{minWidth:0,maxWidth:Infinity,minHeight:0,maxHeight:Infinity,minPixels:0,maxPixels:Infinity,minBandwidth:0,maxBandwidth:Infinity}},preferredAudioLanguage:"",preferredTextLanguage:"",restrictions:{minWidth:0,maxWidth:Infinity,minHeight:0,maxHeight:Infinity,minPixels:0,maxPixels:Infinity,minBandwidth:0,maxBandwidth:Infinity}}}
|
|
function qg(){return{width:NaN,height:NaN,streamBandwidth:NaN,decodedFrames:NaN,droppedFrames:NaN,estimatedBandwidth:NaN,loadLatency:NaN,playTime:0,bufferingTime:0,switchHistory:[],stateHistory:[]}}k=W.prototype;k.fb=function(a){var b=this.a?vf(this.a):{};Wb(this.j,b,a);b=0<$b(a.variants).length;Vb(a,this.b.restrictions,this.ob)&&this.a&&V(this.a)==a&&wg(this);a=1>$b(a.variants).length;if(!b)throw new t(2,4,4011);if(a)throw new t(2,4,4012);};
|
|
function Dg(a,b,c){for(var d in b){var e=b[d],f=c||!1;"text"==d&&(f=!0);a.Za?a.G[d]={stream:e,Kc:f}:yf(a.a,d,e,f)}}function Gg(a){if(a.c){var b=Date.now()/1E3;a.ka?a.i.bufferingTime+=b-a.Ua:a.i.playTime+=b-a.Ua;a.Ua=b}}
|
|
function vg(a,b){function c(a,b){if(!a)return null;var c=a.findSegmentPosition(b-e.startTime);return null==c?null:(c=a.getSegmentReference(c))?c.startTime+e.startTime:null}var d=vf(a.a),e=V(a.a),f=c(d.video,b),d=c(d.audio,b);return null!=f&&null!=d?Math.max(f,d):null!=f?f:null!=d?d:b}k.de=function(a,b){this.b.abr.manager.segmentDownloaded(a,b)};k.zc=function(a){Gg(this);this.ka=a;this.Sa();if(this.g){var b=this.g;a!=b.h&&(b.h=a,lf(b,b.g))}this.dispatchEvent(new I("buffering",{buffering:a}))};
|
|
k.$d=function(){wg(this)};k.Sa=function(){if(!this.O){var a=this.ka?"buffering":this.f.ended?"ended":this.f.paused?"paused":"playing";var b=Date.now()/1E3;if(this.i.stateHistory.length){var c=this.i.stateHistory[this.i.stateHistory.length-1];c.duration=b-c.timestamp;if(a==c.state)return}this.i.stateHistory.push({timestamp:b,state:a,duration:0})}};k.ce=function(){if(this.v){var a=this.v;a.c.forEach(a.o.bind(a,!0))}this.a&&Bf(this.a)};
|
|
function Hg(a,b,c,d,e){if(!c||1>c.length)return a.ya(new t(2,4,4012)),{};a.b.abr.manager.setVariants(c);a.b.abr.manager.setTextStreams(d);var f=[];e&&(f=["video","audio"],b.textStreams.length&&f.push("text"));e=vf(a.a);var g=a.a;var h=g.c.video||g.c.audio;g=h?g.b.periods[h.wa]:null;if(b=fc(e.audio,e.video,g?g.variants:b.variants)){b.allowedByApplication&&b.allowedByKeySystem||(f.push("audio"),f.push("video"));for(var l in e)b=e[l],"audio"==b.type&&b.language!=c[0].language?f.push(l):"text"==b.type&&
|
|
0<d.length&&b.language!=d[0].language&&f.push(l)}f=f.filter(Aa);if(0<f.length){c={};try{c=a.b.abr.manager.chooseStreams(f)}catch(m){a.ya(m)}return c}return{}}function Ag(a,b){var c={audio:!1,text:!1},d=dc(b,a.ia,c,a.mb),e=ec(b,a.Ca,c,a.lb),d=Hg(a,b,d,e),f;for(f in d)Cg(a,d[f],!0);Dg(a,d,!0);xg(a);d.text&&d.audio&&c.text&&d.text.language!=d.audio.language&&(a.A.mode="showing",Fg(a))}
|
|
k.ed=function(a){this.Za=!0;this.b.abr.manager.disable();var b=dc(a,this.ia,void 0,this.mb),c=ec(a,this.Ca,void 0,this.lb);a=Hg(this,a,b,c,!0);for(var d in this.G)a[d]=this.G[d].stream;this.G={};for(d in a)Cg(this,a[d],!0);return a};k.Gc=function(){this.Za=!1;this.b.abr.enabled&&this.b.abr.manager.enable();for(var a in this.G){var b=this.G[a];yf(this.a,a,b.stream,b.Kc)}this.G={}};k.ld=function(){this.h&&this.h.update&&this.h.update()};k.ud=function(){this.g&&this.g.Ab()};
|
|
k.Lb=function(a,b){var c=vf(this.a),d;for(d in a){var e=a[d];c[d]!=e?Cg(this,e,!0):delete a[d]}if(!Ma(a)&&this.a){for(d in a)yf(this.a,d,a[d],b||!1);xg(this)}};function xg(a){Promise.resolve().then(function(){this.O||this.dispatchEvent(new I("adaptation"))}.bind(a))}function wg(a){Promise.resolve().then(function(){this.O||this.dispatchEvent(new I("trackschanged"))}.bind(a))}function Fg(a){a.dispatchEvent(new I("texttrackvisibility"))}k.ya=function(a){this.O||this.dispatchEvent(new I("error",{detail:a}))};
|
|
k.xd=function(a){this.v?this.v.v(a):this.Xa.push(a)};k.gb=function(a){this.dispatchEvent(a)};k.yd=function(){if(this.f.error){var a=this.f.error.code;if(1!=a){var b=this.f.error.msExtendedCode;b&&(0>b&&(b+=Math.pow(2,32)),b=b.toString(16));this.ya(new t(2,3,3016,a,b))}}};
|
|
k.be=function(a){var b=["output-restricted","internal-error"],c=V(this.a),d=!1;c.variants.forEach(function(c){var e=[];c.audio&&e.push(c.audio);c.video&&e.push(c.video);e.forEach(function(e){var f=c.allowedByKeySystem;e.keyId&&(e=a[e.keyId],c.allowedByKeySystem=!!e&&0>b.indexOf(e));f!=c.allowedByKeySystem&&(d=!0)})});var e=vf(this.a);(e=fc(e.audio,e.video,c.variants))&&!e.allowedByKeySystem&&Ag(this,c);d&&wg(this)};
|
|
k.ae=function(a,b){if(this.h&&this.h.onExpirationUpdated)this.h.onExpirationUpdated(a,b);this.dispatchEvent(new I("expirationupdated"))};function X(a){if(!a||a.constructor!=W)throw new t(2,9,9008);this.a=fg();this.f=a;this.i=Ig(this);this.b=null;this.v=!1;this.j=null;this.g=-1;this.l=0;this.c=null;this.h=new gg(this.a,a.o,a.getConfiguration().streaming.retryParameters,this.i)}n("shaka.offline.Storage",X);function Jg(){return!!window.indexedDB}X.support=Jg;X.prototype.m=function(){var a=this.a,b=this.h?this.h.m()["catch"](function(){}).then(function(){if(a)return a.m()}):Promise.resolve();this.i=this.f=this.h=this.a=null;return b};
|
|
X.prototype.destroy=X.prototype.m;X.prototype.configure=function(a){Ca(this.i,a,Ig(this),{},"")};X.prototype.configure=X.prototype.configure;
|
|
X.prototype.le=function(a,b,c){function d(a){f=a}if(this.v)return Promise.reject(new t(2,9,9006));this.v=!0;var e,f=null;return Kg(this).then(function(){Y(this);return Lg(this,a,d,c)}.bind(this)).then(function(c){Y(this);this.c=c.manifest;this.b=c.Lc;if(this.c.presentationTimeline.$()||this.c.presentationTimeline.va())throw new t(2,9,9005,a);this.c.periods.forEach(this.o.bind(this));this.g=this.a.c.manifest++;this.l=0;c=this.c.periods.map(this.B.bind(this));var d=this.b.b,f=jb(this.b);if(d){if(!f.length)throw new t(2,
|
|
9,9007,a);d.initData=[]}e={key:this.g,originalManifestUri:a,duration:this.l,size:0,expiration:this.b.ab(),periods:c,sessionIds:f,drmInfo:d,appMetadata:b};return ig(this.h,e)}.bind(this)).then(function(){Y(this);if(f)throw f;return Mg(this)}.bind(this)).then(function(){return $f(e)}.bind(this))["catch"](function(a){return Mg(this)["catch"](y).then(function(){throw a;})}.bind(this))};X.prototype.store=X.prototype.le;
|
|
X.prototype.remove=function(a){function b(a){6013!=a.code&&(e=a)}var c=a.offlineUri,d=/^offline:([0-9]+)$/.exec(c);if(!d)return Promise.reject(new t(2,9,9004,c));var e=null,f,g,h=Number(d[1]);return Kg(this).then(function(){Y(this);return this.a.get("manifest",h)}.bind(this)).then(function(a){Y(this);if(!a)throw new t(2,9,9003,c);f=a;a=lg(f);g=new bb(this.f.o,b,function(){},function(){});g.configure(this.f.getConfiguration().drm);return g.init(a,!0)}.bind(this)).then(function(){return gb(g,f.sessionIds)}.bind(this)).then(function(){return g.m()}.bind(this)).then(function(){Y(this);
|
|
if(e)throw e;var b=f.periods.map(function(a){return a.streams.map(function(a){var b=a.segments.map(function(a){a=/^offline:[0-9]+\/[0-9]+\/([0-9]+)$/.exec(a.uri);return Number(a[1])});a.initSegmentUri&&(a=/^offline:[0-9]+\/[0-9]+\/([0-9]+)$/.exec(a.initSegmentUri),b.push(Number(a[1])));return b}).reduce(x,[])}).reduce(x,[]),c=0,d=b.length,g=this.i.progressCallback;return Xf(this.a,b,function(){c++;g(a,c/d)})}.bind(this)).then(function(){Y(this);this.i.progressCallback(a,1);return this.a.remove("manifest",
|
|
h)}.bind(this))};X.prototype.remove=X.prototype.remove;X.prototype.list=function(){var a=[];return Kg(this).then(function(){Y(this);return this.a.forEach("manifest",function(b){a.push($f(b))})}.bind(this)).then(function(){return a})};X.prototype.list=X.prototype.list;
|
|
function Lg(a,b,c,d){function e(){}var f=a.f.o,g=a.f.getConfiguration(),h,l,m;return Gd(b,f,g.manifest.retryParameters,d).then(function(a){Y(this);m=new a;m.configure(g.manifest);return m.start(b,{networkingEngine:f,filterPeriod:this.o.bind(this),onTimelineRegionAdded:function(){},onEvent:function(){},onError:c})}.bind(a)).then(function(a){Y(this);h=a;l=new bb(f,c,e,function(){});l.configure(g.drm);return l.init(h,!0)}.bind(a)).then(function(){Y(this);return Ng(h)}.bind(a)).then(function(){Y(this);
|
|
return fb(l)}.bind(a)).then(function(){Y(this);return m.stop()}.bind(a)).then(function(){Y(this);return{manifest:h,Lc:l}}.bind(a))["catch"](function(a){if(m)return m.stop().then(function(){throw a;});throw a;})}
|
|
X.prototype.A=function(a){for(var b=[],c=Sb(this.f.getConfiguration().preferredAudioLanguage),d=[0,Qb,Rb],e=a.filter(function(a){return"variant"==a.type}),d=d.map(function(a){return e.filter(function(b){b=Sb(b.language);return Pb(a,c,b)})}),f,g=0;g<d.length;g++)if(d[g].length){f=d[g];break}f||(d=e.filter(function(a){return a.primary}),d.length&&(f=d));f||(f=e,e.map(function(a){return a.language}).filter(Aa));var h=f.filter(function(a){return a.height&&480>=a.height});h.length&&(h.sort(function(a,
|
|
b){return b.height-a.height}),f=h.filter(function(a){return a.height==h[0].height}));f.sort(function(a,b){return a.bandwidth-b.bandwidth});f.length&&b.push(f[Math.floor(f.length/2)]);b.push.apply(b,a.filter(function(a){return"text"==a.type}));return b};function Ig(a){return{trackSelectionCallback:a.A.bind(a),progressCallback:function(a,c){if(a||c)return null}}}function Kg(a){return a.a?a.a.a?Promise.resolve():a.a.init(Zf):Promise.reject(new t(2,9,9E3))}
|
|
X.prototype.o=function(a){var b={};if(this.j){var c=this.j.filter(function(a){return"variant"==a.type}),d=null;c.length&&(d=bc(a,c[0]));d&&(d.video&&(b.video=d.video),d.audio&&(b.audio=d.audio))}Wb(this.b,b,a);Vb(a,this.f.getConfiguration().restrictions,{width:Infinity,height:Infinity})};function Mg(a){var b=a.b?a.b.m():Promise.resolve();a.b=null;a.c=null;a.v=!1;a.j=null;a.g=-1;return b}
|
|
function Ng(a){var b=a.periods.map(function(a){return a.variants}).reduce(x,[]).map(function(a){var b=[];a.audio&&b.push(a.audio);a.video&&b.push(a.video);return b}).reduce(x,[]).filter(Aa);a=a.periods.map(function(a){return a.textStreams}).reduce(x,[]);b.push.apply(b,a);return Promise.all(b.map(function(a){return a.createSegmentIndex()}))}
|
|
X.prototype.B=function(a){var b,c,d=Zb(a,null,null),e=ac(a,null),d=this.i.trackSelectionCallback(d.concat(e));this.j||(this.j=d,this.c.periods.forEach(this.o.bind(this)));for(e=d.length-1;0<e;--e){var f=!1;for(c=e-1;0<=c;--c)if(d[e].type==d[c].type&&d[e].kind==d[c].kind&&d[e].language==d[c].language){f=!0;break}if(f)break}f=[];for(e=0;e<d.length;e++)(b=bc(a,d[e]))?(b.audio&&((c=f.filter(function(a){return a.id==b.audio.id})[0])?c.variantIds.push(b.id):(c=b.video?b.bandwidth/2:b.bandwidth,f.push(Og(this,
|
|
a,b.audio,c,b.id)))),b.video&&((c=f.filter(function(a){return a.id==b.video.id})[0])?c.variantIds.push(b.id):(c=b.audio?b.bandwidth/2:b.bandwidth,f.push(Og(this,a,b.video,c,b.id))))):f.push(Og(this,a,cc(a,d[e]),0));return{startTime:a.startTime,streams:f}};
|
|
function Og(a,b,c,d,e){var f=[],g=a.c.presentationTimeline.ma();var h=g;for(var l=c.findSegmentPosition(g),m=null!=l?c.getSegmentReference(l):null;m;)h=a.a.c.segment++,hg(a.h,c.type,m,(m.endTime-m.startTime)*d/8,{key:h,data:null,manifestKey:a.g,streamNumber:c.id,segmentNumber:h}),f.push({startTime:m.startTime,endTime:m.endTime,uri:"offline:"+a.g+"/"+c.id+"/"+h}),h=m.endTime+b.startTime,m=c.getSegmentReference(++l);a.l=Math.max(a.l,h-g);b=null;c.initSegmentReference&&(h=a.a.c.segment++,b="offline:"+
|
|
a.g+"/"+c.id+"/"+h,hg(a.h,c.contentType,c.initSegmentReference,0,{key:h,data:null,manifestKey:a.g,streamNumber:c.id,segmentNumber:-1}));a=[];null!=e&&a.push(e);return{id:c.id,primary:c.primary,presentationTimeOffset:c.presentationTimeOffset||0,contentType:c.type,mimeType:c.mimeType,codecs:c.codecs,frameRate:c.frameRate,kind:c.kind,language:c.language,label:c.label,width:c.width||null,height:c.height||null,initSegmentUri:b,encrypted:c.encrypted,keyId:c.keyId,segments:f,variantIds:a}}
|
|
function Y(a){if(!a.f)throw new t(2,9,9002);}tg.offline=Jg;n("shaka.polyfill.installAll",function(){for(var a=0;a<Pg.length;++a)Pg[a]()});var Pg=[];function Qg(a){Pg.push(a)}n("shaka.polyfill.register",Qg);function Rg(a){var b=a.type.replace(/^(webkit|moz|MS)/,"").toLowerCase();if("function"===typeof Event)var c=new Event(b,a);else c=document.createEvent("Event"),c.initEvent(b,a.bubbles,a.cancelable);a.target.dispatchEvent(c)}
|
|
Qg(function(){if(window.Document){var a=Element.prototype;a.requestFullscreen=a.requestFullscreen||a.mozRequestFullScreen||a.msRequestFullscreen||a.webkitRequestFullscreen;a=Document.prototype;a.exitFullscreen=a.exitFullscreen||a.mozCancelFullScreen||a.msExitFullscreen||a.webkitExitFullscreen;"fullscreenElement"in document||(Object.defineProperty(document,"fullscreenElement",{get:function(){return document.mozFullScreenElement||document.msFullscreenElement||document.webkitFullscreenElement}}),Object.defineProperty(document,
|
|
"fullscreenEnabled",{get:function(){return document.mozFullScreenEnabled||document.msFullscreenEnabled||document.webkitFullscreenEnabled}}));document.addEventListener("webkitfullscreenchange",Rg);document.addEventListener("webkitfullscreenerror",Rg);document.addEventListener("mozfullscreenchange",Rg);document.addEventListener("mozfullscreenerror",Rg);document.addEventListener("MSFullscreenChange",Rg);document.addEventListener("MSFullscreenError",Rg)}});Qg(function(){var a=navigator.userAgent;a&&0<=a.indexOf("CrKey")&&delete window.indexedDB});Qg(function(){if(4503599627370497!=Math.round(4503599627370497)){var a=Math.round;Math.round=function(b){var c=b;4503599627370496>=b&&(c=a(b));return c}}});function Sg(a){this.f=[];this.b=[];this.a=[];(new Q).da("pssh",this.c.bind(this)).parse(a.buffer)}Sg.prototype.c=function(a){if(!(1<a.version)){var b=$a(a.s.Ka(16)),c=[];if(0<a.version)for(var d=a.s.D(),e=0;e<d;++e){var f=$a(a.s.Ka(16));c.push(f)}d=a.s.D();a.s.I(d);this.b.push.apply(this.b,c);this.f.push(b);this.a.push({start:a.start,end:a.start+a.size-1})}};function Tg(a,b){try{var c=new Ug(a,b);return Promise.resolve(c)}catch(d){return Promise.reject(d)}}
|
|
function Ug(a,b){this.keySystem=a;for(var c=!1,d=0;d<b.length;++d){var e=b[d];var f={audioCapabilities:[],videoCapabilities:[],persistentState:"optional",distinctiveIdentifier:"optional",initDataTypes:e.initDataTypes,sessionTypes:["temporary"],label:e.label},g=!1;if(e.audioCapabilities)for(var h=0;h<e.audioCapabilities.length;++h){var l=e.audioCapabilities[h];if(l.contentType){g=!0;var m=l.contentType.split(";")[0];MSMediaKeys.isTypeSupported(this.keySystem,m)&&(f.audioCapabilities.push(l),c=!0)}}if(e.videoCapabilities)for(h=
|
|
0;h<e.videoCapabilities.length;++h)l=e.videoCapabilities[h],l.contentType&&(g=!0,m=l.contentType.split(";")[0],MSMediaKeys.isTypeSupported(this.keySystem,m)&&(f.videoCapabilities.push(l),c=!0));g||(c=MSMediaKeys.isTypeSupported(this.keySystem,"video/mp4"));"required"==e.persistentState&&(f.persistentState="required",f.sessionTypes=["persistent-license"]);if(c){this.a=f;return}}e=Error("Unsupported keySystem");e.name="NotSupportedError";e.code=DOMException.NOT_SUPPORTED_ERR;throw e;}
|
|
Ug.prototype.createMediaKeys=function(){var a=new Vg(this.keySystem);return Promise.resolve(a)};Ug.prototype.getConfiguration=function(){return this.a};function Wg(a){var b=this.mediaKeys;b&&b!=a&&Xg(b,null);delete this.mediaKeys;return(this.mediaKeys=a)?Xg(a,this):Promise.resolve()}function Vg(a){this.a=new MSMediaKeys(a);this.b=new D}Vg.prototype.createSession=function(a){if("temporary"!=(a||"temporary"))throw new TypeError("Session type "+a+" is unsupported on this platform.");return new Yg(this.a)};
|
|
Vg.prototype.setServerCertificate=function(){return Promise.resolve(!1)};function Xg(a,b){function c(){b.msSetMediaKeys(d.a);b.removeEventListener("loadedmetadata",c)}Ja(a.b);if(!b)return Promise.resolve();E(a.b,b,"msneedkey",Zg);var d=a;try{return 1<=b.readyState?b.msSetMediaKeys(a.a):b.addEventListener("loadedmetadata",c),Promise.resolve()}catch(e){return Promise.reject(e)}}
|
|
function Yg(a){p.call(this);this.c=null;this.g=a;this.b=this.a=null;this.f=new D;this.sessionId="";this.expiration=NaN;this.closed=new A;this.keyStatuses=new $g}ba(Yg);k=Yg.prototype;k.generateRequest=function(a,b){this.a=new A;try{this.c=this.g.createSession("video/mp4",new Uint8Array(b),null),E(this.f,this.c,"mskeymessage",this.pd.bind(this)),E(this.f,this.c,"mskeyadded",this.nd.bind(this)),E(this.f,this.c,"mskeyerror",this.od.bind(this)),ah(this,"status-pending")}catch(c){this.a.reject(c)}return this.a};
|
|
k.load=function(){return Promise.reject(Error("MediaKeySession.load not yet supported"))};k.update=function(a){this.b=new A;try{this.c.update(new Uint8Array(a))}catch(b){this.b.reject(b)}return this.b};k.close=function(){try{this.c.close(),this.closed.resolve(),Ja(this.f)}catch(a){this.closed.reject(a)}return this.closed};k.remove=function(){return Promise.reject(Error("MediaKeySession.remove is only applicable for persistent licenses, which are not supported on this platform"))};
|
|
function Zg(a){var b=document.createEvent("CustomEvent");b.initCustomEvent("encrypted",!1,!1,null);b.initDataType="cenc";var c=a.initData;if(c){var d=new Sg(c);if(1>=d.a.length)a=c;else{var e=[];for(a=0;a<d.a.length;a++)e.push(c.subarray(d.a[a].start,d.a[a].end+1));c=Ga(e,bh);for(a=d=0;a<c.length;a++)d+=c[a].length;d=new Uint8Array(d);for(a=e=0;a<c.length;a++)d.set(c[a],e),e+=c[a].length;a=d}}else a=c;b.initData=a;this.dispatchEvent(b)}function bh(a,b){return ab(a,b)}
|
|
k.pd=function(a){this.a&&(this.a.resolve(),this.a=null);this.dispatchEvent(new I("message",{messageType:void 0==this.keyStatuses.sb()?"licenserequest":"licenserenewal",message:a.message.buffer}))};k.nd=function(){this.a?(ah(this,"usable"),this.a.resolve(),this.a=null):this.b&&(ah(this,"usable"),this.b.resolve(),this.b=null)};
|
|
k.od=function(){var a=Error("EME PatchedMediaKeysMs key error");a.errorCode=this.c.error;if(this.a)this.a.reject(a),this.a=null;else if(this.b)this.b.reject(a),this.b=null;else switch(this.c.error.code){case MSMediaKeyError.MS_MEDIA_KEYERR_OUTPUT:case MSMediaKeyError.MS_MEDIA_KEYERR_HARDWARECHANGE:ah(this,"output-not-allowed");default:ah(this,"internal-error")}};function ah(a,b){a.keyStatuses.Kb(b);a.dispatchEvent(new I("keystatuseschange"))}function $g(){this.size=0;this.a=void 0}var ch;k=$g.prototype;
|
|
k.Kb=function(a){this.size=void 0==a?0:1;this.a=a};k.sb=function(){return this.a};k.forEach=function(a){this.a&&a(this.a,ch)};k.get=function(a){if(this.has(a))return this.a};k.has=function(a){var b=ch;return this.a&&ab(new Uint8Array(a),new Uint8Array(b))?!0:!1};k.entries=function(){};k.keys=function(){};k.values=function(){};function dh(){return Promise.reject(Error("The key system specified is not supported."))}function eh(a){return a?Promise.reject(Error("MediaKeys not supported.")):Promise.resolve()}function fh(){throw new TypeError("Illegal constructor.");}fh.prototype.createSession=function(){};fh.prototype.setServerCertificate=function(){};function gh(){throw new TypeError("Illegal constructor.");}gh.prototype.getConfiguration=function(){};gh.prototype.createMediaKeys=function(){};var hh="";function ih(a){hh=a;jh=(new Uint8Array([0])).buffer;navigator.requestMediaKeySystemAccess=kh;delete HTMLMediaElement.prototype.mediaKeys;HTMLMediaElement.prototype.mediaKeys=null;HTMLMediaElement.prototype.setMediaKeys=lh;window.MediaKeys=mh;window.MediaKeySystemAccess=nh}function oh(a){var b=hh;return b?b+a.charAt(0).toUpperCase()+a.slice(1):a}function kh(a,b){try{var c=new nh(a,b);return Promise.resolve(c)}catch(d){return Promise.reject(d)}}
|
|
function lh(a){var b=this.mediaKeys;b&&b!=a&&ph(b,null);delete this.mediaKeys;(this.mediaKeys=a)&&ph(a,this);return Promise.resolve()}
|
|
function nh(a,b){this.a=this.keySystem=a;var c=!0;"org.w3.clearkey"==a&&(this.a="webkit-org.w3.clearkey",c=!1);var d=!1;var e=document.getElementsByTagName("video");var f=e.length?e[0]:document.createElement("video");for(var g=0;g<b.length;++g){e=b[g];var h={audioCapabilities:[],videoCapabilities:[],persistentState:"optional",distinctiveIdentifier:"optional",initDataTypes:e.initDataTypes,sessionTypes:["temporary"],label:e.label},l=!1;if(e.audioCapabilities)for(var m=0;m<e.audioCapabilities.length;++m){var q=
|
|
e.audioCapabilities[m];if(q.contentType){var l=!0,r=q.contentType.split(";")[0];f.canPlayType(r,this.a)&&(h.audioCapabilities.push(q),d=!0)}}if(e.videoCapabilities)for(m=0;m<e.videoCapabilities.length;++m)q=e.videoCapabilities[m],q.contentType&&(l=!0,f.canPlayType(q.contentType,this.a)&&(h.videoCapabilities.push(q),d=!0));l||(d=f.canPlayType("video/mp4",this.a)||f.canPlayType("video/webm",this.a));"required"==e.persistentState&&(c?(h.persistentState="required",h.sessionTypes=["persistent-license"]):
|
|
d=!1);if(d){this.b=h;return}}c="Unsupported keySystem";if("org.w3.clearkey"==a||"com.widevine.alpha"==a)c="None of the requested configurations were supported.";c=Error(c);c.name="NotSupportedError";c.code=DOMException.NOT_SUPPORTED_ERR;throw c;}nh.prototype.createMediaKeys=function(){var a=new mh(this.a);return Promise.resolve(a)};nh.prototype.getConfiguration=function(){return this.b};function mh(a){this.g=a;this.b=null;this.a=new D;this.c=[];this.f={}}
|
|
function ph(a,b){a.b=b;Ja(a.a);var c=hh;b&&(E(a.a,b,c+"needkey",a.Cd.bind(a)),E(a.a,b,c+"keymessage",a.Bd.bind(a)),E(a.a,b,c+"keyadded",a.zd.bind(a)),E(a.a,b,c+"keyerror",a.Ad.bind(a)))}k=mh.prototype;k.createSession=function(a){var b=a||"temporary";if("temporary"!=b&&"persistent-license"!=b)throw new TypeError("Session type "+a+" is unsupported on this platform.");a=this.b||document.createElement("video");a.src||(a.src="about:blank");b=new qh(a,this.g,b);this.c.push(b);return b};
|
|
k.setServerCertificate=function(){return Promise.resolve(!1)};k.Cd=function(a){var b=document.createEvent("CustomEvent");b.initCustomEvent("encrypted",!1,!1,null);b.initDataType="webm";b.initData=a.initData;this.b.dispatchEvent(b)};k.Bd=function(a){var b=rh(this,a.sessionId);b&&(a=new I("message",{messageType:void 0==b.keyStatuses.sb()?"licenserequest":"licenserenewal",message:a.message}),b.b&&(b.b.resolve(),b.b=null),b.dispatchEvent(a))};
|
|
k.zd=function(a){if(a=rh(this,a.sessionId))sh(a,"usable"),a.a&&a.a.resolve(),a.a=null};
|
|
k.Ad=function(a){var b=rh(this,a.sessionId);if(b){var c=Error("EME v0.1b key error");c.errorCode=a.errorCode;c.errorCode.systemCode=a.systemCode;!a.sessionId&&b.b?(c.method="generateRequest",45==a.systemCode&&(c.message="Unsupported session type."),b.b.reject(c),b.b=null):a.sessionId&&b.a?(c.method="update",b.a.reject(c),b.a=null):(c=a.systemCode,a.errorCode.code==MediaKeyError.MEDIA_KEYERR_OUTPUT?sh(b,"output-restricted"):1==c?sh(b,"expired"):sh(b,"internal-error"))}};
|
|
function rh(a,b){var c=a.f[b];return c?c:(c=a.c.shift())?(c.sessionId=b,a.f[b]=c):null}function qh(a,b,c){p.call(this);this.f=a;this.h=!1;this.a=this.b=null;this.c=b;this.g=c;this.sessionId="";this.expiration=NaN;this.closed=new A;this.keyStatuses=new th}ba(qh);
|
|
function uh(a,b,c){if(a.h)return Promise.reject(Error("The session is already initialized."));a.h=!0;try{if("persistent-license"==a.g)if(c)var d=new Uint8Array(Ua("LOAD_SESSION|"+c));else{var e=Ua("PERSISTENT|"),f=new Uint8Array(e.byteLength+b.byteLength);f.set(new Uint8Array(e),0);f.set(new Uint8Array(b),e.byteLength);d=f}else d=new Uint8Array(b)}catch(h){return Promise.reject(h)}a.b=new A;var g=oh("generateKeyRequest");try{a.f[g](a.c,d)}catch(h){if("InvalidStateError"!=h.name)return a.b=null,Promise.reject(h);
|
|
setTimeout(function(){try{this.f[g](this.c,d)}catch(l){this.b.reject(l),this.b=null}}.bind(a),10)}return a.b}k=qh.prototype;
|
|
k.Mb=function(a,b){if(this.a)this.a.then(this.Mb.bind(this,a,b))["catch"](this.Mb.bind(this,a,b));else{this.a=a;if("webkit-org.w3.clearkey"==this.c){var c=F(b);var d=JSON.parse(c);"oct"!=d.keys[0].kty&&(this.a.reject(Error("Response is not a valid JSON Web Key Set.")),this.a=null);c=Ya(d.keys[0].k);d=Ya(d.keys[0].kid)}else c=new Uint8Array(b),d=null;var e=oh("addKey");try{this.f[e](this.c,c,d,this.sessionId)}catch(f){this.a.reject(f),this.a=null}}};
|
|
function sh(a,b){a.keyStatuses.Kb(b);a.dispatchEvent(new I("keystatuseschange"))}k.generateRequest=function(a,b){return uh(this,b,null)};k.load=function(a){return"persistent-license"==this.g?uh(this,null,a):Promise.reject(Error("Not a persistent session."))};k.update=function(a){var b=new A;this.Mb(b,a);return b};
|
|
k.close=function(){if("persistent-license"!=this.g){if(!this.sessionId)return this.closed.reject(Error("The session is not callable.")),this.closed;var a=oh("cancelKeyRequest");try{this.f[a](this.c,this.sessionId)}catch(b){}}this.closed.resolve();return this.closed};k.remove=function(){return"persistent-license"!=this.g?Promise.reject(Error("Not a persistent session.")):this.close()};function th(){this.size=0;this.a=void 0}var jh;k=th.prototype;k.Kb=function(a){this.size=void 0==a?0:1;this.a=a};
|
|
k.sb=function(){return this.a};k.forEach=function(a){this.a&&a(this.a,jh)};k.get=function(a){if(this.has(a))return this.a};k.has=function(a){var b=jh;return this.a&&ab(new Uint8Array(a),new Uint8Array(b))?!0:!1};k.entries=function(){};k.keys=function(){};k.values=function(){};Qg(function(){!window.HTMLVideoElement||navigator.requestMediaKeySystemAccess&&MediaKeySystemAccess.prototype.getConfiguration||(HTMLMediaElement.prototype.webkitGenerateKeyRequest?ih("webkit"):HTMLMediaElement.prototype.generateKeyRequest?ih(""):window.MSMediaKeys?(ch=(new Uint8Array([0])).buffer,delete HTMLMediaElement.prototype.mediaKeys,HTMLMediaElement.prototype.mediaKeys=null,HTMLMediaElement.prototype.setMediaKeys=Wg,window.MediaKeys=Vg,window.MediaKeySystemAccess=Ug,navigator.requestMediaKeySystemAccess=
|
|
Tg):(navigator.requestMediaKeySystemAccess=dh,delete HTMLMediaElement.prototype.mediaKeys,HTMLMediaElement.prototype.mediaKeys=null,HTMLMediaElement.prototype.setMediaKeys=eh,window.MediaKeys=fh,window.MediaKeySystemAccess=gh))});function vh(){var a=MediaSource.prototype.addSourceBuffer;MediaSource.prototype.addSourceBuffer=function(){var b=a.apply(this,arguments);b.abort=function(){};return b}}
|
|
function wh(){var a=MediaSource.prototype.endOfStream;MediaSource.prototype.endOfStream=function(){for(var b,d=0,e=0;e<this.sourceBuffers.length;++e)b=this.sourceBuffers[e],b=b.buffered.end(b.buffered.length-1),d=Math.max(d,b);if(!isNaN(this.duration)&&d<this.duration)for(this.Zb=!0,e=0;e<this.sourceBuffers.length;++e)b=this.sourceBuffers[e],b.Tb=!1;return a.apply(this,arguments)};var b=MediaSource.prototype.addSourceBuffer;MediaSource.prototype.addSourceBuffer=function(){var a=b.apply(this,arguments);
|
|
a.N=this;a.addEventListener("updateend",xh,!1);this.a||(this.addEventListener("sourceclose",yh,!1),this.a=!0);return a}}function xh(a){var b=a.target,c=b.N;if(c.Zb){a.preventDefault();a.stopPropagation();a.stopImmediatePropagation();b.Tb=!0;for(a=0;a<c.sourceBuffers.length;++a)if(0==c.sourceBuffers[a].Tb)return;c.Zb=!1}}function yh(a){a=a.target;for(var b=0;b<a.sourceBuffers.length;++b)a.sourceBuffers[b].removeEventListener("updateend",xh,!1);a.removeEventListener("sourceclose",yh,!1)}
|
|
Qg(function(){if(window.MediaSource){var a=navigator.vendor,b=navigator.appVersion;!a||!b||0>a.indexOf("Apple")||(0<=b.indexOf("Version/8")?window.MediaSource=null:0<=b.indexOf("Version/9")?vh():0<=b.indexOf("Version/10")&&(vh(),wh()))}});function Z(a){this.c=[];this.b=[];this.Aa=zh;if(a)try{a(this.fa.bind(this),this.a.bind(this))}catch(b){this.a(b)}}var zh=0;function Ah(a){var b=new Z;b.fa(void 0);return b.then(function(){return a})}function Bh(a){var b=new Z;b.a(a);return b}function Ch(a){function b(a,b,c){a.Aa==zh&&(e[b]=c,d++,d==e.length&&a.fa(e))}var c=new Z;if(!a.length)return c.fa([]),c;for(var d=0,e=Array(a.length),f=c.a.bind(c),g=0;g<a.length;++g)a[g]&&a[g].then?a[g].then(b.bind(null,c,g),f):b(c,g,a[g]);return c}
|
|
function Dh(a){for(var b=new Z,c=b.fa.bind(b),d=b.a.bind(b),e=0;e<a.length;++e)a[e]&&a[e].then?a[e].then(c,d):c(a[e]);return b}Z.prototype.then=function(a,b){var c=new Z;switch(this.Aa){case 1:Eh(this,c,a);break;case 2:Eh(this,c,b);break;case zh:this.c.push({L:c,pb:a}),this.b.push({L:c,pb:b})}return c};Z.prototype["catch"]=function(a){return this.then(void 0,a)};
|
|
Z.prototype.fa=function(a){if(this.Aa==zh){this.jb=a;this.Aa=1;for(a=0;a<this.c.length;++a)Eh(this,this.c[a].L,this.c[a].pb);this.c=[];this.b=[]}};Z.prototype.a=function(a){if(this.Aa==zh){this.jb=a;this.Aa=2;for(a=0;a<this.b.length;++a)Eh(this,this.b[a].L,this.b[a].pb);this.c=[];this.b=[]}};
|
|
function Eh(a,b,c){Fh.push(function(){if(c&&"function"==typeof c){try{var a=c(this.jb)}catch(f){b.a(f);return}try{var e=a&&a.then}catch(f){b.a(f);return}a instanceof Z?a==b?b.a(new TypeError("Chaining cycle detected")):a.then(b.fa.bind(b),b.a.bind(b)):e?Gh(a,e,b):b.fa(a)}else 1==this.Aa?b.fa(this.jb):b.a(this.jb)}.bind(a));null==Hh&&(Hh=Ih(Jh))}
|
|
function Gh(a,b,c){try{var d=!1;b.call(a,function(a){if(!d){d=!0;try{var b=a&&a.then}catch(g){c.a(g);return}b?Gh(a,b,c):c.fa(a)}},c.a.bind(c))}catch(e){c.a(e)}}function Jh(){for(;Fh.length;){null!=Hh&&(Kh(Hh),Hh=null);var a=Fh;Fh=[];for(var b=0;b<a.length;++b)a[b]()}}function Ih(){return 0}function Kh(){}var Hh=null,Fh=[];
|
|
Qg(function(a){window.setImmediate?(Ih=function(a){return window.setImmediate(a)},Kh=function(a){return window.clearImmediate(a)}):(Ih=function(a){return window.setTimeout(a,0)},Kh=function(a){return window.clearTimeout(a)});if(!window.Promise||a)window.Promise=Z,window.Promise.resolve=Ah,window.Promise.reject=Bh,window.Promise.all=Ch,window.Promise.race=Dh,window.Promise.prototype.then=Z.prototype.then,window.Promise.prototype["catch"]=Z.prototype["catch"]});Qg(function(){if(window.HTMLMediaElement){var a=HTMLMediaElement.prototype.play;HTMLMediaElement.prototype.play=function(){var b=a.apply(this,arguments);b&&b["catch"](function(){});return b}}});function Lh(){return{droppedVideoFrames:this.webkitDroppedFrameCount,totalVideoFrames:this.webkitDecodedFrameCount,corruptedVideoFrames:0,creationTime:NaN,totalFrameDelay:0}}Qg(function(){if(window.HTMLVideoElement){var a=HTMLVideoElement.prototype;!a.getVideoPlaybackQuality&&"webkitDroppedFrameCount"in a&&(a.getVideoPlaybackQuality=Lh)}});function Mh(a,b,c){return new window.TextTrackCue(a,b,c)}function Nh(a,b,c){return new window.TextTrackCue(a+"-"+b+"-"+c,a,b,c)}Qg(function(){if(!window.VTTCue&&window.TextTrackCue){var a=TextTrackCue.length;if(3==a)window.VTTCue=Mh;else if(6==a)window.VTTCue=Nh;else{try{var b=!!Mh(1,2,"")}catch(c){b=!1}b&&(window.VTTCue=Mh)}}});}.call(g,this));
|
|
if (typeof(module)!="undefined"&&module.exports)module.exports=g.shaka;
|
|
else if (typeof(define)!="undefined" && define.amd)define(function(){return g.shaka});
|
|
else this.shaka=g.shaka;
|
|
})();
|
|
|
|
|
|
},{}],6:[function(_dereq_,module,exports){
|
|
// stats.js - http://github.com/mrdoob/stats.js
|
|
var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";
|
|
i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div");
|
|
k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display=
|
|
"block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:12,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height=
|
|
a+"px",m=b,r=0);return b},update:function(){l=this.end()}}};"object"===typeof module&&(module.exports=Stats);
|
|
|
|
},{}],7:[function(_dereq_,module,exports){
|
|
(function (global){
|
|
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.WebVRManager = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof _dereq_=="function"&&_dereq_;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof _dereq_=="function"&&_dereq_;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Emitter = _dereq_('./emitter.js');
|
|
var Modes = _dereq_('./modes.js');
|
|
var Util = _dereq_('./util.js');
|
|
|
|
/**
|
|
* Everything having to do with the WebVR button.
|
|
* Emits a 'click' event when it's clicked.
|
|
*/
|
|
function ButtonManager(opt_root) {
|
|
var root = opt_root || document.body;
|
|
this.loadIcons_();
|
|
|
|
// Make the fullscreen button.
|
|
var fsButton = this.createButton();
|
|
fsButton.src = this.ICONS.fullscreen;
|
|
fsButton.title = 'Fullscreen mode';
|
|
var s = fsButton.style;
|
|
s.bottom = '40px';
|
|
s.right = 0;
|
|
fsButton.addEventListener('click', this.createClickHandler_('fs'));
|
|
root.appendChild(fsButton);
|
|
this.fsButton = fsButton;
|
|
|
|
// Make the VR button.
|
|
var vrButton = this.createButton();
|
|
vrButton.src = this.ICONS.cardboard;
|
|
vrButton.title = 'Virtual reality mode';
|
|
var s = vrButton.style;
|
|
s.bottom = '40px';
|
|
s.right = '48px';
|
|
vrButton.addEventListener('click', this.createClickHandler_('vr'));
|
|
root.appendChild(vrButton);
|
|
this.vrButton = vrButton;
|
|
|
|
this.isVisible = true;
|
|
|
|
}
|
|
ButtonManager.prototype = new Emitter();
|
|
|
|
ButtonManager.prototype.createButton = function() {
|
|
var button = document.createElement('img');
|
|
button.className = 'webvr-button';
|
|
var s = button.style;
|
|
s.position = 'absolute';
|
|
s.width = '24px'
|
|
s.height = '24px';
|
|
s.backgroundSize = 'cover';
|
|
s.backgroundColor = 'transparent';
|
|
s.border = 0;
|
|
s.userSelect = 'none';
|
|
s.webkitUserSelect = 'none';
|
|
s.MozUserSelect = 'none';
|
|
s.cursor = 'pointer';
|
|
s.padding = '12px';
|
|
s.zIndex = 1;
|
|
s.display = 'none';
|
|
s.boxSizing = 'content-box';
|
|
|
|
// Prevent button from being selected and dragged.
|
|
button.draggable = false;
|
|
button.addEventListener('dragstart', function(e) {
|
|
e.preventDefault();
|
|
});
|
|
|
|
// Style it on hover.
|
|
button.addEventListener('mouseenter', function(e) {
|
|
s.filter = s.webkitFilter = 'drop-shadow(0 0 5px rgba(255,255,255,1))';
|
|
});
|
|
button.addEventListener('mouseleave', function(e) {
|
|
s.filter = s.webkitFilter = '';
|
|
});
|
|
return button;
|
|
};
|
|
|
|
ButtonManager.prototype.setMode = function(mode, isVRCompatible) {
|
|
isVRCompatible = isVRCompatible || WebVRConfig.FORCE_ENABLE_VR;
|
|
if (!this.isVisible) {
|
|
return;
|
|
}
|
|
switch (mode) {
|
|
case Modes.NORMAL:
|
|
this.fsButton.style.display = 'none';
|
|
this.fsButton.src = this.ICONS.fullscreen;
|
|
this.vrButton.style.display = (isVRCompatible ? 'block' : 'none');
|
|
break;
|
|
case Modes.MAGIC_WINDOW:
|
|
this.fsButton.style.display = 'block';
|
|
this.fsButton.src = this.ICONS.exitFullscreen;
|
|
this.vrButton.style.display = 'none';
|
|
break;
|
|
case Modes.VR:
|
|
this.fsButton.style.display = 'none';
|
|
this.vrButton.style.display = 'none';
|
|
break;
|
|
}
|
|
|
|
// Hack for Safari Mac/iOS to force relayout (svg-specific issue)
|
|
// http://goo.gl/hjgR6r
|
|
var oldValue = this.fsButton.style.display;
|
|
this.fsButton.style.display = 'inline-block';
|
|
this.fsButton.offsetHeight;
|
|
this.fsButton.style.display = oldValue;
|
|
};
|
|
|
|
ButtonManager.prototype.setVisibility = function(isVisible) {
|
|
this.isVisible = isVisible;
|
|
this.fsButton.style.display = isVisible ? 'block' : 'none';
|
|
this.vrButton.style.display = isVisible ? 'block' : 'none';
|
|
};
|
|
|
|
ButtonManager.prototype.createClickHandler_ = function(eventName) {
|
|
return function(e) {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
this.emit(eventName);
|
|
}.bind(this);
|
|
};
|
|
|
|
ButtonManager.prototype.loadIcons_ = function() {
|
|
// Preload some hard-coded SVG.
|
|
this.ICONS = {};
|
|
this.ICONS.cardboard = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMjAuNzQgNkgzLjIxQzIuNTUgNiAyIDYuNTcgMiA3LjI4djEwLjQ0YzAgLjcuNTUgMS4yOCAxLjIzIDEuMjhoNC43OWMuNTIgMCAuOTYtLjMzIDEuMTQtLjc5bDEuNC0zLjQ4Yy4yMy0uNTkuNzktMS4wMSAxLjQ0LTEuMDFzMS4yMS40MiAxLjQ1IDEuMDFsMS4zOSAzLjQ4Yy4xOS40Ni42My43OSAxLjExLjc5aDQuNzljLjcxIDAgMS4yNi0uNTcgMS4yNi0xLjI4VjcuMjhjMC0uNy0uNTUtMS4yOC0xLjI2LTEuMjh6TTcuNSAxNC42MmMtMS4xNyAwLTIuMTMtLjk1LTIuMTMtMi4xMiAwLTEuMTcuOTYtMi4xMyAyLjEzLTIuMTMgMS4xOCAwIDIuMTIuOTYgMi4xMiAyLjEzcy0uOTUgMi4xMi0yLjEyIDIuMTJ6bTkgMGMtMS4xNyAwLTIuMTMtLjk1LTIuMTMtMi4xMiAwLTEuMTcuOTYtMi4xMyAyLjEzLTIuMTNzMi4xMi45NiAyLjEyIDIuMTMtLjk1IDIuMTItMi4xMiAyLjEyeiIvPgogICAgPHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgyNHYyNEgwVjB6Ii8+Cjwvc3ZnPgo=');
|
|
this.ICONS.fullscreen = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNNyAxNEg1djVoNXYtMkg3di0zem0tMi00aDJWN2gzVjVINXY1em0xMiA3aC0zdjJoNXYtNWgtMnYzek0xNCA1djJoM3YzaDJWNWgtNXoiLz4KPC9zdmc+Cg==');
|
|
this.ICONS.exitFullscreen = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNNSAxNmgzdjNoMnYtNUg1djJ6bTMtOEg1djJoNVY1SDh2M3ptNiAxMWgydi0zaDN2LTJoLTV2NXptMi0xMVY1aC0ydjVoNVY4aC0zeiIvPgo8L3N2Zz4K');
|
|
this.ICONS.settings = Util.base64('image/svg+xml', 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI0ZGRkZGRiI+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+CiAgICA8cGF0aCBkPSJNMTkuNDMgMTIuOThjLjA0LS4zMi4wNy0uNjQuMDctLjk4cy0uMDMtLjY2LS4wNy0uOThsMi4xMS0xLjY1Yy4xOS0uMTUuMjQtLjQyLjEyLS42NGwtMi0zLjQ2Yy0uMTItLjIyLS4zOS0uMy0uNjEtLjIybC0yLjQ5IDFjLS41Mi0uNC0xLjA4LS43My0xLjY5LS45OGwtLjM4LTIuNjVDMTQuNDYgMi4xOCAxNC4yNSAyIDE0IDJoLTRjLS4yNSAwLS40Ni4xOC0uNDkuNDJsLS4zOCAyLjY1Yy0uNjEuMjUtMS4xNy41OS0xLjY5Ljk4bC0yLjQ5LTFjLS4yMy0uMDktLjQ5IDAtLjYxLjIybC0yIDMuNDZjLS4xMy4yMi0uMDcuNDkuMTIuNjRsMi4xMSAxLjY1Yy0uMDQuMzItLjA3LjY1LS4wNy45OHMuMDMuNjYuMDcuOThsLTIuMTEgMS42NWMtLjE5LjE1LS4yNC40Mi0uMTIuNjRsMiAzLjQ2Yy4xMi4yMi4zOS4zLjYxLjIybDIuNDktMWMuNTIuNCAxLjA4LjczIDEuNjkuOThsLjM4IDIuNjVjLjAzLjI0LjI0LjQyLjQ5LjQyaDRjLjI1IDAgLjQ2LS4xOC40OS0uNDJsLjM4LTIuNjVjLjYxLS4yNSAxLjE3LS41OSAxLjY5LS45OGwyLjQ5IDFjLjIzLjA5LjQ5IDAgLjYxLS4yMmwyLTMuNDZjLjEyLS4yMi4wNy0uNDktLjEyLS42NGwtMi4xMS0xLjY1ek0xMiAxNS41Yy0xLjkzIDAtMy41LTEuNTctMy41LTMuNXMxLjU3LTMuNSAzLjUtMy41IDMuNSAxLjU3IDMuNSAzLjUtMS41NyAzLjUtMy41IDMuNXoiLz4KPC9zdmc+Cg==');
|
|
};
|
|
|
|
module.exports = ButtonManager;
|
|
|
|
},{"./emitter.js":2,"./modes.js":3,"./util.js":4}],2:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
function Emitter() {
|
|
this.callbacks = {};
|
|
}
|
|
|
|
Emitter.prototype.emit = function(eventName) {
|
|
var callbacks = this.callbacks[eventName];
|
|
if (!callbacks) {
|
|
//console.log('No valid callback specified.');
|
|
return;
|
|
}
|
|
var args = [].slice.call(arguments);
|
|
// Eliminate the first param (the callback).
|
|
args.shift();
|
|
for (var i = 0; i < callbacks.length; i++) {
|
|
callbacks[i].apply(this, args);
|
|
}
|
|
};
|
|
|
|
Emitter.prototype.on = function(eventName, callback) {
|
|
if (eventName in this.callbacks) {
|
|
this.callbacks[eventName].push(callback);
|
|
} else {
|
|
this.callbacks[eventName] = [callback];
|
|
}
|
|
};
|
|
|
|
module.exports = Emitter;
|
|
|
|
},{}],3:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Modes = {
|
|
UNKNOWN: 0,
|
|
// Not fullscreen, just tracking.
|
|
NORMAL: 1,
|
|
// Magic window immersive mode.
|
|
MAGIC_WINDOW: 2,
|
|
// Full screen split screen VR mode.
|
|
VR: 3,
|
|
};
|
|
|
|
module.exports = Modes;
|
|
|
|
},{}],4:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Util = {};
|
|
|
|
Util.base64 = function(mimeType, base64) {
|
|
return 'data:' + mimeType + ';base64,' + base64;
|
|
};
|
|
|
|
Util.isMobile = function() {
|
|
var check = false;
|
|
(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
|
|
return check;
|
|
};
|
|
|
|
Util.isFirefox = function() {
|
|
return /firefox/i.test(navigator.userAgent);
|
|
};
|
|
|
|
Util.isIOS = function() {
|
|
return /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
|
|
};
|
|
|
|
Util.isIFrame = function() {
|
|
try {
|
|
return window.self !== window.top;
|
|
} catch (e) {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
Util.appendQueryParameter = function(url, key, value) {
|
|
// Determine delimiter based on if the URL already GET parameters in it.
|
|
var delimiter = (url.indexOf('?') < 0 ? '?' : '&');
|
|
url += delimiter + key + '=' + value;
|
|
return url;
|
|
};
|
|
|
|
// From http://goo.gl/4WX3tg
|
|
Util.getQueryParameter = function(name) {
|
|
var name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
|
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
|
|
results = regex.exec(location.search);
|
|
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
|
|
};
|
|
|
|
Util.isLandscapeMode = function() {
|
|
return (window.orientation == 90 || window.orientation == -90);
|
|
};
|
|
|
|
Util.getScreenWidth = function() {
|
|
return Math.max(window.screen.width, window.screen.height) *
|
|
window.devicePixelRatio;
|
|
};
|
|
|
|
Util.getScreenHeight = function() {
|
|
return Math.min(window.screen.width, window.screen.height) *
|
|
window.devicePixelRatio;
|
|
};
|
|
|
|
module.exports = Util;
|
|
|
|
},{}],5:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var ButtonManager = _dereq_('./button-manager.js');
|
|
var Emitter = _dereq_('./emitter.js');
|
|
var Modes = _dereq_('./modes.js');
|
|
var Util = _dereq_('./util.js');
|
|
|
|
/**
|
|
* Helper for getting in and out of VR mode.
|
|
*/
|
|
function WebVRManager(renderer, effect, params) {
|
|
this.params = params || {};
|
|
|
|
this.mode = Modes.UNKNOWN;
|
|
|
|
// Set option to hide the button.
|
|
this.hideButton = this.params.hideButton || false;
|
|
// Whether or not the FOV should be distorted or un-distorted. By default, it
|
|
// should be distorted, but in the case of vertex shader based distortion,
|
|
// ensure that we use undistorted parameters.
|
|
this.predistorted = !!this.params.predistorted;
|
|
|
|
// Save the THREE.js renderer and effect for later.
|
|
this.renderer = renderer;
|
|
this.effect = effect;
|
|
var polyfillWrapper = document.querySelector('.webvr-polyfill-fullscreen-wrapper');
|
|
this.button = new ButtonManager(polyfillWrapper);
|
|
|
|
this.isFullscreenDisabled = !!Util.getQueryParameter('no_fullscreen');
|
|
this.startMode = Modes.NORMAL;
|
|
var startModeParam = parseInt(Util.getQueryParameter('start_mode'));
|
|
if (!isNaN(startModeParam)) {
|
|
this.startMode = startModeParam;
|
|
}
|
|
|
|
if (this.hideButton) {
|
|
this.button.setVisibility(false);
|
|
}
|
|
|
|
// Check if the browser is compatible with WebVR.
|
|
this.getDeviceByType_(VRDisplay).then(function(hmd) {
|
|
this.hmd = hmd;
|
|
|
|
// Only enable VR mode if there's a VR device attached or we are running the
|
|
// polyfill on mobile.
|
|
if (!this.isVRCompatibleOverride) {
|
|
this.isVRCompatible = !hmd.isPolyfilled || Util.isMobile();
|
|
}
|
|
|
|
switch (this.startMode) {
|
|
case Modes.MAGIC_WINDOW:
|
|
this.setMode_(Modes.MAGIC_WINDOW);
|
|
break;
|
|
case Modes.VR:
|
|
this.enterVRMode_();
|
|
this.setMode_(Modes.VR);
|
|
break;
|
|
default:
|
|
this.setMode_(Modes.NORMAL);
|
|
}
|
|
|
|
this.emit('initialized');
|
|
}.bind(this));
|
|
|
|
// Hook up button listeners.
|
|
this.button.on('fs', this.onFSClick_.bind(this));
|
|
this.button.on('vr', this.onVRClick_.bind(this));
|
|
|
|
// Bind to fullscreen events.
|
|
document.addEventListener('webkitfullscreenchange',
|
|
this.onFullscreenChange_.bind(this));
|
|
document.addEventListener('mozfullscreenchange',
|
|
this.onFullscreenChange_.bind(this));
|
|
document.addEventListener('msfullscreenchange',
|
|
this.onFullscreenChange_.bind(this));
|
|
|
|
// Bind to VR* specific events.
|
|
window.addEventListener('vrdisplaypresentchange',
|
|
this.onVRDisplayPresentChange_.bind(this));
|
|
window.addEventListener('vrdisplaydeviceparamschange',
|
|
this.onVRDisplayDeviceParamsChange_.bind(this));
|
|
}
|
|
|
|
WebVRManager.prototype = new Emitter();
|
|
|
|
// Expose these values externally.
|
|
WebVRManager.Modes = Modes;
|
|
|
|
WebVRManager.prototype.render = function(scene, camera, timestamp) {
|
|
// Scene may be an array of two scenes, one for each eye.
|
|
if (scene instanceof Array) {
|
|
this.effect.render(scene[0], camera);
|
|
} else {
|
|
this.effect.render(scene, camera);
|
|
}
|
|
};
|
|
|
|
WebVRManager.prototype.setVRCompatibleOverride = function(isVRCompatible) {
|
|
this.isVRCompatible = isVRCompatible;
|
|
this.isVRCompatibleOverride = true;
|
|
|
|
// Don't actually change modes, just update the buttons.
|
|
this.button.setMode(this.mode, this.isVRCompatible);
|
|
};
|
|
|
|
WebVRManager.prototype.setFullscreenCallback = function(callback) {
|
|
this.fullscreenCallback = callback;
|
|
};
|
|
|
|
WebVRManager.prototype.setVRCallback = function(callback) {
|
|
this.vrCallback = callback;
|
|
};
|
|
|
|
WebVRManager.prototype.setExitFullscreenCallback = function(callback) {
|
|
this.exitFullscreenCallback = callback;
|
|
}
|
|
|
|
/**
|
|
* Promise returns true if there is at least one HMD device available.
|
|
*/
|
|
WebVRManager.prototype.getDeviceByType_ = function(type) {
|
|
return new Promise(function(resolve, reject) {
|
|
navigator.getVRDisplays().then(function(displays) {
|
|
// Promise succeeds, but check if there are any displays actually.
|
|
for (var i = 0; i < displays.length; i++) {
|
|
if (displays[i] instanceof type) {
|
|
resolve(displays[i]);
|
|
break;
|
|
}
|
|
}
|
|
resolve(null);
|
|
}, function() {
|
|
// No displays are found.
|
|
resolve(null);
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Helper for entering VR mode.
|
|
*/
|
|
WebVRManager.prototype.enterVRMode_ = function() {
|
|
this.hmd.requestPresent([{
|
|
source: this.renderer.domElement,
|
|
predistorted: this.predistorted
|
|
}]);
|
|
};
|
|
|
|
WebVRManager.prototype.setMode_ = function(mode) {
|
|
var oldMode = this.mode;
|
|
if (mode == this.mode) {
|
|
console.warn('Not changing modes, already in %s', mode);
|
|
return;
|
|
}
|
|
// console.log('Mode change: %s => %s', this.mode, mode);
|
|
this.mode = mode;
|
|
this.button.setMode(mode, this.isVRCompatible);
|
|
|
|
// Emit an event indicating the mode changed.
|
|
this.emit('modechange', mode, oldMode);
|
|
};
|
|
|
|
/**
|
|
* Main button was clicked.
|
|
*/
|
|
WebVRManager.prototype.onFSClick_ = function() {
|
|
switch (this.mode) {
|
|
case Modes.NORMAL:
|
|
// TODO: Remove this hack if/when iOS gets real fullscreen mode.
|
|
// If this is an iframe on iOS, break out and open in no_fullscreen mode.
|
|
if (Util.isIOS() && Util.isIFrame()) {
|
|
if (this.fullscreenCallback) {
|
|
this.fullscreenCallback();
|
|
} else {
|
|
var url = window.location.href;
|
|
url = Util.appendQueryParameter(url, 'no_fullscreen', 'true');
|
|
url = Util.appendQueryParameter(url, 'start_mode', Modes.MAGIC_WINDOW);
|
|
top.location.href = url;
|
|
return;
|
|
}
|
|
}
|
|
this.setMode_(Modes.MAGIC_WINDOW);
|
|
this.requestFullscreen_();
|
|
break;
|
|
case Modes.MAGIC_WINDOW:
|
|
if (this.isFullscreenDisabled) {
|
|
window.history.back();
|
|
return;
|
|
}
|
|
if (this.exitFullscreenCallback) {
|
|
this.exitFullscreenCallback();
|
|
}
|
|
this.setMode_(Modes.NORMAL);
|
|
this.exitFullscreen_();
|
|
break;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* The VR button was clicked.
|
|
*/
|
|
WebVRManager.prototype.onVRClick_ = function() {
|
|
// TODO: Remove this hack when iOS has fullscreen mode.
|
|
// If this is an iframe on iOS, break out and open in no_fullscreen mode.
|
|
if (this.mode == Modes.NORMAL && Util.isIOS() && Util.isIFrame()) {
|
|
if (this.vrCallback) {
|
|
this.vrCallback();
|
|
} else {
|
|
var url = window.location.href;
|
|
url = Util.appendQueryParameter(url, 'no_fullscreen', 'true');
|
|
url = Util.appendQueryParameter(url, 'start_mode', Modes.VR);
|
|
top.location.href = url;
|
|
return;
|
|
}
|
|
}
|
|
this.enterVRMode_();
|
|
};
|
|
|
|
WebVRManager.prototype.requestFullscreen_ = function() {
|
|
var canvas = document.body;
|
|
//var canvas = this.renderer.domElement;
|
|
if (canvas.requestFullscreen) {
|
|
canvas.requestFullscreen();
|
|
} else if (canvas.mozRequestFullScreen) {
|
|
canvas.mozRequestFullScreen();
|
|
} else if (canvas.webkitRequestFullscreen) {
|
|
canvas.webkitRequestFullscreen();
|
|
} else if (canvas.msRequestFullscreen) {
|
|
canvas.msRequestFullscreen();
|
|
}
|
|
};
|
|
|
|
WebVRManager.prototype.exitFullscreen_ = function() {
|
|
if (document.exitFullscreen) {
|
|
document.exitFullscreen();
|
|
} else if (document.mozCancelFullScreen) {
|
|
document.mozCancelFullScreen();
|
|
} else if (document.webkitExitFullscreen) {
|
|
document.webkitExitFullscreen();
|
|
} else if (document.msExitFullscreen) {
|
|
document.msExitFullscreen();
|
|
}
|
|
};
|
|
|
|
WebVRManager.prototype.onVRDisplayPresentChange_ = function(e) {
|
|
console.log('onVRDisplayPresentChange_', e);
|
|
if (this.hmd.isPresenting) {
|
|
this.setMode_(Modes.VR);
|
|
} else {
|
|
this.setMode_(Modes.NORMAL);
|
|
}
|
|
};
|
|
|
|
WebVRManager.prototype.onVRDisplayDeviceParamsChange_ = function(e) {
|
|
console.log('onVRDisplayDeviceParamsChange_', e);
|
|
};
|
|
|
|
WebVRManager.prototype.onFullscreenChange_ = function(e) {
|
|
// If we leave full-screen, go back to normal mode.
|
|
if (document.webkitFullscreenElement === null ||
|
|
document.mozFullScreenElement === null) {
|
|
this.setMode_(Modes.NORMAL);
|
|
}
|
|
};
|
|
|
|
module.exports = WebVRManager;
|
|
|
|
},{"./button-manager.js":1,"./emitter.js":2,"./modes.js":3,"./util.js":4}]},{},[5])(5)
|
|
});
|
|
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
},{}],8:[function(_dereq_,module,exports){
|
|
module.exports={
|
|
"_args": [
|
|
[
|
|
"webvr-polyfill@^0.9.38",
|
|
"/Users/lincolnfrog/daydream/vrview"
|
|
]
|
|
],
|
|
"_from": "webvr-polyfill@>=0.9.38 <0.10.0",
|
|
"_id": "webvr-polyfill@0.9.40",
|
|
"_inCache": true,
|
|
"_installable": true,
|
|
"_location": "/webvr-polyfill",
|
|
"_nodeVersion": "8.6.0",
|
|
"_npmOperationalInternal": {
|
|
"host": "s3://npm-registry-packages",
|
|
"tmp": "tmp/webvr-polyfill-0.9.40.tgz_1507657755590_0.00047161197289824486"
|
|
},
|
|
"_npmUser": {
|
|
"email": "jsantell@gmail.com",
|
|
"name": "jsantell"
|
|
},
|
|
"_npmVersion": "5.3.0",
|
|
"_phantomChildren": {},
|
|
"_requested": {
|
|
"name": "webvr-polyfill",
|
|
"raw": "webvr-polyfill@^0.9.38",
|
|
"rawSpec": "^0.9.38",
|
|
"scope": null,
|
|
"spec": ">=0.9.38 <0.10.0",
|
|
"type": "range"
|
|
},
|
|
"_requiredBy": [
|
|
"/",
|
|
"/webvr-boilerplate"
|
|
],
|
|
"_resolved": "https://registry.npmjs.org/webvr-polyfill/-/webvr-polyfill-0.9.40.tgz",
|
|
"_shasum": "2cfa0ec0e0cc6ba7238c73a09cba4952fff59a63",
|
|
"_shrinkwrap": null,
|
|
"_spec": "webvr-polyfill@^0.9.38",
|
|
"_where": "/Users/lincolnfrog/daydream/vrview",
|
|
"authors": [
|
|
"Boris Smus <boris@smus.com>",
|
|
"Brandon Jones <tojiro@gmail.com>",
|
|
"Jordan Santell <jordan@jsantell.com>"
|
|
],
|
|
"bugs": {
|
|
"url": "https://github.com/googlevr/webvr-polyfill/issues"
|
|
},
|
|
"dependencies": {},
|
|
"description": "Use WebVR today, on mobile or desktop, without requiring a special browser build.",
|
|
"devDependencies": {
|
|
"chai": "^3.5.0",
|
|
"jsdom": "^9.12.0",
|
|
"mocha": "^3.2.0",
|
|
"semver": "^5.3.0",
|
|
"webpack": "^2.6.1",
|
|
"webpack-dev-server": "2.7.1"
|
|
},
|
|
"directories": {},
|
|
"dist": {
|
|
"integrity": "sha512-m7jhJHjFcUYPyPSNeGmly7a2h/cP7bARz0OZMoUn5SueVXEKeZ4P7bzbAUDBDvvqCsa5gHgM3PFIhYe13bqaWw==",
|
|
"shasum": "2cfa0ec0e0cc6ba7238c73a09cba4952fff59a63",
|
|
"tarball": "https://registry.npmjs.org/webvr-polyfill/-/webvr-polyfill-0.9.40.tgz"
|
|
},
|
|
"gitHead": "45828ffdb8c3e0f9bb90296d6039d3cc7909ba8e",
|
|
"homepage": "https://github.com/googlevr/webvr-polyfill",
|
|
"keywords": [
|
|
"vr",
|
|
"webvr"
|
|
],
|
|
"license": "Apache-2.0",
|
|
"main": "src/node-entry",
|
|
"maintainers": [
|
|
{
|
|
"email": "jsantell@gmail.com",
|
|
"name": "jsantell"
|
|
},
|
|
{
|
|
"email": "tojiro@gmail.com",
|
|
"name": "toji"
|
|
},
|
|
{
|
|
"email": "boris@smus.com",
|
|
"name": "smus"
|
|
}
|
|
],
|
|
"name": "webvr-polyfill",
|
|
"optionalDependencies": {},
|
|
"readme": "ERROR: No README data found!",
|
|
"repository": {
|
|
"type": "git",
|
|
"url": "git+https://github.com/googlevr/webvr-polyfill.git"
|
|
},
|
|
"scripts": {
|
|
"build": "webpack",
|
|
"start": "npm run watch",
|
|
"test": "mocha",
|
|
"watch": "webpack-dev-server"
|
|
},
|
|
"version": "0.9.40"
|
|
}
|
|
|
|
},{}],9:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Util = _dereq_('./util.js');
|
|
var WakeLock = _dereq_('./wakelock.js');
|
|
|
|
// Start at a higher number to reduce chance of conflict.
|
|
var nextDisplayId = 1000;
|
|
var hasShowDeprecationWarning = false;
|
|
|
|
var defaultLeftBounds = [0, 0, 0.5, 1];
|
|
var defaultRightBounds = [0.5, 0, 0.5, 1];
|
|
|
|
/**
|
|
* The base class for all VR frame data.
|
|
*/
|
|
|
|
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;
|
|
};
|
|
|
|
/**
|
|
* The base class for all VR displays.
|
|
*/
|
|
function VRDisplay() {
|
|
this.isPolyfilled = true;
|
|
this.displayId = nextDisplayId++;
|
|
this.displayName = 'webvr-polyfill displayName';
|
|
|
|
this.depthNear = 0.01;
|
|
this.depthFar = 10000.0;
|
|
|
|
this.isConnected = true;
|
|
this.isPresenting = false;
|
|
this.capabilities = {
|
|
hasPosition: false,
|
|
hasOrientation: false,
|
|
hasExternalDisplay: false,
|
|
canPresent: false,
|
|
maxLayers: 1
|
|
};
|
|
this.stageParameters = null;
|
|
|
|
// "Private" members.
|
|
this.waitingForPresent_ = false;
|
|
this.layer_ = null;
|
|
|
|
this.fullscreenElement_ = null;
|
|
this.fullscreenWrapper_ = null;
|
|
this.fullscreenElementCachedStyle_ = null;
|
|
|
|
this.fullscreenEventTarget_ = null;
|
|
this.fullscreenChangeHandler_ = null;
|
|
this.fullscreenErrorHandler_ = null;
|
|
|
|
this.wakelock_ = new WakeLock();
|
|
}
|
|
|
|
VRDisplay.prototype.getFrameData = function(frameData) {
|
|
// TODO: Technically this should retain it's value for the duration of a frame
|
|
// but I doubt that's practical to do in javascript.
|
|
return Util.frameDataFromPose(frameData, this.getPose(), this);
|
|
};
|
|
|
|
VRDisplay.prototype.getPose = function() {
|
|
// TODO: Technically this should retain it's value for the duration of a frame
|
|
// but I doubt that's practical to do in javascript.
|
|
return this.getImmediatePose();
|
|
};
|
|
|
|
VRDisplay.prototype.requestAnimationFrame = function(callback) {
|
|
return window.requestAnimationFrame(callback);
|
|
};
|
|
|
|
VRDisplay.prototype.cancelAnimationFrame = function(id) {
|
|
return window.cancelAnimationFrame(id);
|
|
};
|
|
|
|
VRDisplay.prototype.wrapForFullscreen = function(element) {
|
|
// Don't wrap in iOS.
|
|
if (Util.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_;
|
|
}
|
|
|
|
// Remove any previously applied wrappers
|
|
this.removeFullscreenWrapper();
|
|
|
|
this.fullscreenElement_ = element;
|
|
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);
|
|
parent.insertBefore(element, this.fullscreenWrapper_);
|
|
parent.removeChild(this.fullscreenWrapper_);
|
|
|
|
return element;
|
|
};
|
|
|
|
VRDisplay.prototype.requestPresent = function(layers) {
|
|
var wasPresenting = this.isPresenting;
|
|
var self = this;
|
|
|
|
if (!(layers instanceof Array)) {
|
|
if (!hasShowDeprecationWarning) {
|
|
console.warn("Using a deprecated form of requestPresent. Should pass in an array of VRLayers.");
|
|
hasShowDeprecationWarning = true;
|
|
}
|
|
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) {
|
|
/*
|
|
todo: figure out the correct behavior if the source is not provided.
|
|
see https://github.com/w3c/webvr/issues/58
|
|
*/
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
var leftBounds = incomingLayer.leftBounds || defaultLeftBounds;
|
|
var rightBounds = incomingLayer.rightBounds || defaultRightBounds;
|
|
if (wasPresenting) {
|
|
// Already presenting, just changing configuration
|
|
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];
|
|
}
|
|
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
// Was not already presenting.
|
|
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() {
|
|
var actualFullscreenElement = Util.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.wakelock_.release();
|
|
self.endPresent_();
|
|
self.removeFullscreenListeners_();
|
|
}
|
|
self.fireVRDisplayPresentChange_();
|
|
}
|
|
var onFullscreenError = function() {
|
|
if (!self.waitingForPresent_) {
|
|
return;
|
|
}
|
|
|
|
self.removeFullscreenWrapper();
|
|
self.removeFullscreenListeners_();
|
|
|
|
self.wakelock_.release();
|
|
self.waitingForPresent_ = false;
|
|
self.isPresenting = false;
|
|
|
|
reject(new Error('Unable to present.'));
|
|
}
|
|
|
|
self.addFullscreenListeners_(fullscreenElement,
|
|
onFullscreenChange, onFullscreenError);
|
|
|
|
if (Util.requestFullscreen(fullscreenElement)) {
|
|
self.wakelock_.request();
|
|
self.waitingForPresent_ = true;
|
|
} else if (Util.isIOS() || Util.isWebViewAndroid()) {
|
|
// *sigh* Just fake it.
|
|
self.wakelock_.request();
|
|
self.isPresenting = true;
|
|
self.beginPresent_();
|
|
self.fireVRDisplayPresentChange_();
|
|
resolve();
|
|
}
|
|
}
|
|
|
|
if (!self.waitingForPresent_ && !Util.isIOS()) {
|
|
Util.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.wakelock_.release();
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
if (wasPresenting) {
|
|
if (!Util.exitFullscreen() && Util.isIOS()) {
|
|
self.endPresent_();
|
|
self.fireVRDisplayPresentChange_();
|
|
}
|
|
|
|
if (Util.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() {
|
|
// Important: unfortunately we cannot have full spec compliance here.
|
|
// CustomEvent custom fields all go under e.detail (so the VRDisplay ends up
|
|
// being e.detail.display, instead of e.display as per WebVR spec).
|
|
var event = new CustomEvent('vrdisplaypresentchange', {detail: {display: this}});
|
|
window.dispatchEvent(event);
|
|
};
|
|
|
|
VRDisplay.prototype.fireVRDisplayConnect_ = function() {
|
|
// Important: unfortunately we cannot have full spec compliance here.
|
|
// CustomEvent custom fields all go under e.detail (so the VRDisplay ends up
|
|
// being e.detail.display, instead of e.display as per WebVR spec).
|
|
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.beginPresent_ = function() {
|
|
// Override to add custom behavior when presentation begins.
|
|
};
|
|
|
|
VRDisplay.prototype.endPresent_ = function() {
|
|
// Override to add custom behavior when presentation ends.
|
|
};
|
|
|
|
VRDisplay.prototype.submitFrame = function(pose) {
|
|
// Override to add custom behavior for frame submission.
|
|
};
|
|
|
|
VRDisplay.prototype.getEyeParameters = function(whichEye) {
|
|
// Override to return accurate eye parameters if canPresent is true.
|
|
return null;
|
|
};
|
|
|
|
/*
|
|
* Deprecated classes
|
|
*/
|
|
|
|
/**
|
|
* The base class for all VR devices. (Deprecated)
|
|
*/
|
|
function VRDevice() {
|
|
this.isPolyfilled = true;
|
|
this.hardwareUnitId = 'webvr-polyfill hardwareUnitId';
|
|
this.deviceId = 'webvr-polyfill deviceId';
|
|
this.deviceName = 'webvr-polyfill deviceName';
|
|
}
|
|
|
|
/**
|
|
* The base class for all VR HMD devices. (Deprecated)
|
|
*/
|
|
function HMDVRDevice() {
|
|
}
|
|
HMDVRDevice.prototype = new VRDevice();
|
|
|
|
/**
|
|
* The base class for all VR position sensor devices. (Deprecated)
|
|
*/
|
|
function PositionSensorVRDevice() {
|
|
}
|
|
PositionSensorVRDevice.prototype = new VRDevice();
|
|
|
|
module.exports.VRFrameData = VRFrameData;
|
|
module.exports.VRDisplay = VRDisplay;
|
|
module.exports.VRDevice = VRDevice;
|
|
module.exports.HMDVRDevice = HMDVRDevice;
|
|
module.exports.PositionSensorVRDevice = PositionSensorVRDevice;
|
|
|
|
},{"./util.js":29,"./wakelock.js":31}],10:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var CardboardUI = _dereq_('./cardboard-ui.js');
|
|
var Util = _dereq_('./util.js');
|
|
var WGLUPreserveGLState = _dereq_('./deps/wglu-preserve-state.js');
|
|
|
|
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');
|
|
|
|
/**
|
|
* A mesh-based distorter.
|
|
*/
|
|
function CardboardDistorter(gl) {
|
|
this.gl = gl;
|
|
this.ctxAttribs = gl.getContextAttributes();
|
|
|
|
this.meshWidth = 20;
|
|
this.meshHeight = 20;
|
|
|
|
this.bufferScale = window.WebVRConfig.BUFFER_SCALE;
|
|
|
|
this.bufferWidth = gl.drawingBufferWidth;
|
|
this.bufferHeight = gl.drawingBufferHeight;
|
|
|
|
// Patching support
|
|
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 (!Util.isIOS()) {
|
|
this.realCanvasWidth = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'width');
|
|
this.realCanvasHeight = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'height');
|
|
}
|
|
|
|
this.isPatched = false;
|
|
|
|
// State tracking
|
|
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 = Util.linkProgram(gl, distortionVS, distortionFS, this.attribs);
|
|
this.uniforms = Util.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();
|
|
|
|
if (!window.WebVRConfig.CARDBOARD_UI_DISABLED) {
|
|
this.cardboardUI = new CardboardUI(gl);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Tears down all the resources created by the distorter and removes any
|
|
* patches.
|
|
*/
|
|
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();
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Resizes the backbuffer to match the canvas width and height.
|
|
*/
|
|
CardboardDistorter.prototype.onResize = function() {
|
|
var gl = this.gl;
|
|
var self = this;
|
|
|
|
var glState = [
|
|
gl.RENDERBUFFER_BINDING,
|
|
gl.TEXTURE_BINDING_2D, gl.TEXTURE0
|
|
];
|
|
|
|
WGLUPreserveGLState(gl, glState, function(gl) {
|
|
// Bind real backbuffer and clear it once. We don't need to clear it again
|
|
// after that because we're overwriting the same area every frame.
|
|
self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);
|
|
|
|
// Put things in a good state
|
|
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);
|
|
|
|
// Now bind and resize the fake backbuffer
|
|
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 (!Util.isIOS()) {
|
|
canvas.width = Util.getScreenWidth() * this.bufferScale;
|
|
canvas.height = Util.getScreenHeight() * this.bufferScale;
|
|
|
|
Object.defineProperty(canvas, 'width', {
|
|
configurable: true,
|
|
enumerable: true,
|
|
get: function() {
|
|
return self.bufferWidth;
|
|
},
|
|
set: function(value) {
|
|
self.bufferWidth = value;
|
|
self.realCanvasWidth.set.call(canvas, value);
|
|
self.onResize();
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(canvas, 'height', {
|
|
configurable: true,
|
|
enumerable: true,
|
|
get: function() {
|
|
return self.bufferHeight;
|
|
},
|
|
set: function(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;
|
|
// Silently make calls to bind the default framebuffer bind ours instead.
|
|
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;
|
|
Util.safariCssSizeWorkaround(canvas);
|
|
};
|
|
|
|
CardboardDistorter.prototype.unpatch = function() {
|
|
if (!this.isPatched) {
|
|
return;
|
|
}
|
|
|
|
var gl = this.gl;
|
|
var canvas = this.gl.canvas;
|
|
|
|
if (!Util.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;
|
|
|
|
// Check to see if our fake backbuffer is bound and bind the real backbuffer
|
|
// if that's the case.
|
|
if (this.lastBoundFramebuffer == this.framebuffer) {
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
}
|
|
|
|
this.isPatched = false;
|
|
|
|
setTimeout(function() {
|
|
Util.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];
|
|
}
|
|
|
|
// Left eye
|
|
this.viewportOffsetScale[0] = leftBounds[0]; // X
|
|
this.viewportOffsetScale[1] = leftBounds[1]; // Y
|
|
this.viewportOffsetScale[2] = leftBounds[2]; // Width
|
|
this.viewportOffsetScale[3] = leftBounds[3]; // Height
|
|
|
|
// Right eye
|
|
this.viewportOffsetScale[4] = rightBounds[0]; // X
|
|
this.viewportOffsetScale[5] = rightBounds[1]; // Y
|
|
this.viewportOffsetScale[6] = rightBounds[2]; // Width
|
|
this.viewportOffsetScale[7] = rightBounds[3]; // Height
|
|
};
|
|
|
|
/**
|
|
* Performs distortion pass on the injected backbuffer, rendering it to the real
|
|
* backbuffer.
|
|
*/
|
|
CardboardDistorter.prototype.submitFrame = function() {
|
|
var gl = this.gl;
|
|
var self = this;
|
|
|
|
var glState = [];
|
|
|
|
if (!window.WebVRConfig.DIRTY_SUBMIT_FRAME_BINDINGS) {
|
|
glState.push(
|
|
gl.CURRENT_PROGRAM,
|
|
gl.ARRAY_BUFFER_BINDING,
|
|
gl.ELEMENT_ARRAY_BUFFER_BINDING,
|
|
gl.TEXTURE_BINDING_2D, gl.TEXTURE0
|
|
);
|
|
}
|
|
|
|
WGLUPreserveGLState(gl, glState, function(gl) {
|
|
// Bind the real default framebuffer
|
|
self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);
|
|
|
|
// Make sure the GL state is in a good place
|
|
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 the backbuffer has an alpha channel clear every frame so the page
|
|
// doesn't show through.
|
|
if (self.ctxAttribs.alpha || Util.isIOS()) {
|
|
self.realClearColor.call(gl, 0, 0, 0, 1);
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
}
|
|
|
|
// Bind distortion program and mesh
|
|
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);
|
|
|
|
// Draws both eyes
|
|
gl.drawElements(gl.TRIANGLES, self.indexCount, gl.UNSIGNED_SHORT, 0);
|
|
|
|
if (self.cardboardUI) {
|
|
self.cardboardUI.renderNoState();
|
|
}
|
|
|
|
// Bind the fake default framebuffer again
|
|
self.realBindFramebuffer.call(self.gl, gl.FRAMEBUFFER, self.framebuffer);
|
|
|
|
// If preserveDrawingBuffer == false clear the framebuffer
|
|
if (!self.ctxAttribs.preserveDrawingBuffer) {
|
|
self.realClearColor.call(gl, 0, 0, 0, 0);
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
}
|
|
|
|
if (!window.WebVRConfig.DIRTY_SUBMIT_FRAME_BINDINGS) {
|
|
self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);
|
|
}
|
|
|
|
// Restore state
|
|
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);
|
|
}
|
|
});
|
|
|
|
// Workaround for the fact that Safari doesn't allow us to patch the canvas
|
|
// width and height correctly. After each submit frame check to see what the
|
|
// real backbuffer size has been set to and resize the fake backbuffer size
|
|
// to match.
|
|
if (Util.isIOS()) {
|
|
var canvas = gl.canvas;
|
|
if (canvas.width != self.bufferWidth || canvas.height != self.bufferHeight) {
|
|
self.bufferWidth = canvas.width;
|
|
self.bufferHeight = canvas.height;
|
|
self.onResize();
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Call when the deviceInfo has changed. At this point we need
|
|
* to re-calculate the distortion mesh.
|
|
*/
|
|
CardboardDistorter.prototype.updateDeviceInfo = function(deviceInfo) {
|
|
var gl = this.gl;
|
|
var self = this;
|
|
|
|
var glState = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING];
|
|
WGLUPreserveGLState(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);
|
|
|
|
// Indices don't change based on device parameters, so only compute once.
|
|
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;
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Build the distortion mesh vertices.
|
|
* Based on code from the Unity cardboard plugin.
|
|
*/
|
|
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;
|
|
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++) {
|
|
var u = i / (width - 1);
|
|
var v = j / (height - 1);
|
|
|
|
// Grid points regularly spaced in StreoScreen, and barrel distorted in
|
|
// the mesh.
|
|
var s = u;
|
|
var t = v;
|
|
var x = Util.lerp(lensFrustum[0], lensFrustum[2], u);
|
|
var y = Util.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]);
|
|
|
|
// Convert u,v to mesh screen coordinates.
|
|
var aspect = deviceInfo.device.widthMeters / deviceInfo.device.heightMeters;
|
|
|
|
// FIXME: The original Unity plugin multiplied U by the aspect ratio
|
|
// and didn't multiply either value by 2, but that seems to get it
|
|
// really close to correct looking for me. I hate this kind of "Don't
|
|
// know why it works" code though, and wold love a more logical
|
|
// explanation of what needs to happen here.
|
|
u = (viewport.x + u * viewport.width - 0.5) * 2.0; //* aspect;
|
|
v = (viewport.y + v * viewport.height - 0.5) * 2.0;
|
|
|
|
vertices[(vidx * 5) + 0] = u; // position.x
|
|
vertices[(vidx * 5) + 1] = v; // position.y
|
|
vertices[(vidx * 5) + 2] = s; // texCoord.x
|
|
vertices[(vidx * 5) + 3] = t; // texCoord.y
|
|
vertices[(vidx * 5) + 4] = e; // texCoord.z (viewport index)
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Build the distortion mesh indices.
|
|
* Based on code from the Unity cardboard plugin.
|
|
*/
|
|
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;
|
|
// Build a quad. Lower right and upper left quadrants have quads with
|
|
// the triangle diagonal flipped to get the vignette to interpolate
|
|
// correctly.
|
|
if ((i <= halfwidth) == (j <= halfheight)) {
|
|
// Quad diagonal lower left to upper right.
|
|
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 {
|
|
// Quad diagonal upper left to lower right.
|
|
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);
|
|
// In some cases (ahem... Safari), the descriptor returns undefined get and
|
|
// set fields. In this case, we need to create a synthetic property
|
|
// descriptor. This works around some of the issues in
|
|
// https://github.com/borismus/webvr-polyfill/issues/46
|
|
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;
|
|
};
|
|
|
|
module.exports = CardboardDistorter;
|
|
|
|
},{"./cardboard-ui.js":11,"./deps/wglu-preserve-state.js":13,"./util.js":29}],11:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Util = _dereq_('./util.js');
|
|
var WGLUPreserveGLState = _dereq_('./deps/wglu-preserve-state.js');
|
|
|
|
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;
|
|
|
|
// The gear has 6 identical sections, each spanning 60 degrees.
|
|
var kAnglePerGearSection = 60;
|
|
|
|
// Half-angle of the span of the outer rim.
|
|
var kOuterRimEndAngle = 12;
|
|
|
|
// Angle between the middle of the outer rim and the start of the inner rim.
|
|
var kInnerRimBeginAngle = 20;
|
|
|
|
// Distance from center to outer rim, normalized so that the entire model
|
|
// fits in a [-1, 1] x [-1, 1] square.
|
|
var kOuterRadius = 1;
|
|
|
|
// Distance from center to depressed rim, in model units.
|
|
var kMiddleRadius = 0.75;
|
|
|
|
// Radius of the inner hollow circle, in model units.
|
|
var kInnerRadius = 0.3125;
|
|
|
|
// Center line thickness in DP.
|
|
var kCenterLineThicknessDp = 4;
|
|
|
|
// Button width in DP.
|
|
var kButtonWidthDp = 28;
|
|
|
|
// Factor to scale the touch area that responds to the touch.
|
|
var kTouchSlopFactor = 1.5;
|
|
|
|
var Angles = [
|
|
0, kOuterRimEndAngle, kInnerRimBeginAngle,
|
|
kAnglePerGearSection - kInnerRimBeginAngle,
|
|
kAnglePerGearSection - kOuterRimEndAngle
|
|
];
|
|
|
|
/**
|
|
* Renders the alignment line and "options" gear. It is assumed that the canvas
|
|
* this is rendered into covers the entire screen (or close to it.)
|
|
*/
|
|
function CardboardUI(gl) {
|
|
this.gl = gl;
|
|
|
|
this.attribs = {
|
|
position: 0
|
|
};
|
|
this.program = Util.linkProgram(gl, uiVS, uiFS, this.attribs);
|
|
this.uniforms = Util.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();
|
|
};
|
|
|
|
/**
|
|
* Tears down all the resources created by the UI renderer.
|
|
*/
|
|
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);
|
|
};
|
|
|
|
/**
|
|
* Adds a listener to clicks on the gear and back icons
|
|
*/
|
|
CardboardUI.prototype.listen = function(optionsCallback, backCallback) {
|
|
var canvas = this.gl.canvas;
|
|
this.listener = function(event) {
|
|
var midline = canvas.clientWidth / 2;
|
|
var buttonSize = kButtonWidthDp * kTouchSlopFactor;
|
|
// Check to see if the user clicked on (or around) the gear icon
|
|
if (event.clientX > midline - buttonSize &&
|
|
event.clientX < midline + buttonSize &&
|
|
event.clientY > canvas.clientHeight - buttonSize) {
|
|
optionsCallback(event);
|
|
}
|
|
// Check to see if the user clicked on (or around) the back icon
|
|
else if (event.clientX < buttonSize && event.clientY < buttonSize) {
|
|
backCallback(event);
|
|
}
|
|
};
|
|
canvas.addEventListener('click', this.listener, false);
|
|
};
|
|
|
|
/**
|
|
* Builds the UI mesh.
|
|
*/
|
|
CardboardUI.prototype.onResize = function() {
|
|
var gl = this.gl;
|
|
var self = this;
|
|
|
|
var glState = [
|
|
gl.ARRAY_BUFFER_BINDING
|
|
];
|
|
|
|
WGLUPreserveGLState(gl, glState, function(gl) {
|
|
var vertices = [];
|
|
|
|
var midline = gl.drawingBufferWidth / 2;
|
|
|
|
// The gl buffer size will likely be smaller than the physical pixel count.
|
|
// So we need to scale the dps down based on the actual buffer size vs physical pixel count.
|
|
// This will properly size the ui elements no matter what the gl buffer resolution is
|
|
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;
|
|
|
|
// Build centerline
|
|
vertices.push(midline - lineWidth, buttonSize);
|
|
vertices.push(midline - lineWidth, gl.drawingBufferHeight);
|
|
vertices.push(midline + lineWidth, buttonSize);
|
|
vertices.push(midline + lineWidth, gl.drawingBufferHeight);
|
|
|
|
// Build gear
|
|
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;
|
|
|
|
// Build back arrow
|
|
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;
|
|
|
|
// Buffer data
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Performs distortion pass on the injected backbuffer, rendering it to the real
|
|
* backbuffer.
|
|
*/
|
|
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
|
|
];
|
|
|
|
WGLUPreserveGLState(gl, glState, function(gl) {
|
|
// Make sure the GL state is in a good place
|
|
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;
|
|
|
|
// Bind distortion program and mesh
|
|
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);
|
|
|
|
Util.orthoMatrix(this.projMat, 0, gl.drawingBufferWidth, 0, gl.drawingBufferHeight, 0.1, 1024.0);
|
|
gl.uniformMatrix4fv(this.uniforms.projectionMat, false, this.projMat);
|
|
|
|
// Draws UI element
|
|
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);
|
|
};
|
|
|
|
module.exports = CardboardUI;
|
|
|
|
},{"./deps/wglu-preserve-state.js":13,"./util.js":29}],12:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var CardboardDistorter = _dereq_('./cardboard-distorter.js');
|
|
var CardboardUI = _dereq_('./cardboard-ui.js');
|
|
var DeviceInfo = _dereq_('./device-info.js');
|
|
var Dpdb = _dereq_('./dpdb/dpdb.js');
|
|
var FusionPoseSensor = _dereq_('./sensor-fusion/fusion-pose-sensor.js');
|
|
var RotateInstructions = _dereq_('./rotate-instructions.js');
|
|
var ViewerSelector = _dereq_('./viewer-selector.js');
|
|
var VRDisplay = _dereq_('./base.js').VRDisplay;
|
|
var Util = _dereq_('./util.js');
|
|
|
|
var Eye = {
|
|
LEFT: 'left',
|
|
RIGHT: 'right'
|
|
};
|
|
|
|
/**
|
|
* VRDisplay based on mobile device parameters and DeviceMotion APIs.
|
|
*/
|
|
function CardboardVRDisplay() {
|
|
this.displayName = 'Cardboard VRDisplay (webvr-polyfill)';
|
|
|
|
this.capabilities.hasOrientation = true;
|
|
this.capabilities.canPresent = true;
|
|
|
|
// "Private" members.
|
|
this.bufferScale_ = window.WebVRConfig.BUFFER_SCALE;
|
|
this.poseSensor_ = new FusionPoseSensor();
|
|
this.distorter_ = null;
|
|
this.cardboardUI_ = null;
|
|
|
|
this.dpdb_ = new Dpdb(true, this.onDeviceParamsUpdated_.bind(this));
|
|
this.deviceInfo_ = new DeviceInfo(this.dpdb_.getDeviceParams());
|
|
|
|
this.viewerSelector_ = new ViewerSelector();
|
|
this.viewerSelector_.onChange(this.onViewerChanged_.bind(this));
|
|
|
|
// Set the correct initial viewer.
|
|
this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer());
|
|
|
|
if (!window.WebVRConfig.ROTATE_INSTRUCTIONS_DISABLED) {
|
|
this.rotateInstructions_ = new RotateInstructions();
|
|
}
|
|
|
|
if (Util.isIOS()) {
|
|
// Listen for resize events to workaround this awful Safari bug.
|
|
window.addEventListener('resize', this.onResize_.bind(this));
|
|
}
|
|
}
|
|
CardboardVRDisplay.prototype = new VRDisplay();
|
|
|
|
CardboardVRDisplay.prototype.getImmediatePose = function() {
|
|
return {
|
|
position: this.poseSensor_.getPosition(),
|
|
orientation: this.poseSensor_.getOrientation(),
|
|
linearVelocity: null,
|
|
linearAcceleration: null,
|
|
angularVelocity: null,
|
|
angularAcceleration: null
|
|
};
|
|
};
|
|
|
|
CardboardVRDisplay.prototype.resetPose = function() {
|
|
this.poseSensor_.resetPose();
|
|
};
|
|
|
|
CardboardVRDisplay.prototype.getEyeParameters = function(whichEye) {
|
|
var offset = [this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];
|
|
var fieldOfView;
|
|
|
|
// TODO: FoV can be a little expensive to compute. Cache when device params change.
|
|
if (whichEye == Eye.LEFT) {
|
|
offset[0] *= -1.0;
|
|
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: fieldOfView,
|
|
offset: offset,
|
|
// TODO: Should be able to provide better values than these.
|
|
renderWidth: this.deviceInfo_.device.width * 0.5 * this.bufferScale_,
|
|
renderHeight: this.deviceInfo_.device.height * this.bufferScale_,
|
|
};
|
|
};
|
|
|
|
CardboardVRDisplay.prototype.onDeviceParamsUpdated_ = function(newParams) {
|
|
if (Util.isDebug()) {
|
|
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; // Can't do distortion without a WebGL context.
|
|
|
|
// Provides a way to opt out of distortion
|
|
if (this.layer_.predistorted) {
|
|
if (!window.WebVRConfig.CARDBOARD_UI_DISABLED) {
|
|
gl.canvas.width = Util.getScreenWidth() * this.bufferScale_;
|
|
gl.canvas.height = Util.getScreenHeight() * this.bufferScale_;
|
|
this.cardboardUI_ = new CardboardUI(gl);
|
|
}
|
|
} else {
|
|
// Create a new distorter for the target context
|
|
this.distorter_ = new CardboardDistorter(gl);
|
|
this.distorter_.updateDeviceInfo(this.deviceInfo_);
|
|
this.cardboardUI_ = this.distorter_.cardboardUI;
|
|
}
|
|
|
|
if (this.cardboardUI_) {
|
|
this.cardboardUI_.listen(function(e) {
|
|
// Options clicked.
|
|
this.viewerSelector_.show(this.layer_.source.parentElement);
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
}.bind(this), function(e) {
|
|
// Back clicked.
|
|
this.exitPresent();
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
}.bind(this));
|
|
}
|
|
|
|
if (this.rotateInstructions_) {
|
|
if (Util.isLandscapeMode() && Util.isMobile()) {
|
|
// In landscape mode, temporarily show the "put into Cardboard"
|
|
// interstitial. Otherwise, do the default thing.
|
|
this.rotateInstructions_.showTemporarily(3000, this.layer_.source.parentElement);
|
|
} else {
|
|
this.rotateInstructions_.update();
|
|
}
|
|
}
|
|
|
|
// Listen for orientation change events in order to show interstitial.
|
|
this.orientationHandler = this.onOrientationChange_.bind(this);
|
|
window.addEventListener('orientationchange', this.orientationHandler);
|
|
|
|
// Listen for present display change events in order to update distorter dimensions
|
|
this.vrdisplaypresentchangeHandler = this.updateBounds_.bind(this);
|
|
window.addEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);
|
|
|
|
// Fire this event initially, to give geometry-distortion clients the chance
|
|
// to do something custom.
|
|
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.submitFrame = function(pose) {
|
|
if (this.distorter_) {
|
|
this.updateBounds_();
|
|
this.distorter_.submitFrame();
|
|
} else if (this.cardboardUI_ && this.layer_) {
|
|
// Hack for predistorted: true.
|
|
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;
|
|
|
|
// Render the Cardboard UI.
|
|
this.cardboardUI_.render();
|
|
}
|
|
};
|
|
|
|
CardboardVRDisplay.prototype.onOrientationChange_ = function(e) {
|
|
// Hide the viewer selector.
|
|
this.viewerSelector_.hide();
|
|
|
|
// Update the rotate instructions.
|
|
if (this.rotateInstructions_) {
|
|
this.rotateInstructions_.update();
|
|
}
|
|
|
|
this.onResize_();
|
|
};
|
|
|
|
CardboardVRDisplay.prototype.onResize_ = function(e) {
|
|
if (this.layer_) {
|
|
var gl = this.layer_.source.getContext('webgl');
|
|
// Size the CSS canvas.
|
|
// Added padding on right and bottom because iPhone 5 will not
|
|
// hide the URL bar unless content is bigger than the screen.
|
|
// This will not be visible as long as the container element (e.g. body)
|
|
// is set to 'overflow: hidden'.
|
|
// Additionally, 'box-sizing: content-box' ensures renderWidth = width + padding.
|
|
// This is required when 'box-sizing: border-box' is used elsewhere in the page.
|
|
var cssProperties = [
|
|
'position: absolute',
|
|
'top: 0',
|
|
'left: 0',
|
|
// Use vw/vh to handle implicitly devicePixelRatio; issue #282
|
|
'width: 100vw',
|
|
'height: 100vh',
|
|
'border: 0',
|
|
'margin: 0',
|
|
// Set no padding in the case where you don't have control over
|
|
// the content injection, like in Unity WebGL; issue #282
|
|
'padding: 0px',
|
|
'box-sizing: content-box',
|
|
];
|
|
gl.canvas.setAttribute('style', cssProperties.join('; ') + ';');
|
|
|
|
Util.safariCssSizeWorkaround(gl.canvas);
|
|
}
|
|
};
|
|
|
|
CardboardVRDisplay.prototype.onViewerChanged_ = function(viewer) {
|
|
this.deviceInfo_.setViewer(viewer);
|
|
|
|
if (this.distorter_) {
|
|
// Update the distortion appropriately.
|
|
this.distorter_.updateDeviceInfo(this.deviceInfo_);
|
|
}
|
|
|
|
// Fire a new event containing viewer and device parameters for clients that
|
|
// want to implement their own geometry-based distortion.
|
|
this.fireVRDisplayDeviceParamsChange_();
|
|
};
|
|
|
|
CardboardVRDisplay.prototype.fireVRDisplayDeviceParamsChange_ = function() {
|
|
var event = new CustomEvent('vrdisplaydeviceparamschange', {
|
|
detail: {
|
|
vrdisplay: this,
|
|
deviceInfo: this.deviceInfo_,
|
|
}
|
|
});
|
|
window.dispatchEvent(event);
|
|
};
|
|
|
|
module.exports = CardboardVRDisplay;
|
|
|
|
},{"./base.js":9,"./cardboard-distorter.js":10,"./cardboard-ui.js":11,"./device-info.js":14,"./dpdb/dpdb.js":18,"./rotate-instructions.js":23,"./sensor-fusion/fusion-pose-sensor.js":25,"./util.js":29,"./viewer-selector.js":30}],13:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2016, Brandon Jones.
|
|
* https://github.com/toji/webgl-utils/blob/master/src/wglu-preserve-state.js
|
|
* LICENSE: https://github.com/toji/webgl-utils/blob/master/LICENSE.md
|
|
*/
|
|
|
|
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; // Ignore this binding, since we special-case it to happen last.
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = WGLUPreserveGLState;
|
|
|
|
},{}],14:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Distortion = _dereq_('./distortion/distortion.js');
|
|
var MathUtil = _dereq_('./math-util.js');
|
|
var Util = _dereq_('./util.js');
|
|
|
|
function Device(params) {
|
|
this.width = params.width || Util.getScreenWidth();
|
|
this.height = params.height || Util.getScreenHeight();
|
|
this.widthMeters = params.widthMeters;
|
|
this.heightMeters = params.heightMeters;
|
|
this.bevelMeters = params.bevelMeters;
|
|
}
|
|
|
|
|
|
// Fallback Android device (based on Nexus 5 measurements) for use when
|
|
// we can't recognize an Android device.
|
|
var DEFAULT_ANDROID = new Device({
|
|
widthMeters: 0.110,
|
|
heightMeters: 0.062,
|
|
bevelMeters: 0.004
|
|
});
|
|
|
|
// Fallback iOS device (based on iPhone6) for use when
|
|
// we can't recognize an Android device.
|
|
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]
|
|
})
|
|
};
|
|
|
|
|
|
var DEFAULT_LEFT_CENTER = {x: 0.5, y: 0.5};
|
|
var DEFAULT_RIGHT_CENTER = {x: 0.5, y: 0.5};
|
|
|
|
/**
|
|
* Manages information about the device and the viewer.
|
|
*
|
|
* deviceParams indicates the parameters of the device to use (generally
|
|
* obtained from dpdb.getDeviceParams()). Can be null to mean no device
|
|
* params were found.
|
|
*/
|
|
function DeviceInfo(deviceParams) {
|
|
this.viewer = Viewers.CardboardV2;
|
|
this.updateDeviceParams(deviceParams);
|
|
this.distortion = new Distortion(this.viewer.distortionCoefficients);
|
|
}
|
|
|
|
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) {
|
|
// No parameters, so use a default.
|
|
if (Util.isIOS()) {
|
|
console.warn('Using fallback iOS device measurements.');
|
|
return DEFAULT_IOS;
|
|
} else {
|
|
console.warn('Using fallback Android device measurements.');
|
|
return DEFAULT_ANDROID;
|
|
}
|
|
}
|
|
|
|
// Compute device screen dimensions based on deviceParams.
|
|
var METERS_PER_INCH = 0.0254;
|
|
var metersPerPixelX = METERS_PER_INCH / deviceParams.xdpi;
|
|
var metersPerPixelY = METERS_PER_INCH / deviceParams.ydpi;
|
|
var width = Util.getScreenWidth();
|
|
var height = Util.getScreenHeight();
|
|
return new Device({
|
|
widthMeters: metersPerPixelX * width,
|
|
heightMeters: metersPerPixelY * height,
|
|
bevelMeters: deviceParams.bevelMm * 0.001,
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Calculates field of view for the left eye.
|
|
*/
|
|
DeviceInfo.prototype.getDistortedFieldOfViewLeftEye = function() {
|
|
var viewer = this.viewer;
|
|
var device = this.device;
|
|
var distortion = this.distortion;
|
|
|
|
// Device.height and device.width for device in portrait mode, so transpose.
|
|
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 = MathUtil.radToDeg * Math.atan(
|
|
distortion.distort(outerDist / eyeToScreenDistance));
|
|
var innerAngle = MathUtil.radToDeg * Math.atan(
|
|
distortion.distort(innerDist / eyeToScreenDistance));
|
|
var bottomAngle = MathUtil.radToDeg * Math.atan(
|
|
distortion.distort(bottomDist / eyeToScreenDistance));
|
|
var topAngle = MathUtil.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)
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Calculates the tan-angles from the maximum FOV for the left eye for the
|
|
* current device and screen parameters.
|
|
*/
|
|
DeviceInfo.prototype.getLeftEyeVisibleTanAngles = function() {
|
|
var viewer = this.viewer;
|
|
var device = this.device;
|
|
var distortion = this.distortion;
|
|
|
|
// Tan-angles from the max FOV.
|
|
var fovLeft = Math.tan(-MathUtil.degToRad * viewer.fov);
|
|
var fovTop = Math.tan(MathUtil.degToRad * viewer.fov);
|
|
var fovRight = Math.tan(MathUtil.degToRad * viewer.fov);
|
|
var fovBottom = Math.tan(-MathUtil.degToRad * viewer.fov);
|
|
// Viewport size.
|
|
var halfWidth = device.widthMeters / 4;
|
|
var halfHeight = device.heightMeters / 2;
|
|
// Viewport center, measured from left lens position.
|
|
var verticalLensOffset = (viewer.baselineLensDistance - device.bevelMeters - halfHeight);
|
|
var centerX = viewer.interLensDistance / 2 - halfWidth;
|
|
var centerY = -verticalLensOffset;
|
|
var centerZ = viewer.screenLensDistance;
|
|
// Tan-angles of the viewport edges, as seen through the lens.
|
|
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);
|
|
// Compare the two sets of tan-angles and take the value closer to zero on each side.
|
|
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;
|
|
};
|
|
|
|
/**
|
|
* Calculates the tan-angles from the maximum FOV for the left eye for the
|
|
* current device and screen parameters, assuming no lenses.
|
|
*/
|
|
DeviceInfo.prototype.getLeftEyeNoLensTanAngles = function() {
|
|
var viewer = this.viewer;
|
|
var device = this.device;
|
|
var distortion = this.distortion;
|
|
|
|
var result = new Float32Array(4);
|
|
// Tan-angles from the max FOV.
|
|
var fovLeft = distortion.distortInverse(Math.tan(-MathUtil.degToRad * viewer.fov));
|
|
var fovTop = distortion.distortInverse(Math.tan(MathUtil.degToRad * viewer.fov));
|
|
var fovRight = distortion.distortInverse(Math.tan(MathUtil.degToRad * viewer.fov));
|
|
var fovBottom = distortion.distortInverse(Math.tan(-MathUtil.degToRad * viewer.fov));
|
|
// Viewport size.
|
|
var halfWidth = device.widthMeters / 4;
|
|
var halfHeight = device.heightMeters / 2;
|
|
// Viewport center, measured from left lens position.
|
|
var verticalLensOffset = (viewer.baselineLensDistance - device.bevelMeters - halfHeight);
|
|
var centerX = viewer.interLensDistance / 2 - halfWidth;
|
|
var centerY = -verticalLensOffset;
|
|
var centerZ = viewer.screenLensDistance;
|
|
// Tan-angles of the viewport edges, as seen through the lens.
|
|
var screenLeft = (centerX - halfWidth) / centerZ;
|
|
var screenTop = (centerY + halfHeight) / centerZ;
|
|
var screenRight = (centerX + halfWidth) / centerZ;
|
|
var screenBottom = (centerY - halfHeight) / centerZ;
|
|
// Compare the two sets of tan-angles and take the value closer to zero on each side.
|
|
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;
|
|
};
|
|
|
|
/**
|
|
* Calculates the screen rectangle visible from the left eye for the
|
|
* current device and screen parameters.
|
|
*/
|
|
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
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Calculates undistorted field of view for the left eye.
|
|
*/
|
|
DeviceInfo.prototype.getUndistortedFieldOfViewLeftEye = function() {
|
|
var p = this.getUndistortedParams_();
|
|
|
|
return {
|
|
leftDegrees: MathUtil.radToDeg * Math.atan(p.outerDist),
|
|
rightDegrees: MathUtil.radToDeg * Math.atan(p.innerDist),
|
|
downDegrees: MathUtil.radToDeg * Math.atan(p.bottomDist),
|
|
upDegrees: MathUtil.radToDeg * Math.atan(p.topDist)
|
|
};
|
|
};
|
|
|
|
DeviceInfo.prototype.getUndistortedViewportLeftEye = function() {
|
|
var p = this.getUndistortedParams_();
|
|
var viewer = this.viewer;
|
|
var device = this.device;
|
|
|
|
// Distances stored in local variables are in tan-angle units unless otherwise
|
|
// noted.
|
|
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;
|
|
|
|
// Most of these variables in tan-angle units.
|
|
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(MathUtil.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) {
|
|
// A machine readable ID.
|
|
this.id = params.id;
|
|
// A human readable label.
|
|
this.label = params.label;
|
|
|
|
// Field of view in degrees (per side).
|
|
this.fov = params.fov;
|
|
|
|
// Distance between lens centers in meters.
|
|
this.interLensDistance = params.interLensDistance;
|
|
// Distance between viewer baseline and lens center in meters.
|
|
this.baselineLensDistance = params.baselineLensDistance;
|
|
// Screen-to-lens distance in meters.
|
|
this.screenLensDistance = params.screenLensDistance;
|
|
|
|
// Distortion coefficients.
|
|
this.distortionCoefficients = params.distortionCoefficients;
|
|
// Inverse distortion coefficients.
|
|
// TODO: Calculate these from distortionCoefficients in the future.
|
|
this.inverseCoefficients = params.inverseCoefficients;
|
|
}
|
|
|
|
// Export viewer information.
|
|
DeviceInfo.Viewers = Viewers;
|
|
module.exports = DeviceInfo;
|
|
|
|
},{"./distortion/distortion.js":16,"./math-util.js":20,"./util.js":29}],15:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
var VRDisplay = _dereq_('./base.js').VRDisplay;
|
|
var HMDVRDevice = _dereq_('./base.js').HMDVRDevice;
|
|
var PositionSensorVRDevice = _dereq_('./base.js').PositionSensorVRDevice;
|
|
|
|
/**
|
|
* Wraps a VRDisplay and exposes it as a HMDVRDevice
|
|
*/
|
|
function VRDisplayHMDDevice(display) {
|
|
this.display = display;
|
|
|
|
this.hardwareUnitId = display.displayId;
|
|
this.deviceId = 'webvr-polyfill:HMD:' + display.displayId;
|
|
this.deviceName = display.displayName + ' (HMD)';
|
|
}
|
|
VRDisplayHMDDevice.prototype = new HMDVRDevice();
|
|
|
|
VRDisplayHMDDevice.prototype.getEyeParameters = function(whichEye) {
|
|
var eyeParameters = this.display.getEyeParameters(whichEye);
|
|
|
|
return {
|
|
currentFieldOfView: eyeParameters.fieldOfView,
|
|
maximumFieldOfView: eyeParameters.fieldOfView,
|
|
minimumFieldOfView: eyeParameters.fieldOfView,
|
|
recommendedFieldOfView: eyeParameters.fieldOfView,
|
|
eyeTranslation: { x: eyeParameters.offset[0], y: eyeParameters.offset[1], z: eyeParameters.offset[2] },
|
|
renderRect: {
|
|
x: (whichEye == 'right') ? eyeParameters.renderWidth : 0,
|
|
y: 0,
|
|
width: eyeParameters.renderWidth,
|
|
height: eyeParameters.renderHeight
|
|
}
|
|
};
|
|
};
|
|
|
|
VRDisplayHMDDevice.prototype.setFieldOfView =
|
|
function(opt_fovLeft, opt_fovRight, opt_zNear, opt_zFar) {
|
|
// Not supported. getEyeParameters reports that the min, max, and recommended
|
|
// FoV is all the same, so no adjustment can be made.
|
|
};
|
|
|
|
// TODO: Need to hook requestFullscreen to see if a wrapped VRDisplay was passed
|
|
// in as an option. If so we should prevent the default fullscreen behavior and
|
|
// call VRDisplay.requestPresent instead.
|
|
|
|
/**
|
|
* Wraps a VRDisplay and exposes it as a PositionSensorVRDevice
|
|
*/
|
|
function VRDisplayPositionSensorDevice(display) {
|
|
this.display = display;
|
|
|
|
this.hardwareUnitId = display.displayId;
|
|
this.deviceId = 'webvr-polyfill:PositionSensor: ' + display.displayId;
|
|
this.deviceName = display.displayName + ' (PositionSensor)';
|
|
}
|
|
VRDisplayPositionSensorDevice.prototype = new PositionSensorVRDevice();
|
|
|
|
VRDisplayPositionSensorDevice.prototype.getState = function() {
|
|
var pose = this.display.getPose();
|
|
return {
|
|
position: pose.position ? { x: pose.position[0], y: pose.position[1], z: pose.position[2] } : null,
|
|
orientation: pose.orientation ? { x: pose.orientation[0], y: pose.orientation[1], z: pose.orientation[2], w: pose.orientation[3] } : null,
|
|
linearVelocity: null,
|
|
linearAcceleration: null,
|
|
angularVelocity: null,
|
|
angularAcceleration: null
|
|
};
|
|
};
|
|
|
|
VRDisplayPositionSensorDevice.prototype.resetState = function() {
|
|
return this.positionDevice.resetPose();
|
|
};
|
|
|
|
|
|
module.exports.VRDisplayHMDDevice = VRDisplayHMDDevice;
|
|
module.exports.VRDisplayPositionSensorDevice = VRDisplayPositionSensorDevice;
|
|
|
|
|
|
},{"./base.js":9}],16:[function(_dereq_,module,exports){
|
|
/**
|
|
* TODO(smus): Implement coefficient inversion.
|
|
*/
|
|
function Distortion(coefficients) {
|
|
this.coefficients = coefficients;
|
|
}
|
|
|
|
/**
|
|
* Calculates the inverse distortion for a radius.
|
|
* </p><p>
|
|
* Allows to compute the original undistorted radius from a distorted one.
|
|
* See also getApproximateInverseDistortion() for a faster but potentially
|
|
* less accurate method.
|
|
*
|
|
* @param {Number} radius Distorted radius from the lens center in tan-angle units.
|
|
* @return {Number} The undistorted radius in tan-angle units.
|
|
*/
|
|
Distortion.prototype.distortInverse = function(radius) {
|
|
// Secant method.
|
|
var r0 = 0;
|
|
var r1 = 1;
|
|
var dr0 = radius - this.distort(r0);
|
|
while (Math.abs(r1 - r0) > 0.0001 /** 0.1mm */) {
|
|
var dr1 = radius - this.distort(r1);
|
|
var r2 = r1 - dr1 * ((r1 - r0) / (dr1 - dr0));
|
|
r0 = r1;
|
|
r1 = r2;
|
|
dr0 = dr1;
|
|
}
|
|
return r1;
|
|
};
|
|
|
|
/**
|
|
* Distorts a radius by its distortion factor from the center of the lenses.
|
|
*
|
|
* @param {Number} radius Radius from the lens center in tan-angle units.
|
|
* @return {Number} The distorted radius in tan-angle units.
|
|
*/
|
|
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;
|
|
};
|
|
|
|
module.exports = Distortion;
|
|
|
|
},{}],17:[function(_dereq_,module,exports){
|
|
module.exports={
|
|
"format": 1,
|
|
"last_updated": "2017-08-27T14:39:31Z",
|
|
"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/*/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": "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-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": "ZTE/*/ZTE Blade L2/*"
|
|
},
|
|
{
|
|
"ua": "ZTE Blade L2"
|
|
}
|
|
],
|
|
"dpi": 240,
|
|
"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
|
|
}
|
|
]
|
|
}
|
|
},{}],18:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
// Offline cache of the DPDB, to be used until we load the online one (and
|
|
// as a fallback in case we can't load the online one).
|
|
var DPDB_CACHE = _dereq_('./dpdb.json');
|
|
var Util = _dereq_('../util.js');
|
|
|
|
// Online DPDB URL.
|
|
var ONLINE_DPDB_URL =
|
|
'https://dpdb.webvr.rocks/dpdb.json';
|
|
|
|
/**
|
|
* Calculates device parameters based on the DPDB (Device Parameter Database).
|
|
* Initially, uses the cached DPDB values.
|
|
*
|
|
* If fetchOnline == true, then this object tries to fetch the online version
|
|
* of the DPDB and updates the device info if a better match is found.
|
|
* Calls the onDeviceParamsUpdated callback when there is an update to the
|
|
* device information.
|
|
*/
|
|
function Dpdb(fetchOnline, onDeviceParamsUpdated) {
|
|
// Start with the offline DPDB cache while we are loading the real one.
|
|
this.dpdb = DPDB_CACHE;
|
|
|
|
// Calculate device params based on the offline version of the DPDB.
|
|
this.recalculateDeviceParams_();
|
|
|
|
// XHR to fetch online DPDB file, if requested.
|
|
if (fetchOnline) {
|
|
// Set the callback.
|
|
this.onDeviceParamsUpdated = onDeviceParamsUpdated;
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
var obj = this;
|
|
xhr.open('GET', ONLINE_DPDB_URL, true);
|
|
xhr.addEventListener('load', function() {
|
|
obj.loading = false;
|
|
if (xhr.status >= 200 && xhr.status <= 299) {
|
|
// Success.
|
|
obj.dpdb = JSON.parse(xhr.response);
|
|
obj.recalculateDeviceParams_();
|
|
} else {
|
|
// Error loading the DPDB.
|
|
console.error('Error loading online DPDB!');
|
|
}
|
|
});
|
|
xhr.send();
|
|
}
|
|
}
|
|
|
|
// Returns the current device parameters.
|
|
Dpdb.prototype.getDeviceParams = function() {
|
|
return this.deviceParams;
|
|
};
|
|
|
|
// Recalculates this device's parameters based on the DPDB.
|
|
Dpdb.prototype.recalculateDeviceParams_ = function() {
|
|
var newDeviceParams = this.calcDeviceParams_();
|
|
if (newDeviceParams) {
|
|
this.deviceParams = newDeviceParams;
|
|
// Invoke callback, if it is set.
|
|
if (this.onDeviceParamsUpdated) {
|
|
this.onDeviceParamsUpdated(this.deviceParams);
|
|
}
|
|
} else {
|
|
console.error('Failed to recalculate device parameters.');
|
|
}
|
|
};
|
|
|
|
// Returns a DeviceParams object that represents the best guess as to this
|
|
// device's parameters. Can return null if the device does not match any
|
|
// known devices.
|
|
Dpdb.prototype.calcDeviceParams_ = function() {
|
|
var db = this.dpdb; // shorthand
|
|
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;
|
|
}
|
|
|
|
// Get the actual user agent and screen dimensions in pixels.
|
|
var userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
|
var width = Util.getScreenWidth();
|
|
var height = Util.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;
|
|
}
|
|
|
|
// See if this device is of the appropriate type.
|
|
if (Util.isIOS() != (device.type == 'ios')) continue;
|
|
|
|
// See if this device matches any of the rules:
|
|
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;
|
|
|
|
// device.dpi might be an array of [ xdpi, ydpi] or just a scalar.
|
|
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) {
|
|
// We can only match 'ua' and 'res' rules, not other types like 'mdmh'
|
|
// (which are meant for native platforms).
|
|
if (!rule.ua && !rule.res) return false;
|
|
|
|
// If our user agent string doesn't contain the indicated user agent string,
|
|
// the match fails.
|
|
if (rule.ua && ua.indexOf(rule.ua) < 0) return false;
|
|
|
|
// If the rule specifies screen dimensions that don't correspond to ours,
|
|
// the match fails.
|
|
if (rule.res) {
|
|
if (!rule.res[0] || !rule.res[1]) return false;
|
|
var resX = rule.res[0];
|
|
var resY = rule.res[1];
|
|
// Compare min and max so as to make the order not matter, i.e., it should
|
|
// be true that 640x480 == 480x640.
|
|
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;
|
|
}
|
|
|
|
module.exports = Dpdb;
|
|
|
|
},{"../util.js":29,"./dpdb.json":17}],19:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
var Util = _dereq_('./util.js');
|
|
var WebVRPolyfill = _dereq_('./webvr-polyfill.js').WebVRPolyfill;
|
|
|
|
// Initialize a WebVRConfig just in case.
|
|
window.WebVRConfig = Util.extend({
|
|
// Forces availability of VR mode, even for non-mobile devices.
|
|
FORCE_ENABLE_VR: false,
|
|
|
|
// Complementary filter coefficient. 0 for accelerometer, 1 for gyro.
|
|
K_FILTER: 0.98,
|
|
|
|
// How far into the future to predict during fast motion (in seconds).
|
|
PREDICTION_TIME_S: 0.040,
|
|
|
|
// Flag to enable touch panner. In case you have your own touch controls.
|
|
TOUCH_PANNER_DISABLED: true,
|
|
|
|
// Flag to disabled the UI in VR Mode.
|
|
CARDBOARD_UI_DISABLED: false, // Default: false
|
|
|
|
// Flag to disable the instructions to rotate your device.
|
|
ROTATE_INSTRUCTIONS_DISABLED: false, // Default: false.
|
|
|
|
// Enable yaw panning only, disabling roll and pitch. This can be useful
|
|
// for panoramas with nothing interesting above or below.
|
|
YAW_ONLY: false,
|
|
|
|
// To disable keyboard and mouse controls, if you want to use your own
|
|
// implementation.
|
|
MOUSE_KEYBOARD_CONTROLS_DISABLED: false,
|
|
|
|
// Prevent the polyfill from initializing immediately. Requires the app
|
|
// to call InitializeWebVRPolyfill() before it can be used.
|
|
DEFER_INITIALIZATION: false,
|
|
|
|
// Enable the deprecated version of the API (navigator.getVRDevices).
|
|
ENABLE_DEPRECATED_API: false,
|
|
|
|
// Scales the recommended buffer size reported by WebVR, which can improve
|
|
// performance.
|
|
// UPDATE(2016-05-03): Setting this to 0.5 by default since 1.0 does not
|
|
// perform well on many mobile devices.
|
|
BUFFER_SCALE: 0.5,
|
|
|
|
// Allow VRDisplay.submitFrame to change gl bindings, which is more
|
|
// efficient if the application code will re-bind its resources on the
|
|
// next frame anyway. This has been seen to cause rendering glitches with
|
|
// THREE.js.
|
|
// Dirty bindings include: gl.FRAMEBUFFER_BINDING, gl.CURRENT_PROGRAM,
|
|
// gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING,
|
|
// and gl.TEXTURE_BINDING_2D for texture unit 0.
|
|
DIRTY_SUBMIT_FRAME_BINDINGS: false,
|
|
|
|
// When set to true, this will cause a polyfilled VRDisplay to always be
|
|
// appended to the list returned by navigator.getVRDisplays(), even if that
|
|
// list includes a native VRDisplay.
|
|
ALWAYS_APPEND_POLYFILL_DISPLAY: false,
|
|
|
|
// There are versions of Chrome (M58-M60?) where the native WebVR API exists,
|
|
// and instead of returning 0 VR displays when none are detected,
|
|
// `navigator.getVRDisplays()`'s promise never resolves. This results
|
|
// in the polyfill hanging and not being able to provide fallback
|
|
// displays, so set a timeout in milliseconds to stop waiting for a response
|
|
// and just use polyfilled displays.
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=727969
|
|
GET_VR_DISPLAYS_TIMEOUT: 1000,
|
|
}, window.WebVRConfig);
|
|
|
|
if (!window.WebVRConfig.DEFER_INITIALIZATION) {
|
|
new WebVRPolyfill();
|
|
} else {
|
|
window.InitializeWebVRPolyfill = function() {
|
|
new WebVRPolyfill();
|
|
}
|
|
}
|
|
|
|
window.WebVRPolyfill = WebVRPolyfill;
|
|
|
|
},{"./util.js":29,"./webvr-polyfill.js":32}],20:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var MathUtil = window.MathUtil || {};
|
|
|
|
MathUtil.degToRad = Math.PI / 180;
|
|
MathUtil.radToDeg = 180 / Math.PI;
|
|
|
|
// Some minimal math functionality borrowed from THREE.Math and stripped down
|
|
// for the purposes of this library.
|
|
|
|
|
|
MathUtil.Vector2 = function ( x, y ) {
|
|
this.x = x || 0;
|
|
this.y = y || 0;
|
|
};
|
|
|
|
MathUtil.Vector2.prototype = {
|
|
constructor: MathUtil.Vector2,
|
|
|
|
set: function ( x, y ) {
|
|
this.x = x;
|
|
this.y = y;
|
|
|
|
return this;
|
|
},
|
|
|
|
copy: function ( v ) {
|
|
this.x = v.x;
|
|
this.y = v.y;
|
|
|
|
return this;
|
|
},
|
|
|
|
subVectors: function ( a, b ) {
|
|
this.x = a.x - b.x;
|
|
this.y = a.y - b.y;
|
|
|
|
return this;
|
|
},
|
|
};
|
|
|
|
MathUtil.Vector3 = function ( x, y, z ) {
|
|
this.x = x || 0;
|
|
this.y = y || 0;
|
|
this.z = z || 0;
|
|
};
|
|
|
|
MathUtil.Vector3.prototype = {
|
|
constructor: MathUtil.Vector3,
|
|
|
|
set: function ( x, y, z ) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z;
|
|
|
|
return this;
|
|
},
|
|
|
|
copy: function ( v ) {
|
|
this.x = v.x;
|
|
this.y = v.y;
|
|
this.z = v.z;
|
|
|
|
return this;
|
|
},
|
|
|
|
length: function () {
|
|
return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
|
|
},
|
|
|
|
normalize: function () {
|
|
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 ( scalar ) {
|
|
this.x *= scalar;
|
|
this.y *= scalar;
|
|
this.z *= scalar;
|
|
},
|
|
|
|
applyQuaternion: function ( 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;
|
|
|
|
// calculate quat * vector
|
|
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;
|
|
|
|
// calculate result * inverse quat
|
|
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 ( v ) {
|
|
return this.x * v.x + this.y * v.y + this.z * v.z;
|
|
},
|
|
|
|
crossVectors: function ( 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;
|
|
},
|
|
};
|
|
|
|
MathUtil.Quaternion = function ( x, y, z, w ) {
|
|
this.x = x || 0;
|
|
this.y = y || 0;
|
|
this.z = z || 0;
|
|
this.w = ( w !== undefined ) ? w : 1;
|
|
};
|
|
|
|
MathUtil.Quaternion.prototype = {
|
|
constructor: MathUtil.Quaternion,
|
|
|
|
set: function ( x, y, z, w ) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z;
|
|
this.w = w;
|
|
|
|
return this;
|
|
},
|
|
|
|
copy: function ( quaternion ) {
|
|
this.x = quaternion.x;
|
|
this.y = quaternion.y;
|
|
this.z = quaternion.z;
|
|
this.w = quaternion.w;
|
|
|
|
return this;
|
|
},
|
|
|
|
setFromEulerXYZ: function( 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( 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 ( axis, angle ) {
|
|
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
|
|
// assumes axis is normalized
|
|
|
|
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 ( q ) {
|
|
return this.multiplyQuaternions( this, q );
|
|
},
|
|
|
|
multiplyQuaternions: function ( a, b ) {
|
|
// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
|
|
|
|
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 () {
|
|
this.x *= -1;
|
|
this.y *= -1;
|
|
this.z *= -1;
|
|
|
|
this.normalize();
|
|
|
|
return this;
|
|
},
|
|
|
|
normalize: function () {
|
|
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 ( 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;
|
|
|
|
// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
|
|
|
|
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 () {
|
|
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
|
|
// assumes direction vectors vFrom and vTo are normalized
|
|
|
|
var v1, r;
|
|
var EPS = 0.000001;
|
|
|
|
return function ( vFrom, vTo ) {
|
|
if ( v1 === undefined ) v1 = new MathUtil.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;
|
|
}
|
|
}(),
|
|
};
|
|
|
|
module.exports = MathUtil;
|
|
|
|
},{}],21:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var VRDisplay = _dereq_('./base.js').VRDisplay;
|
|
var MathUtil = _dereq_('./math-util.js');
|
|
var Util = _dereq_('./util.js');
|
|
|
|
// How much to rotate per key stroke.
|
|
var KEY_SPEED = 0.15;
|
|
var KEY_ANIMATION_DURATION = 80;
|
|
|
|
// How much to rotate for mouse events.
|
|
var MOUSE_SPEED_X = 0.5;
|
|
var MOUSE_SPEED_Y = 0.3;
|
|
|
|
/**
|
|
* VRDisplay based on mouse and keyboard input. Designed for desktops/laptops
|
|
* where orientation events aren't supported. Cannot present.
|
|
*/
|
|
function MouseKeyboardVRDisplay() {
|
|
this.displayName = 'Mouse and Keyboard VRDisplay (webvr-polyfill)';
|
|
|
|
this.capabilities.hasOrientation = true;
|
|
|
|
// Attach to mouse and keyboard events.
|
|
window.addEventListener('keydown', this.onKeyDown_.bind(this));
|
|
window.addEventListener('mousemove', this.onMouseMove_.bind(this));
|
|
window.addEventListener('mousedown', this.onMouseDown_.bind(this));
|
|
window.addEventListener('mouseup', this.onMouseUp_.bind(this));
|
|
|
|
// "Private" members.
|
|
this.phi_ = 0;
|
|
this.theta_ = 0;
|
|
|
|
// Variables for keyboard-based rotation animation.
|
|
this.targetAngle_ = null;
|
|
this.angleAnimation_ = null;
|
|
|
|
// State variables for calculations.
|
|
this.orientation_ = new MathUtil.Quaternion();
|
|
|
|
// Variables for mouse-based rotation.
|
|
this.rotateStart_ = new MathUtil.Vector2();
|
|
this.rotateEnd_ = new MathUtil.Vector2();
|
|
this.rotateDelta_ = new MathUtil.Vector2();
|
|
this.isDragging_ = false;
|
|
|
|
this.orientationOut_ = new Float32Array(4);
|
|
}
|
|
MouseKeyboardVRDisplay.prototype = new VRDisplay();
|
|
|
|
MouseKeyboardVRDisplay.prototype.getImmediatePose = function() {
|
|
this.orientation_.setFromEulerYXZ(this.phi_, this.theta_, 0);
|
|
|
|
this.orientationOut_[0] = this.orientation_.x;
|
|
this.orientationOut_[1] = this.orientation_.y;
|
|
this.orientationOut_[2] = this.orientation_.z;
|
|
this.orientationOut_[3] = this.orientation_.w;
|
|
|
|
return {
|
|
position: null,
|
|
orientation: this.orientationOut_,
|
|
linearVelocity: null,
|
|
linearAcceleration: null,
|
|
angularVelocity: null,
|
|
angularAcceleration: null
|
|
};
|
|
};
|
|
|
|
MouseKeyboardVRDisplay.prototype.onKeyDown_ = function(e) {
|
|
// Track WASD and arrow keys.
|
|
if (e.keyCode == 38) { // Up key.
|
|
this.animatePhi_(this.phi_ + KEY_SPEED);
|
|
} else if (e.keyCode == 39) { // Right key.
|
|
this.animateTheta_(this.theta_ - KEY_SPEED);
|
|
} else if (e.keyCode == 40) { // Down key.
|
|
this.animatePhi_(this.phi_ - KEY_SPEED);
|
|
} else if (e.keyCode == 37) { // Left key.
|
|
this.animateTheta_(this.theta_ + KEY_SPEED);
|
|
}
|
|
};
|
|
|
|
MouseKeyboardVRDisplay.prototype.animateTheta_ = function(targetAngle) {
|
|
this.animateKeyTransitions_('theta_', targetAngle);
|
|
};
|
|
|
|
MouseKeyboardVRDisplay.prototype.animatePhi_ = function(targetAngle) {
|
|
// Prevent looking too far up or down.
|
|
targetAngle = Util.clamp(targetAngle, -Math.PI/2, Math.PI/2);
|
|
this.animateKeyTransitions_('phi_', targetAngle);
|
|
};
|
|
|
|
/**
|
|
* Start an animation to transition an angle from one value to another.
|
|
*/
|
|
MouseKeyboardVRDisplay.prototype.animateKeyTransitions_ = function(angleName, targetAngle) {
|
|
// If an animation is currently running, cancel it.
|
|
if (this.angleAnimation_) {
|
|
cancelAnimationFrame(this.angleAnimation_);
|
|
}
|
|
var startAngle = this[angleName];
|
|
var startTime = new Date();
|
|
// Set up an interval timer to perform the animation.
|
|
this.angleAnimation_ = requestAnimationFrame(function animate() {
|
|
// Once we're finished the animation, we're done.
|
|
var elapsed = new Date() - startTime;
|
|
if (elapsed >= KEY_ANIMATION_DURATION) {
|
|
this[angleName] = targetAngle;
|
|
cancelAnimationFrame(this.angleAnimation_);
|
|
return;
|
|
}
|
|
// loop with requestAnimationFrame
|
|
this.angleAnimation_ = requestAnimationFrame(animate.bind(this))
|
|
// Linearly interpolate the angle some amount.
|
|
var percent = elapsed / KEY_ANIMATION_DURATION;
|
|
this[angleName] = startAngle + (targetAngle - startAngle) * percent;
|
|
}.bind(this));
|
|
};
|
|
|
|
MouseKeyboardVRDisplay.prototype.onMouseDown_ = function(e) {
|
|
this.rotateStart_.set(e.clientX, e.clientY);
|
|
this.isDragging_ = true;
|
|
};
|
|
|
|
// Very similar to https://gist.github.com/mrflix/8351020
|
|
MouseKeyboardVRDisplay.prototype.onMouseMove_ = function(e) {
|
|
if (!this.isDragging_ && !this.isPointerLocked_()) {
|
|
return;
|
|
}
|
|
// Support pointer lock API.
|
|
if (this.isPointerLocked_()) {
|
|
var movementX = e.movementX || e.mozMovementX || 0;
|
|
var movementY = e.movementY || e.mozMovementY || 0;
|
|
this.rotateEnd_.set(this.rotateStart_.x - movementX, this.rotateStart_.y - movementY);
|
|
} else {
|
|
this.rotateEnd_.set(e.clientX, e.clientY);
|
|
}
|
|
// Calculate how much we moved in mouse space.
|
|
this.rotateDelta_.subVectors(this.rotateEnd_, this.rotateStart_);
|
|
this.rotateStart_.copy(this.rotateEnd_);
|
|
|
|
// Keep track of the cumulative euler angles.
|
|
this.phi_ += 2 * Math.PI * this.rotateDelta_.y / screen.height * MOUSE_SPEED_Y;
|
|
this.theta_ += 2 * Math.PI * this.rotateDelta_.x / screen.width * MOUSE_SPEED_X;
|
|
|
|
// Prevent looking too far up or down.
|
|
this.phi_ = Util.clamp(this.phi_, -Math.PI/2, Math.PI/2);
|
|
};
|
|
|
|
MouseKeyboardVRDisplay.prototype.onMouseUp_ = function(e) {
|
|
this.isDragging_ = false;
|
|
};
|
|
|
|
MouseKeyboardVRDisplay.prototype.isPointerLocked_ = function() {
|
|
var el = document.pointerLockElement || document.mozPointerLockElement ||
|
|
document.webkitPointerLockElement;
|
|
return el !== undefined;
|
|
};
|
|
|
|
MouseKeyboardVRDisplay.prototype.resetPose = function() {
|
|
this.phi_ = 0;
|
|
this.theta_ = 0;
|
|
};
|
|
|
|
module.exports = MouseKeyboardVRDisplay;
|
|
|
|
},{"./base.js":9,"./math-util.js":20,"./util.js":29}],22:[function(_dereq_,module,exports){
|
|
(function (global){
|
|
// This is the entry point if requiring/importing via node, or
|
|
// a build tool that uses package.json entry (like browserify, webpack).
|
|
// If running in node with a window mock available, globalize its members
|
|
// if needed. Otherwise, just continue to `./main`
|
|
if (typeof global !== 'undefined' && global.window) {
|
|
global.document = global.window.document;
|
|
global.navigator = global.window.navigator;
|
|
}
|
|
|
|
_dereq_('./main');
|
|
|
|
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
},{"./main":19}],23:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Util = _dereq_('./util.js');
|
|
|
|
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';
|
|
// Force this to be above the fullscreen canvas, which is at zIndex: 999999.
|
|
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 (Util.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();
|
|
// In portrait VR mode, tell the user to rotate to landscape. Otherwise, hide
|
|
// the instructions.
|
|
if (!Util.isLandscapeMode() && Util.isMobile()) {
|
|
this.show();
|
|
} else {
|
|
this.hide();
|
|
}
|
|
};
|
|
|
|
RotateInstructions.prototype.loadIcon_ = function() {
|
|
// Encoded asset_src/rotate-instructions.svg
|
|
this.icon = Util.base64('image/svg+xml', 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjE5OHB4IiBoZWlnaHQ9IjI0MHB4IiB2aWV3Qm94PSIwIDAgMTk4IDI0MCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpza2V0Y2g9Imh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaC9ucyI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDMuMy4zICgxMjA4MSkgLSBodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2ggLS0+CiAgICA8dGl0bGU+dHJhbnNpdGlvbjwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxkZWZzPjwvZGVmcz4KICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHNrZXRjaDp0eXBlPSJNU1BhZ2UiPgogICAgICAgIDxnIGlkPSJ0cmFuc2l0aW9uIiBza2V0Y2g6dHlwZT0iTVNBcnRib2FyZEdyb3VwIj4KICAgICAgICAgICAgPGcgaWQ9IkltcG9ydGVkLUxheWVycy1Db3B5LTQtKy1JbXBvcnRlZC1MYXllcnMtQ29weS0rLUltcG9ydGVkLUxheWVycy1Db3B5LTItQ29weSIgc2tldGNoOnR5cGU9Ik1TTGF5ZXJHcm91cCI+CiAgICAgICAgICAgICAgICA8ZyBpZD0iSW1wb3J0ZWQtTGF5ZXJzLUNvcHktNCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC4wMDAwMDAsIDEwNy4wMDAwMDApIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ5LjYyNSwyLjUyNyBDMTQ5LjYyNSwyLjUyNyAxNTUuODA1LDYuMDk2IDE1Ni4zNjIsNi40MTggTDE1Ni4zNjIsNy4zMDQgQzE1Ni4zNjIsNy40ODEgMTU2LjM3NSw3LjY2NCAxNTYuNCw3Ljg1MyBDMTU2LjQxLDcuOTM0IDE1Ni40Miw4LjAxNSAxNTYuNDI3LDguMDk1IEMxNTYuNTY3LDkuNTEgMTU3LjQwMSwxMS4wOTMgMTU4LjUzMiwxMi4wOTQgTDE2NC4yNTIsMTcuMTU2IEwxNjQuMzMzLDE3LjA2NiBDMTY0LjMzMywxNy4wNjYgMTY4LjcxNSwxNC41MzYgMTY5LjU2OCwxNC4wNDIgQzE3MS4wMjUsMTQuODgzIDE5NS41MzgsMjkuMDM1IDE5NS41MzgsMjkuMDM1IEwxOTUuNTM4LDgzLjAzNiBDMTk1LjUzOCw4My44MDcgMTk1LjE1Miw4NC4yNTMgMTk0LjU5LDg0LjI1MyBDMTk0LjM1Nyw4NC4yNTMgMTk0LjA5NSw4NC4xNzcgMTkzLjgxOCw4NC4wMTcgTDE2OS44NTEsNzAuMTc5IEwxNjkuODM3LDcwLjIwMyBMMTQyLjUxNSw4NS45NzggTDE0MS42NjUsODQuNjU1IEMxMzYuOTM0LDgzLjEyNiAxMzEuOTE3LDgxLjkxNSAxMjYuNzE0LDgxLjA0NSBDMTI2LjcwOSw4MS4wNiAxMjYuNzA3LDgxLjA2OSAxMjYuNzA3LDgxLjA2OSBMMTIxLjY0LDk4LjAzIEwxMTMuNzQ5LDEwMi41ODYgTDExMy43MTIsMTAyLjUyMyBMMTEzLjcxMiwxMzAuMTEzIEMxMTMuNzEyLDEzMC44ODUgMTEzLjMyNiwxMzEuMzMgMTEyLjc2NCwxMzEuMzMgQzExMi41MzIsMTMxLjMzIDExMi4yNjksMTMxLjI1NCAxMTEuOTkyLDEzMS4wOTQgTDY5LjUxOSwxMDYuNTcyIEM2OC41NjksMTA2LjAyMyA2Ny43OTksMTA0LjY5NSA2Ny43OTksMTAzLjYwNSBMNjcuNzk5LDEwMi41NyBMNjcuNzc4LDEwMi42MTcgQzY3LjI3LDEwMi4zOTMgNjYuNjQ4LDEwMi4yNDkgNjUuOTYyLDEwMi4yMTggQzY1Ljg3NSwxMDIuMjE0IDY1Ljc4OCwxMDIuMjEyIDY1LjcwMSwxMDIuMjEyIEM2NS42MDYsMTAyLjIxMiA2NS41MTEsMTAyLjIxNSA2NS40MTYsMTAyLjIxOSBDNjUuMTk1LDEwMi4yMjkgNjQuOTc0LDEwMi4yMzUgNjQuNzU0LDEwMi4yMzUgQzY0LjMzMSwxMDIuMjM1IDYzLjkxMSwxMDIuMjE2IDYzLjQ5OCwxMDIuMTc4IEM2MS44NDMsMTAyLjAyNSA2MC4yOTgsMTAxLjU3OCA1OS4wOTQsMTAwLjg4MiBMMTIuNTE4LDczLjk5MiBMMTIuNTIzLDc0LjAwNCBMMi4yNDUsNTUuMjU0IEMxLjI0NCw1My40MjcgMi4wMDQsNTEuMDM4IDMuOTQzLDQ5LjkxOCBMNTkuOTU0LDE3LjU3MyBDNjAuNjI2LDE3LjE4NSA2MS4zNSwxNy4wMDEgNjIuMDUzLDE3LjAwMSBDNjMuMzc5LDE3LjAwMSA2NC42MjUsMTcuNjYgNjUuMjgsMTguODU0IEw2NS4yODUsMTguODUxIEw2NS41MTIsMTkuMjY0IEw2NS41MDYsMTkuMjY4IEM2NS45MDksMjAuMDAzIDY2LjQwNSwyMC42OCA2Ni45ODMsMjEuMjg2IEw2Ny4yNiwyMS41NTYgQzY5LjE3NCwyMy40MDYgNzEuNzI4LDI0LjM1NyA3NC4zNzMsMjQuMzU3IEM3Ni4zMjIsMjQuMzU3IDc4LjMyMSwyMy44NCA4MC4xNDgsMjIuNzg1IEM4MC4xNjEsMjIuNzg1IDg3LjQ2NywxOC41NjYgODcuNDY3LDE4LjU2NiBDODguMTM5LDE4LjE3OCA4OC44NjMsMTcuOTk0IDg5LjU2NiwxNy45OTQgQzkwLjg5MiwxNy45OTQgOTIuMTM4LDE4LjY1MiA5Mi43OTIsMTkuODQ3IEw5Ni4wNDIsMjUuNzc1IEw5Ni4wNjQsMjUuNzU3IEwxMDIuODQ5LDI5LjY3NCBMMTAyLjc0NCwyOS40OTIgTDE0OS42MjUsMi41MjcgTTE0OS42MjUsMC44OTIgQzE0OS4zNDMsMC44OTIgMTQ5LjA2MiwwLjk2NSAxNDguODEsMS4xMSBMMTAyLjY0MSwyNy42NjYgTDk3LjIzMSwyNC41NDIgTDk0LjIyNiwxOS4wNjEgQzkzLjMxMywxNy4zOTQgOTEuNTI3LDE2LjM1OSA4OS41NjYsMTYuMzU4IEM4OC41NTUsMTYuMzU4IDg3LjU0NiwxNi42MzIgODYuNjQ5LDE3LjE1IEM4My44NzgsMTguNzUgNzkuNjg3LDIxLjE2OSA3OS4zNzQsMjEuMzQ1IEM3OS4zNTksMjEuMzUzIDc5LjM0NSwyMS4zNjEgNzkuMzMsMjEuMzY5IEM3Ny43OTgsMjIuMjU0IDc2LjA4NCwyMi43MjIgNzQuMzczLDIyLjcyMiBDNzIuMDgxLDIyLjcyMiA2OS45NTksMjEuODkgNjguMzk3LDIwLjM4IEw2OC4xNDUsMjAuMTM1IEM2Ny43MDYsMTkuNjcyIDY3LjMyMywxOS4xNTYgNjcuMDA2LDE4LjYwMSBDNjYuOTg4LDE4LjU1OSA2Ni45NjgsMTguNTE5IDY2Ljk0NiwxOC40NzkgTDY2LjcxOSwxOC4wNjUgQzY2LjY5LDE4LjAxMiA2Ni42NTgsMTcuOTYgNjYuNjI0LDE3LjkxMSBDNjUuNjg2LDE2LjMzNyA2My45NTEsMTUuMzY2IDYyLjA1MywxNS4zNjYgQzYxLjA0MiwxNS4zNjYgNjAuMDMzLDE1LjY0IDU5LjEzNiwxNi4xNTggTDMuMTI1LDQ4LjUwMiBDMC40MjYsNTAuMDYxIC0wLjYxMyw1My40NDIgMC44MTEsNTYuMDQgTDExLjA4OSw3NC43OSBDMTEuMjY2LDc1LjExMyAxMS41MzcsNzUuMzUzIDExLjg1LDc1LjQ5NCBMNTguMjc2LDEwMi4yOTggQzU5LjY3OSwxMDMuMTA4IDYxLjQzMywxMDMuNjMgNjMuMzQ4LDEwMy44MDYgQzYzLjgxMiwxMDMuODQ4IDY0LjI4NSwxMDMuODcgNjQuNzU0LDEwMy44NyBDNjUsMTAzLjg3IDY1LjI0OSwxMDMuODY0IDY1LjQ5NCwxMDMuODUyIEM2NS41NjMsMTAzLjg0OSA2NS42MzIsMTAzLjg0NyA2NS43MDEsMTAzLjg0NyBDNjUuNzY0LDEwMy44NDcgNjUuODI4LDEwMy44NDkgNjUuODksMTAzLjg1MiBDNjUuOTg2LDEwMy44NTYgNjYuMDgsMTAzLjg2MyA2Ni4xNzMsMTAzLjg3NCBDNjYuMjgyLDEwNS40NjcgNjcuMzMyLDEwNy4xOTcgNjguNzAyLDEwNy45ODggTDExMS4xNzQsMTMyLjUxIEMxMTEuNjk4LDEzMi44MTIgMTEyLjIzMiwxMzIuOTY1IDExMi43NjQsMTMyLjk2NSBDMTE0LjI2MSwxMzIuOTY1IDExNS4zNDcsMTMxLjc2NSAxMTUuMzQ3LDEzMC4xMTMgTDExNS4zNDcsMTAzLjU1MSBMMTIyLjQ1OCw5OS40NDYgQzEyMi44MTksOTkuMjM3IDEyMy4wODcsOTguODk4IDEyMy4yMDcsOTguNDk4IEwxMjcuODY1LDgyLjkwNSBDMTMyLjI3OSw4My43MDIgMTM2LjU1Nyw4NC43NTMgMTQwLjYwNyw4Ni4wMzMgTDE0MS4xNCw4Ni44NjIgQzE0MS40NTEsODcuMzQ2IDE0MS45NzcsODcuNjEzIDE0Mi41MTYsODcuNjEzIEMxNDIuNzk0LDg3LjYxMyAxNDMuMDc2LDg3LjU0MiAxNDMuMzMzLDg3LjM5MyBMMTY5Ljg2NSw3Mi4wNzYgTDE5Myw4NS40MzMgQzE5My41MjMsODUuNzM1IDE5NC4wNTgsODUuODg4IDE5NC41OSw4NS44ODggQzE5Ni4wODcsODUuODg4IDE5Ny4xNzMsODQuNjg5IDE5Ny4xNzMsODMuMDM2IEwxOTcuMTczLDI5LjAzNSBDMTk3LjE3MywyOC40NTEgMTk2Ljg2MSwyNy45MTEgMTk2LjM1NSwyNy42MTkgQzE5Ni4zNTUsMjcuNjE5IDE3MS44NDMsMTMuNDY3IDE3MC4zODUsMTIuNjI2IEMxNzAuMTMyLDEyLjQ4IDE2OS44NSwxMi40MDcgMTY5LjU2OCwxMi40MDcgQzE2OS4yODUsMTIuNDA3IDE2OS4wMDIsMTIuNDgxIDE2OC43NDksMTIuNjI3IEMxNjguMTQzLDEyLjk3OCAxNjUuNzU2LDE0LjM1NyAxNjQuNDI0LDE1LjEyNSBMMTU5LjYxNSwxMC44NyBDMTU4Ljc5NiwxMC4xNDUgMTU4LjE1NCw4LjkzNyAxNTguMDU0LDcuOTM0IEMxNTguMDQ1LDcuODM3IDE1OC4wMzQsNy43MzkgMTU4LjAyMSw3LjY0IEMxNTguMDA1LDcuNTIzIDE1Ny45OTgsNy40MSAxNTcuOTk4LDcuMzA0IEwxNTcuOTk4LDYuNDE4IEMxNTcuOTk4LDUuODM0IDE1Ny42ODYsNS4yOTUgMTU3LjE4MSw1LjAwMiBDMTU2LjYyNCw0LjY4IDE1MC40NDIsMS4xMTEgMTUwLjQ0MiwxLjExMSBDMTUwLjE4OSwwLjk2NSAxNDkuOTA3LDAuODkyIDE0OS42MjUsMC44OTIiIGlkPSJGaWxsLTEiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTYuMDI3LDI1LjYzNiBMMTQyLjYwMyw1Mi41MjcgQzE0My44MDcsNTMuMjIyIDE0NC41ODIsNTQuMTE0IDE0NC44NDUsNTUuMDY4IEwxNDQuODM1LDU1LjA3NSBMNjMuNDYxLDEwMi4wNTcgTDYzLjQ2LDEwMi4wNTcgQzYxLjgwNiwxMDEuOTA1IDYwLjI2MSwxMDEuNDU3IDU5LjA1NywxMDAuNzYyIEwxMi40ODEsNzMuODcxIEw5Ni4wMjcsMjUuNjM2IiBpZD0iRmlsbC0yIiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTYzLjQ2MSwxMDIuMTc0IEM2My40NTMsMTAyLjE3NCA2My40NDYsMTAyLjE3NCA2My40MzksMTAyLjE3MiBDNjEuNzQ2LDEwMi4wMTYgNjAuMjExLDEwMS41NjMgNTguOTk4LDEwMC44NjMgTDEyLjQyMiw3My45NzMgQzEyLjM4Niw3My45NTIgMTIuMzY0LDczLjkxNCAxMi4zNjQsNzMuODcxIEMxMi4zNjQsNzMuODMgMTIuMzg2LDczLjc5MSAxMi40MjIsNzMuNzcgTDk1Ljk2OCwyNS41MzUgQzk2LjAwNCwyNS41MTQgOTYuMDQ5LDI1LjUxNCA5Ni4wODUsMjUuNTM1IEwxNDIuNjYxLDUyLjQyNiBDMTQzLjg4OCw1My4xMzQgMTQ0LjY4Miw1NC4wMzggMTQ0Ljk1Nyw1NS4wMzcgQzE0NC45Nyw1NS4wODMgMTQ0Ljk1Myw1NS4xMzMgMTQ0LjkxNSw1NS4xNjEgQzE0NC45MTEsNTUuMTY1IDE0NC44OTgsNTUuMTc0IDE0NC44OTQsNTUuMTc3IEw2My41MTksMTAyLjE1OCBDNjMuNTAxLDEwMi4xNjkgNjMuNDgxLDEwMi4xNzQgNjMuNDYxLDEwMi4xNzQgTDYzLjQ2MSwxMDIuMTc0IFogTTEyLjcxNCw3My44NzEgTDU5LjExNSwxMDAuNjYxIEM2MC4yOTMsMTAxLjM0MSA2MS43ODYsMTAxLjc4MiA2My40MzUsMTAxLjkzNyBMMTQ0LjcwNyw1NS4wMTUgQzE0NC40MjgsNTQuMTA4IDE0My42ODIsNTMuMjg1IDE0Mi41NDQsNTIuNjI4IEw5Ni4wMjcsMjUuNzcxIEwxMi43MTQsNzMuODcxIEwxMi43MTQsNzMuODcxIFoiIGlkPSJGaWxsLTMiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ4LjMyNyw1OC40NzEgQzE0OC4xNDUsNTguNDggMTQ3Ljk2Miw1OC40OCAxNDcuNzgxLDU4LjQ3MiBDMTQ1Ljg4Nyw1OC4zODkgMTQ0LjQ3OSw1Ny40MzQgMTQ0LjYzNiw1Ni4zNCBDMTQ0LjY4OSw1NS45NjcgMTQ0LjY2NCw1NS41OTcgMTQ0LjU2NCw1NS4yMzUgTDYzLjQ2MSwxMDIuMDU3IEM2NC4wODksMTAyLjExNSA2NC43MzMsMTAyLjEzIDY1LjM3OSwxMDIuMDk5IEM2NS41NjEsMTAyLjA5IDY1Ljc0MywxMDIuMDkgNjUuOTI1LDEwMi4wOTggQzY3LjgxOSwxMDIuMTgxIDY5LjIyNywxMDMuMTM2IDY5LjA3LDEwNC4yMyBMMTQ4LjMyNyw1OC40NzEiIGlkPSJGaWxsLTQiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNjkuMDcsMTA0LjM0NyBDNjkuMDQ4LDEwNC4zNDcgNjkuMDI1LDEwNC4zNCA2OS4wMDUsMTA0LjMyNyBDNjguOTY4LDEwNC4zMDEgNjguOTQ4LDEwNC4yNTcgNjguOTU1LDEwNC4yMTMgQzY5LDEwMy44OTYgNjguODk4LDEwMy41NzYgNjguNjU4LDEwMy4yODggQzY4LjE1MywxMDIuNjc4IDY3LjEwMywxMDIuMjY2IDY1LjkyLDEwMi4yMTQgQzY1Ljc0MiwxMDIuMjA2IDY1LjU2MywxMDIuMjA3IDY1LjM4NSwxMDIuMjE1IEM2NC43NDIsMTAyLjI0NiA2NC4wODcsMTAyLjIzMiA2My40NSwxMDIuMTc0IEM2My4zOTksMTAyLjE2OSA2My4zNTgsMTAyLjEzMiA2My4zNDcsMTAyLjA4MiBDNjMuMzM2LDEwMi4wMzMgNjMuMzU4LDEwMS45ODEgNjMuNDAyLDEwMS45NTYgTDE0NC41MDYsNTUuMTM0IEMxNDQuNTM3LDU1LjExNiAxNDQuNTc1LDU1LjExMyAxNDQuNjA5LDU1LjEyNyBDMTQ0LjY0Miw1NS4xNDEgMTQ0LjY2OCw1NS4xNyAxNDQuNjc3LDU1LjIwNCBDMTQ0Ljc4MSw1NS41ODUgMTQ0LjgwNiw1NS45NzIgMTQ0Ljc1MSw1Ni4zNTcgQzE0NC43MDYsNTYuNjczIDE0NC44MDgsNTYuOTk0IDE0NS4wNDcsNTcuMjgyIEMxNDUuNTUzLDU3Ljg5MiAxNDYuNjAyLDU4LjMwMyAxNDcuNzg2LDU4LjM1NSBDMTQ3Ljk2NCw1OC4zNjMgMTQ4LjE0Myw1OC4zNjMgMTQ4LjMyMSw1OC4zNTQgQzE0OC4zNzcsNTguMzUyIDE0OC40MjQsNTguMzg3IDE0OC40MzksNTguNDM4IEMxNDguNDU0LDU4LjQ5IDE0OC40MzIsNTguNTQ1IDE0OC4zODUsNTguNTcyIEw2OS4xMjksMTA0LjMzMSBDNjkuMTExLDEwNC4zNDIgNjkuMDksMTA0LjM0NyA2OS4wNywxMDQuMzQ3IEw2OS4wNywxMDQuMzQ3IFogTTY1LjY2NSwxMDEuOTc1IEM2NS43NTQsMTAxLjk3NSA2NS44NDIsMTAxLjk3NyA2NS45MywxMDEuOTgxIEM2Ny4xOTYsMTAyLjAzNyA2OC4yODMsMTAyLjQ2OSA2OC44MzgsMTAzLjEzOSBDNjkuMDY1LDEwMy40MTMgNjkuMTg4LDEwMy43MTQgNjkuMTk4LDEwNC4wMjEgTDE0Ny44ODMsNTguNTkyIEMxNDcuODQ3LDU4LjU5MiAxNDcuODExLDU4LjU5MSAxNDcuNzc2LDU4LjU4OSBDMTQ2LjUwOSw1OC41MzMgMTQ1LjQyMiw1OC4xIDE0NC44NjcsNTcuNDMxIEMxNDQuNTg1LDU3LjA5MSAxNDQuNDY1LDU2LjcwNyAxNDQuNTIsNTYuMzI0IEMxNDQuNTYzLDU2LjAyMSAxNDQuNTUyLDU1LjcxNiAxNDQuNDg4LDU1LjQxNCBMNjMuODQ2LDEwMS45NyBDNjQuMzUzLDEwMi4wMDIgNjQuODY3LDEwMi4wMDYgNjUuMzc0LDEwMS45ODIgQzY1LjQ3MSwxMDEuOTc3IDY1LjU2OCwxMDEuOTc1IDY1LjY2NSwxMDEuOTc1IEw2NS42NjUsMTAxLjk3NSBaIiBpZD0iRmlsbC01IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTIuMjA4LDU1LjEzNCBDMS4yMDcsNTMuMzA3IDEuOTY3LDUwLjkxNyAzLjkwNiw0OS43OTcgTDU5LjkxNywxNy40NTMgQzYxLjg1NiwxNi4zMzMgNjQuMjQxLDE2LjkwNyA2NS4yNDMsMTguNzM0IEw2NS40NzUsMTkuMTQ0IEM2NS44NzIsMTkuODgyIDY2LjM2OCwyMC41NiA2Ni45NDUsMjEuMTY1IEw2Ny4yMjMsMjEuNDM1IEM3MC41NDgsMjQuNjQ5IDc1LjgwNiwyNS4xNTEgODAuMTExLDIyLjY2NSBMODcuNDMsMTguNDQ1IEM4OS4zNywxNy4zMjYgOTEuNzU0LDE3Ljg5OSA5Mi43NTUsMTkuNzI3IEw5Ni4wMDUsMjUuNjU1IEwxMi40ODYsNzMuODg0IEwyLjIwOCw1NS4xMzQgWiIgaWQ9IkZpbGwtNiIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMi40ODYsNzQuMDAxIEMxMi40NzYsNzQuMDAxIDEyLjQ2NSw3My45OTkgMTIuNDU1LDczLjk5NiBDMTIuNDI0LDczLjk4OCAxMi4zOTksNzMuOTY3IDEyLjM4NCw3My45NCBMMi4xMDYsNTUuMTkgQzEuMDc1LDUzLjMxIDEuODU3LDUwLjg0NSAzLjg0OCw0OS42OTYgTDU5Ljg1OCwxNy4zNTIgQzYwLjUyNSwxNi45NjcgNjEuMjcxLDE2Ljc2NCA2Mi4wMTYsMTYuNzY0IEM2My40MzEsMTYuNzY0IDY0LjY2NiwxNy40NjYgNjUuMzI3LDE4LjY0NiBDNjUuMzM3LDE4LjY1NCA2NS4zNDUsMTguNjYzIDY1LjM1MSwxOC42NzQgTDY1LjU3OCwxOS4wODggQzY1LjU4NCwxOS4xIDY1LjU4OSwxOS4xMTIgNjUuNTkxLDE5LjEyNiBDNjUuOTg1LDE5LjgzOCA2Ni40NjksMjAuNDk3IDY3LjAzLDIxLjA4NSBMNjcuMzA1LDIxLjM1MSBDNjkuMTUxLDIzLjEzNyA3MS42NDksMjQuMTIgNzQuMzM2LDI0LjEyIEM3Ni4zMTMsMjQuMTIgNzguMjksMjMuNTgyIDgwLjA1MywyMi41NjMgQzgwLjA2NCwyMi41NTcgODAuMDc2LDIyLjU1MyA4MC4wODgsMjIuNTUgTDg3LjM3MiwxOC4zNDQgQzg4LjAzOCwxNy45NTkgODguNzg0LDE3Ljc1NiA4OS41MjksMTcuNzU2IEM5MC45NTYsMTcuNzU2IDkyLjIwMSwxOC40NzIgOTIuODU4LDE5LjY3IEw5Ni4xMDcsMjUuNTk5IEM5Ni4xMzgsMjUuNjU0IDk2LjExOCwyNS43MjQgOTYuMDYzLDI1Ljc1NiBMMTIuNTQ1LDczLjk4NSBDMTIuNTI2LDczLjk5NiAxMi41MDYsNzQuMDAxIDEyLjQ4Niw3NC4wMDEgTDEyLjQ4Niw3NC4wMDEgWiBNNjIuMDE2LDE2Ljk5NyBDNjEuMzEyLDE2Ljk5NyA2MC42MDYsMTcuMTkgNTkuOTc1LDE3LjU1NCBMMy45NjUsNDkuODk5IEMyLjA4Myw1MC45ODUgMS4zNDEsNTMuMzA4IDIuMzEsNTUuMDc4IEwxMi41MzEsNzMuNzIzIEw5NS44NDgsMjUuNjExIEw5Mi42NTMsMTkuNzgyIEM5Mi4wMzgsMTguNjYgOTAuODcsMTcuOTkgODkuNTI5LDE3Ljk5IEM4OC44MjUsMTcuOTkgODguMTE5LDE4LjE4MiA4Ny40ODksMTguNTQ3IEw4MC4xNzIsMjIuNzcyIEM4MC4xNjEsMjIuNzc4IDgwLjE0OSwyMi43ODIgODAuMTM3LDIyLjc4NSBDNzguMzQ2LDIzLjgxMSA3Ni4zNDEsMjQuMzU0IDc0LjMzNiwyNC4zNTQgQzcxLjU4OCwyNC4zNTQgNjkuMDMzLDIzLjM0NyA2Ny4xNDIsMjEuNTE5IEw2Ni44NjQsMjEuMjQ5IEM2Ni4yNzcsMjAuNjM0IDY1Ljc3NCwxOS45NDcgNjUuMzY3LDE5LjIwMyBDNjUuMzYsMTkuMTkyIDY1LjM1NiwxOS4xNzkgNjUuMzU0LDE5LjE2NiBMNjUuMTYzLDE4LjgxOSBDNjUuMTU0LDE4LjgxMSA2NS4xNDYsMTguODAxIDY1LjE0LDE4Ljc5IEM2NC41MjUsMTcuNjY3IDYzLjM1NywxNi45OTcgNjIuMDE2LDE2Ljk5NyBMNjIuMDE2LDE2Ljk5NyBaIiBpZD0iRmlsbC03IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTQyLjQzNCw0OC44MDggTDQyLjQzNCw0OC44MDggQzM5LjkyNCw0OC44MDcgMzcuNzM3LDQ3LjU1IDM2LjU4Miw0NS40NDMgQzM0Ljc3MSw0Mi4xMzkgMzYuMTQ0LDM3LjgwOSAzOS42NDEsMzUuNzg5IEw1MS45MzIsMjguNjkxIEM1My4xMDMsMjguMDE1IDU0LjQxMywyNy42NTggNTUuNzIxLDI3LjY1OCBDNTguMjMxLDI3LjY1OCA2MC40MTgsMjguOTE2IDYxLjU3MywzMS4wMjMgQzYzLjM4NCwzNC4zMjcgNjIuMDEyLDM4LjY1NyA1OC41MTQsNDAuNjc3IEw0Ni4yMjMsNDcuNzc1IEM0NS4wNTMsNDguNDUgNDMuNzQyLDQ4LjgwOCA0Mi40MzQsNDguODA4IEw0Mi40MzQsNDguODA4IFogTTU1LjcyMSwyOC4xMjUgQzU0LjQ5NSwyOC4xMjUgNTMuMjY1LDI4LjQ2MSA1Mi4xNjYsMjkuMDk2IEwzOS44NzUsMzYuMTk0IEMzNi41OTYsMzguMDg3IDM1LjMwMiw0Mi4xMzYgMzYuOTkyLDQ1LjIxOCBDMzguMDYzLDQ3LjE3MyA0MC4wOTgsNDguMzQgNDIuNDM0LDQ4LjM0IEM0My42NjEsNDguMzQgNDQuODksNDguMDA1IDQ1Ljk5LDQ3LjM3IEw1OC4yODEsNDAuMjcyIEM2MS41NiwzOC4zNzkgNjIuODUzLDM0LjMzIDYxLjE2NCwzMS4yNDggQzYwLjA5MiwyOS4yOTMgNTguMDU4LDI4LjEyNSA1NS43MjEsMjguMTI1IEw1NS43MjEsMjguMTI1IFoiIGlkPSJGaWxsLTgiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQ5LjU4OCwyLjQwNyBDMTQ5LjU4OCwyLjQwNyAxNTUuNzY4LDUuOTc1IDE1Ni4zMjUsNi4yOTcgTDE1Ni4zMjUsNy4xODQgQzE1Ni4zMjUsNy4zNiAxNTYuMzM4LDcuNTQ0IDE1Ni4zNjIsNy43MzMgQzE1Ni4zNzMsNy44MTQgMTU2LjM4Miw3Ljg5NCAxNTYuMzksNy45NzUgQzE1Ni41Myw5LjM5IDE1Ny4zNjMsMTAuOTczIDE1OC40OTUsMTEuOTc0IEwxNjUuODkxLDE4LjUxOSBDMTY2LjA2OCwxOC42NzUgMTY2LjI0OSwxOC44MTQgMTY2LjQzMiwxOC45MzQgQzE2OC4wMTEsMTkuOTc0IDE2OS4zODIsMTkuNCAxNjkuNDk0LDE3LjY1MiBDMTY5LjU0MywxNi44NjggMTY5LjU1MSwxNi4wNTcgMTY5LjUxNywxNS4yMjMgTDE2OS41MTQsMTUuMDYzIEwxNjkuNTE0LDEzLjkxMiBDMTcwLjc4LDE0LjY0MiAxOTUuNTAxLDI4LjkxNSAxOTUuNTAxLDI4LjkxNSBMMTk1LjUwMSw4Mi45MTUgQzE5NS41MDEsODQuMDA1IDE5NC43MzEsODQuNDQ1IDE5My43ODEsODMuODk3IEwxNTEuMzA4LDU5LjM3NCBDMTUwLjM1OCw1OC44MjYgMTQ5LjU4OCw1Ny40OTcgMTQ5LjU4OCw1Ni40MDggTDE0OS41ODgsMjIuMzc1IiBpZD0iRmlsbC05IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE5NC41NTMsODQuMjUgQzE5NC4yOTYsODQuMjUgMTk0LjAxMyw4NC4xNjUgMTkzLjcyMiw4My45OTcgTDE1MS4yNSw1OS40NzYgQzE1MC4yNjksNTguOTA5IDE0OS40NzEsNTcuNTMzIDE0OS40NzEsNTYuNDA4IEwxNDkuNDcxLDIyLjM3NSBMMTQ5LjcwNSwyMi4zNzUgTDE0OS43MDUsNTYuNDA4IEMxNDkuNzA1LDU3LjQ1OSAxNTAuNDUsNTguNzQ0IDE1MS4zNjYsNTkuMjc0IEwxOTMuODM5LDgzLjc5NSBDMTk0LjI2Myw4NC4wNCAxOTQuNjU1LDg0LjA4MyAxOTQuOTQyLDgzLjkxNyBDMTk1LjIyNyw4My43NTMgMTk1LjM4NCw4My4zOTcgMTk1LjM4NCw4Mi45MTUgTDE5NS4zODQsMjguOTgyIEMxOTQuMTAyLDI4LjI0MiAxNzIuMTA0LDE1LjU0MiAxNjkuNjMxLDE0LjExNCBMMTY5LjYzNCwxNS4yMiBDMTY5LjY2OCwxNi4wNTIgMTY5LjY2LDE2Ljg3NCAxNjkuNjEsMTcuNjU5IEMxNjkuNTU2LDE4LjUwMyAxNjkuMjE0LDE5LjEyMyAxNjguNjQ3LDE5LjQwNSBDMTY4LjAyOCwxOS43MTQgMTY3LjE5NywxOS41NzggMTY2LjM2NywxOS4wMzIgQzE2Ni4xODEsMTguOTA5IDE2NS45OTUsMTguNzY2IDE2NS44MTQsMTguNjA2IEwxNTguNDE3LDEyLjA2MiBDMTU3LjI1OSwxMS4wMzYgMTU2LjQxOCw5LjQzNyAxNTYuMjc0LDcuOTg2IEMxNTYuMjY2LDcuOTA3IDE1Ni4yNTcsNy44MjcgMTU2LjI0Nyw3Ljc0OCBDMTU2LjIyMSw3LjU1NSAxNTYuMjA5LDcuMzY1IDE1Ni4yMDksNy4xODQgTDE1Ni4yMDksNi4zNjQgQzE1NS4zNzUsNS44ODMgMTQ5LjUyOSwyLjUwOCAxNDkuNTI5LDIuNTA4IEwxNDkuNjQ2LDIuMzA2IEMxNDkuNjQ2LDIuMzA2IDE1NS44MjcsNS44NzQgMTU2LjM4NCw2LjE5NiBMMTU2LjQ0Miw2LjIzIEwxNTYuNDQyLDcuMTg0IEMxNTYuNDQyLDcuMzU1IDE1Ni40NTQsNy41MzUgMTU2LjQ3OCw3LjcxNyBDMTU2LjQ4OSw3LjggMTU2LjQ5OSw3Ljg4MiAxNTYuNTA3LDcuOTYzIEMxNTYuNjQ1LDkuMzU4IDE1Ny40NTUsMTAuODk4IDE1OC41NzIsMTEuODg2IEwxNjUuOTY5LDE4LjQzMSBDMTY2LjE0MiwxOC41ODQgMTY2LjMxOSwxOC43MiAxNjYuNDk2LDE4LjgzNyBDMTY3LjI1NCwxOS4zMzYgMTY4LDE5LjQ2NyAxNjguNTQzLDE5LjE5NiBDMTY5LjAzMywxOC45NTMgMTY5LjMyOSwxOC40MDEgMTY5LjM3NywxNy42NDUgQzE2OS40MjcsMTYuODY3IDE2OS40MzQsMTYuMDU0IDE2OS40MDEsMTUuMjI4IEwxNjkuMzk3LDE1LjA2NSBMMTY5LjM5NywxMy43MSBMMTY5LjU3MiwxMy44MSBDMTcwLjgzOSwxNC41NDEgMTk1LjU1OSwyOC44MTQgMTk1LjU1OSwyOC44MTQgTDE5NS42MTgsMjguODQ3IEwxOTUuNjE4LDgyLjkxNSBDMTk1LjYxOCw4My40ODQgMTk1LjQyLDgzLjkxMSAxOTUuMDU5LDg0LjExOSBDMTk0LjkwOCw4NC4yMDYgMTk0LjczNyw4NC4yNSAxOTQuNTUzLDg0LjI1IiBpZD0iRmlsbC0xMCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNDUuNjg1LDU2LjE2MSBMMTY5LjgsNzAuMDgzIEwxNDMuODIyLDg1LjA4MSBMMTQyLjM2LDg0Ljc3NCBDMTM1LjgyNiw4Mi42MDQgMTI4LjczMiw4MS4wNDYgMTIxLjM0MSw4MC4xNTggQzExNi45NzYsNzkuNjM0IDExMi42NzgsODEuMjU0IDExMS43NDMsODMuNzc4IEMxMTEuNTA2LDg0LjQxNCAxMTEuNTAzLDg1LjA3MSAxMTEuNzMyLDg1LjcwNiBDMTEzLjI3LDg5Ljk3MyAxMTUuOTY4LDk0LjA2OSAxMTkuNzI3LDk3Ljg0MSBMMTIwLjI1OSw5OC42ODYgQzEyMC4yNiw5OC42ODUgOTQuMjgyLDExMy42ODMgOTQuMjgyLDExMy42ODMgTDcwLjE2Nyw5OS43NjEgTDE0NS42ODUsNTYuMTYxIiBpZD0iRmlsbC0xMSIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik05NC4yODIsMTEzLjgxOCBMOTQuMjIzLDExMy43ODUgTDY5LjkzMyw5OS43NjEgTDcwLjEwOCw5OS42NiBMMTQ1LjY4NSw1Ni4wMjYgTDE0NS43NDMsNTYuMDU5IEwxNzAuMDMzLDcwLjA4MyBMMTQzLjg0Miw4NS4yMDUgTDE0My43OTcsODUuMTk1IEMxNDMuNzcyLDg1LjE5IDE0Mi4zMzYsODQuODg4IDE0Mi4zMzYsODQuODg4IEMxMzUuNzg3LDgyLjcxNCAxMjguNzIzLDgxLjE2MyAxMjEuMzI3LDgwLjI3NCBDMTIwLjc4OCw4MC4yMDkgMTIwLjIzNiw4MC4xNzcgMTE5LjY4OSw4MC4xNzcgQzExNS45MzEsODAuMTc3IDExMi42MzUsODEuNzA4IDExMS44NTIsODMuODE5IEMxMTEuNjI0LDg0LjQzMiAxMTEuNjIxLDg1LjA1MyAxMTEuODQyLDg1LjY2NyBDMTEzLjM3Nyw4OS45MjUgMTE2LjA1OCw5My45OTMgMTE5LjgxLDk3Ljc1OCBMMTE5LjgyNiw5Ny43NzkgTDEyMC4zNTIsOTguNjE0IEMxMjAuMzU0LDk4LjYxNyAxMjAuMzU2LDk4LjYyIDEyMC4zNTgsOTguNjI0IEwxMjAuNDIyLDk4LjcyNiBMMTIwLjMxNyw5OC43ODcgQzEyMC4yNjQsOTguODE4IDk0LjU5OSwxMTMuNjM1IDk0LjM0LDExMy43ODUgTDk0LjI4MiwxMTMuODE4IEw5NC4yODIsMTEzLjgxOCBaIE03MC40MDEsOTkuNzYxIEw5NC4yODIsMTEzLjU0OSBMMTE5LjA4NCw5OS4yMjkgQzExOS42Myw5OC45MTQgMTE5LjkzLDk4Ljc0IDEyMC4xMDEsOTguNjU0IEwxMTkuNjM1LDk3LjkxNCBDMTE1Ljg2NCw5NC4xMjcgMTEzLjE2OCw5MC4wMzMgMTExLjYyMiw4NS43NDYgQzExMS4zODIsODUuMDc5IDExMS4zODYsODQuNDA0IDExMS42MzMsODMuNzM4IEMxMTIuNDQ4LDgxLjUzOSAxMTUuODM2LDc5Ljk0MyAxMTkuNjg5LDc5Ljk0MyBDMTIwLjI0Niw3OS45NDMgMTIwLjgwNiw3OS45NzYgMTIxLjM1NSw4MC4wNDIgQzEyOC43NjcsODAuOTMzIDEzNS44NDYsODIuNDg3IDE0Mi4zOTYsODQuNjYzIEMxNDMuMjMyLDg0LjgzOCAxNDMuNjExLDg0LjkxNyAxNDMuNzg2LDg0Ljk2NyBMMTY5LjU2Niw3MC4wODMgTDE0NS42ODUsNTYuMjk1IEw3MC40MDEsOTkuNzYxIEw3MC40MDEsOTkuNzYxIFoiIGlkPSJGaWxsLTEyIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2Ny4yMywxOC45NzkgTDE2Ny4yMyw2OS44NSBMMTM5LjkwOSw4NS42MjMgTDEzMy40NDgsNzEuNDU2IEMxMzIuNTM4LDY5LjQ2IDEzMC4wMiw2OS43MTggMTI3LjgyNCw3Mi4wMyBDMTI2Ljc2OSw3My4xNCAxMjUuOTMxLDc0LjU4NSAxMjUuNDk0LDc2LjA0OCBMMTE5LjAzNCw5Ny42NzYgTDkxLjcxMiwxMTMuNDUgTDkxLjcxMiw2Mi41NzkgTDE2Ny4yMywxOC45NzkiIGlkPSJGaWxsLTEzIiBmaWxsPSIjRkZGRkZGIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTkxLjcxMiwxMTMuNTY3IEM5MS42OTIsMTEzLjU2NyA5MS42NzIsMTEzLjU2MSA5MS42NTMsMTEzLjU1MSBDOTEuNjE4LDExMy41MyA5MS41OTUsMTEzLjQ5MiA5MS41OTUsMTEzLjQ1IEw5MS41OTUsNjIuNTc5IEM5MS41OTUsNjIuNTM3IDkxLjYxOCw2Mi40OTkgOTEuNjUzLDYyLjQ3OCBMMTY3LjE3MiwxOC44NzggQzE2Ny4yMDgsMTguODU3IDE2Ny4yNTIsMTguODU3IDE2Ny4yODgsMTguODc4IEMxNjcuMzI0LDE4Ljg5OSAxNjcuMzQ3LDE4LjkzNyAxNjcuMzQ3LDE4Ljk3OSBMMTY3LjM0Nyw2OS44NSBDMTY3LjM0Nyw2OS44OTEgMTY3LjMyNCw2OS45MyAxNjcuMjg4LDY5Ljk1IEwxMzkuOTY3LDg1LjcyNSBDMTM5LjkzOSw4NS43NDEgMTM5LjkwNSw4NS43NDUgMTM5Ljg3Myw4NS43MzUgQzEzOS44NDIsODUuNzI1IDEzOS44MTYsODUuNzAyIDEzOS44MDIsODUuNjcyIEwxMzMuMzQyLDcxLjUwNCBDMTMyLjk2Nyw3MC42ODIgMTMyLjI4LDcwLjIyOSAxMzEuNDA4LDcwLjIyOSBDMTMwLjMxOSw3MC4yMjkgMTI5LjA0NCw3MC45MTUgMTI3LjkwOCw3Mi4xMSBDMTI2Ljg3NCw3My4yIDEyNi4wMzQsNzQuNjQ3IDEyNS42MDYsNzYuMDgyIEwxMTkuMTQ2LDk3LjcwOSBDMTE5LjEzNyw5Ny43MzggMTE5LjExOCw5Ny43NjIgMTE5LjA5Miw5Ny43NzcgTDkxLjc3LDExMy41NTEgQzkxLjc1MiwxMTMuNTYxIDkxLjczMiwxMTMuNTY3IDkxLjcxMiwxMTMuNTY3IEw5MS43MTIsMTEzLjU2NyBaIE05MS44MjksNjIuNjQ3IEw5MS44MjksMTEzLjI0OCBMMTE4LjkzNSw5Ny41OTggTDEyNS4zODIsNzYuMDE1IEMxMjUuODI3LDc0LjUyNSAxMjYuNjY0LDczLjA4MSAxMjcuNzM5LDcxLjk1IEMxMjguOTE5LDcwLjcwOCAxMzAuMjU2LDY5Ljk5NiAxMzEuNDA4LDY5Ljk5NiBDMTMyLjM3Nyw2OS45OTYgMTMzLjEzOSw3MC40OTcgMTMzLjU1NCw3MS40MDcgTDEzOS45NjEsODUuNDU4IEwxNjcuMTEzLDY5Ljc4MiBMMTY3LjExMywxOS4xODEgTDkxLjgyOSw2Mi42NDcgTDkxLjgyOSw2Mi42NDcgWiIgaWQ9IkZpbGwtMTQiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTY4LjU0MywxOS4yMTMgTDE2OC41NDMsNzAuMDgzIEwxNDEuMjIxLDg1Ljg1NyBMMTM0Ljc2MSw3MS42ODkgQzEzMy44NTEsNjkuNjk0IDEzMS4zMzMsNjkuOTUxIDEyOS4xMzcsNzIuMjYzIEMxMjguMDgyLDczLjM3NCAxMjcuMjQ0LDc0LjgxOSAxMjYuODA3LDc2LjI4MiBMMTIwLjM0Niw5Ny45MDkgTDkzLjAyNSwxMTMuNjgzIEw5My4wMjUsNjIuODEzIEwxNjguNTQzLDE5LjIxMyIgaWQ9IkZpbGwtMTUiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTMuMDI1LDExMy44IEM5My4wMDUsMTEzLjggOTIuOTg0LDExMy43OTUgOTIuOTY2LDExMy43ODUgQzkyLjkzMSwxMTMuNzY0IDkyLjkwOCwxMTMuNzI1IDkyLjkwOCwxMTMuNjg0IEw5Mi45MDgsNjIuODEzIEM5Mi45MDgsNjIuNzcxIDkyLjkzMSw2Mi43MzMgOTIuOTY2LDYyLjcxMiBMMTY4LjQ4NCwxOS4xMTIgQzE2OC41MiwxOS4wOSAxNjguNTY1LDE5LjA5IDE2OC42MDEsMTkuMTEyIEMxNjguNjM3LDE5LjEzMiAxNjguNjYsMTkuMTcxIDE2OC42NiwxOS4yMTIgTDE2OC42Niw3MC4wODMgQzE2OC42Niw3MC4xMjUgMTY4LjYzNyw3MC4xNjQgMTY4LjYwMSw3MC4xODQgTDE0MS4yOCw4NS45NTggQzE0MS4yNTEsODUuOTc1IDE0MS4yMTcsODUuOTc5IDE0MS4xODYsODUuOTY4IEMxNDEuMTU0LDg1Ljk1OCAxNDEuMTI5LDg1LjkzNiAxNDEuMTE1LDg1LjkwNiBMMTM0LjY1NSw3MS43MzggQzEzNC4yOCw3MC45MTUgMTMzLjU5Myw3MC40NjMgMTMyLjcyLDcwLjQ2MyBDMTMxLjYzMiw3MC40NjMgMTMwLjM1Nyw3MS4xNDggMTI5LjIyMSw3Mi4zNDQgQzEyOC4xODYsNzMuNDMzIDEyNy4zNDcsNzQuODgxIDEyNi45MTksNzYuMzE1IEwxMjAuNDU4LDk3Ljk0MyBDMTIwLjQ1LDk3Ljk3MiAxMjAuNDMxLDk3Ljk5NiAxMjAuNDA1LDk4LjAxIEw5My4wODMsMTEzLjc4NSBDOTMuMDY1LDExMy43OTUgOTMuMDQ1LDExMy44IDkzLjAyNSwxMTMuOCBMOTMuMDI1LDExMy44IFogTTkzLjE0Miw2Mi44ODEgTDkzLjE0MiwxMTMuNDgxIEwxMjAuMjQ4LDk3LjgzMiBMMTI2LjY5NSw3Ni4yNDggQzEyNy4xNCw3NC43NTggMTI3Ljk3Nyw3My4zMTUgMTI5LjA1Miw3Mi4xODMgQzEzMC4yMzEsNzAuOTQyIDEzMS41NjgsNzAuMjI5IDEzMi43Miw3MC4yMjkgQzEzMy42ODksNzAuMjI5IDEzNC40NTIsNzAuNzMxIDEzNC44NjcsNzEuNjQxIEwxNDEuMjc0LDg1LjY5MiBMMTY4LjQyNiw3MC4wMTYgTDE2OC40MjYsMTkuNDE1IEw5My4xNDIsNjIuODgxIEw5My4xNDIsNjIuODgxIFoiIGlkPSJGaWxsLTE2IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2OS44LDcwLjA4MyBMMTQyLjQ3OCw4NS44NTcgTDEzNi4wMTgsNzEuNjg5IEMxMzUuMTA4LDY5LjY5NCAxMzIuNTksNjkuOTUxIDEzMC4zOTMsNzIuMjYzIEMxMjkuMzM5LDczLjM3NCAxMjguNSw3NC44MTkgMTI4LjA2NCw3Ni4yODIgTDEyMS42MDMsOTcuOTA5IEw5NC4yODIsMTEzLjY4MyBMOTQuMjgyLDYyLjgxMyBMMTY5LjgsMTkuMjEzIEwxNjkuOCw3MC4wODMgWiIgaWQ9IkZpbGwtMTciIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNOTQuMjgyLDExMy45MTcgQzk0LjI0MSwxMTMuOTE3IDk0LjIwMSwxMTMuOTA3IDk0LjE2NSwxMTMuODg2IEM5NC4wOTMsMTEzLjg0NSA5NC4wNDgsMTEzLjc2NyA5NC4wNDgsMTEzLjY4NCBMOTQuMDQ4LDYyLjgxMyBDOTQuMDQ4LDYyLjczIDk0LjA5Myw2Mi42NTIgOTQuMTY1LDYyLjYxMSBMMTY5LjY4MywxOS4wMSBDMTY5Ljc1NSwxOC45NjkgMTY5Ljg0NCwxOC45NjkgMTY5LjkxNywxOS4wMSBDMTY5Ljk4OSwxOS4wNTIgMTcwLjAzMywxOS4xMjkgMTcwLjAzMywxOS4yMTIgTDE3MC4wMzMsNzAuMDgzIEMxNzAuMDMzLDcwLjE2NiAxNjkuOTg5LDcwLjI0NCAxNjkuOTE3LDcwLjI4NSBMMTQyLjU5NSw4Ni4wNiBDMTQyLjUzOCw4Ni4wOTIgMTQyLjQ2OSw4Ni4xIDE0Mi40MDcsODYuMDggQzE0Mi4zNDQsODYuMDYgMTQyLjI5Myw4Ni4wMTQgMTQyLjI2Niw4NS45NTQgTDEzNS44MDUsNzEuNzg2IEMxMzUuNDQ1LDcwLjk5NyAxMzQuODEzLDcwLjU4IDEzMy45NzcsNzAuNTggQzEzMi45MjEsNzAuNTggMTMxLjY3Niw3MS4yNTIgMTMwLjU2Miw3Mi40MjQgQzEyOS41NCw3My41MDEgMTI4LjcxMSw3NC45MzEgMTI4LjI4Nyw3Ni4zNDggTDEyMS44MjcsOTcuOTc2IEMxMjEuODEsOTguMDM0IDEyMS43NzEsOTguMDgyIDEyMS43Miw5OC4xMTIgTDk0LjM5OCwxMTMuODg2IEM5NC4zNjIsMTEzLjkwNyA5NC4zMjIsMTEzLjkxNyA5NC4yODIsMTEzLjkxNyBMOTQuMjgyLDExMy45MTcgWiBNOTQuNTE1LDYyLjk0OCBMOTQuNTE1LDExMy4yNzkgTDEyMS40MDYsOTcuNzU0IEwxMjcuODQsNzYuMjE1IEMxMjguMjksNzQuNzA4IDEyOS4xMzcsNzMuMjQ3IDEzMC4yMjQsNzIuMTAzIEMxMzEuNDI1LDcwLjgzOCAxMzIuNzkzLDcwLjExMiAxMzMuOTc3LDcwLjExMiBDMTM0Ljk5NSw3MC4xMTIgMTM1Ljc5NSw3MC42MzggMTM2LjIzLDcxLjU5MiBMMTQyLjU4NCw4NS41MjYgTDE2OS41NjYsNjkuOTQ4IEwxNjkuNTY2LDE5LjYxNyBMOTQuNTE1LDYyLjk0OCBMOTQuNTE1LDYyLjk0OCBaIiBpZD0iRmlsbC0xOCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMDkuODk0LDkyLjk0MyBMMTA5Ljg5NCw5Mi45NDMgQzEwOC4xMiw5Mi45NDMgMTA2LjY1Myw5Mi4yMTggMTA1LjY1LDkwLjgyMyBDMTA1LjU4Myw5MC43MzEgMTA1LjU5Myw5MC42MSAxMDUuNjczLDkwLjUyOSBDMTA1Ljc1Myw5MC40NDggMTA1Ljg4LDkwLjQ0IDEwNS45NzQsOTAuNTA2IEMxMDYuNzU0LDkxLjA1MyAxMDcuNjc5LDkxLjMzMyAxMDguNzI0LDkxLjMzMyBDMTEwLjA0Nyw5MS4zMzMgMTExLjQ3OCw5MC44OTQgMTEyLjk4LDkwLjAyNyBDMTE4LjI5MSw4Ni45NiAxMjIuNjExLDc5LjUwOSAxMjIuNjExLDczLjQxNiBDMTIyLjYxMSw3MS40ODkgMTIyLjE2OSw2OS44NTYgMTIxLjMzMyw2OC42OTIgQzEyMS4yNjYsNjguNiAxMjEuMjc2LDY4LjQ3MyAxMjEuMzU2LDY4LjM5MiBDMTIxLjQzNiw2OC4zMTEgMTIxLjU2Myw2OC4yOTkgMTIxLjY1Niw2OC4zNjUgQzEyMy4zMjcsNjkuNTM3IDEyNC4yNDcsNzEuNzQ2IDEyNC4yNDcsNzQuNTg0IEMxMjQuMjQ3LDgwLjgyNiAxMTkuODIxLDg4LjQ0NyAxMTQuMzgyLDkxLjU4NyBDMTEyLjgwOCw5Mi40OTUgMTExLjI5OCw5Mi45NDMgMTA5Ljg5NCw5Mi45NDMgTDEwOS44OTQsOTIuOTQzIFogTTEwNi45MjUsOTEuNDAxIEMxMDcuNzM4LDkyLjA1MiAxMDguNzQ1LDkyLjI3OCAxMDkuODkzLDkyLjI3OCBMMTA5Ljg5NCw5Mi4yNzggQzExMS4yMTUsOTIuMjc4IDExMi42NDcsOTEuOTUxIDExNC4xNDgsOTEuMDg0IEMxMTkuNDU5LDg4LjAxNyAxMjMuNzgsODAuNjIxIDEyMy43OCw3NC41MjggQzEyMy43OCw3Mi41NDkgMTIzLjMxNyw3MC45MjkgMTIyLjQ1NCw2OS43NjcgQzEyMi44NjUsNzAuODAyIDEyMy4wNzksNzIuMDQyIDEyMy4wNzksNzMuNDAyIEMxMjMuMDc5LDc5LjY0NSAxMTguNjUzLDg3LjI4NSAxMTMuMjE0LDkwLjQyNSBDMTExLjY0LDkxLjMzNCAxMTAuMTMsOTEuNzQyIDEwOC43MjQsOTEuNzQyIEMxMDguMDgzLDkxLjc0MiAxMDcuNDgxLDkxLjU5MyAxMDYuOTI1LDkxLjQwMSBMMTA2LjkyNSw5MS40MDEgWiIgaWQ9IkZpbGwtMTkiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjA5Nyw5MC4yMyBDMTE4LjQ4MSw4Ny4xMjIgMTIyLjg0NSw3OS41OTQgMTIyLjg0NSw3My40MTYgQzEyMi44NDUsNzEuMzY1IDEyMi4zNjIsNjkuNzI0IDEyMS41MjIsNjguNTU2IEMxMTkuNzM4LDY3LjMwNCAxMTcuMTQ4LDY3LjM2MiAxMTQuMjY1LDY5LjAyNiBDMTA4Ljg4MSw3Mi4xMzQgMTA0LjUxNyw3OS42NjIgMTA0LjUxNyw4NS44NCBDMTA0LjUxNyw4Ny44OTEgMTA1LDg5LjUzMiAxMDUuODQsOTAuNyBDMTA3LjYyNCw5MS45NTIgMTEwLjIxNCw5MS44OTQgMTEzLjA5Nyw5MC4yMyIgaWQ9IkZpbGwtMjAiIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTA4LjcyNCw5MS42MTQgTDEwOC43MjQsOTEuNjE0IEMxMDcuNTgyLDkxLjYxNCAxMDYuNTY2LDkxLjQwMSAxMDUuNzA1LDkwLjc5NyBDMTA1LjY4NCw5MC43ODMgMTA1LjY2NSw5MC44MTEgMTA1LjY1LDkwLjc5IEMxMDQuNzU2LDg5LjU0NiAxMDQuMjgzLDg3Ljg0MiAxMDQuMjgzLDg1LjgxNyBDMTA0LjI4Myw3OS41NzUgMTA4LjcwOSw3MS45NTMgMTE0LjE0OCw2OC44MTIgQzExNS43MjIsNjcuOTA0IDExNy4yMzIsNjcuNDQ5IDExOC42MzgsNjcuNDQ5IEMxMTkuNzgsNjcuNDQ5IDEyMC43OTYsNjcuNzU4IDEyMS42NTYsNjguMzYyIEMxMjEuNjc4LDY4LjM3NyAxMjEuNjk3LDY4LjM5NyAxMjEuNzEyLDY4LjQxOCBDMTIyLjYwNiw2OS42NjIgMTIzLjA3OSw3MS4zOSAxMjMuMDc5LDczLjQxNSBDMTIzLjA3OSw3OS42NTggMTE4LjY1Myw4Ny4xOTggMTEzLjIxNCw5MC4zMzggQzExMS42NCw5MS4yNDcgMTEwLjEzLDkxLjYxNCAxMDguNzI0LDkxLjYxNCBMMTA4LjcyNCw5MS42MTQgWiBNMTA2LjAwNiw5MC41MDUgQzEwNi43OCw5MS4wMzcgMTA3LjY5NCw5MS4yODEgMTA4LjcyNCw5MS4yODEgQzExMC4wNDcsOTEuMjgxIDExMS40NzgsOTAuODY4IDExMi45OCw5MC4wMDEgQzExOC4yOTEsODYuOTM1IDEyMi42MTEsNzkuNDk2IDEyMi42MTEsNzMuNDAzIEMxMjIuNjExLDcxLjQ5NCAxMjIuMTc3LDY5Ljg4IDEyMS4zNTYsNjguNzE4IEMxMjAuNTgyLDY4LjE4NSAxMTkuNjY4LDY3LjkxOSAxMTguNjM4LDY3LjkxOSBDMTE3LjMxNSw2Ny45MTkgMTE1Ljg4Myw2OC4zNiAxMTQuMzgyLDY5LjIyNyBDMTA5LjA3MSw3Mi4yOTMgMTA0Ljc1MSw3OS43MzMgMTA0Ljc1MSw4NS44MjYgQzEwNC43NTEsODcuNzM1IDEwNS4xODUsODkuMzQzIDEwNi4wMDYsOTAuNTA1IEwxMDYuMDA2LDkwLjUwNSBaIiBpZD0iRmlsbC0yMSIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNDkuMzE4LDcuMjYyIEwxMzkuMzM0LDE2LjE0IEwxNTUuMjI3LDI3LjE3MSBMMTYwLjgxNiwyMS4wNTkgTDE0OS4zMTgsNy4yNjIiIGlkPSJGaWxsLTIyIiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE2OS42NzYsMTMuODQgTDE1OS45MjgsMTkuNDY3IEMxNTYuMjg2LDIxLjU3IDE1MC40LDIxLjU4IDE0Ni43ODEsMTkuNDkxIEMxNDMuMTYxLDE3LjQwMiAxNDMuMTgsMTQuMDAzIDE0Ni44MjIsMTEuOSBMMTU2LjMxNyw2LjI5MiBMMTQ5LjU4OCwyLjQwNyBMNjcuNzUyLDQ5LjQ3OCBMMTEzLjY3NSw3NS45OTIgTDExNi43NTYsNzQuMjEzIEMxMTcuMzg3LDczLjg0OCAxMTcuNjI1LDczLjMxNSAxMTcuMzc0LDcyLjgyMyBDMTE1LjAxNyw2OC4xOTEgMTE0Ljc4MSw2My4yNzcgMTE2LjY5MSw1OC41NjEgQzEyMi4zMjksNDQuNjQxIDE0MS4yLDMzLjc0NiAxNjUuMzA5LDMwLjQ5MSBDMTczLjQ3OCwyOS4zODggMTgxLjk4OSwyOS41MjQgMTkwLjAxMywzMC44ODUgQzE5MC44NjUsMzEuMDMgMTkxLjc4OSwzMC44OTMgMTkyLjQyLDMwLjUyOCBMMTk1LjUwMSwyOC43NSBMMTY5LjY3NiwxMy44NCIgaWQ9IkZpbGwtMjMiIGZpbGw9IiNGQUZBRkEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjY3NSw3Ni40NTkgQzExMy41OTQsNzYuNDU5IDExMy41MTQsNzYuNDM4IDExMy40NDIsNzYuMzk3IEw2Ny41MTgsNDkuODgyIEM2Ny4zNzQsNDkuNzk5IDY3LjI4NCw0OS42NDUgNjcuMjg1LDQ5LjQ3OCBDNjcuMjg1LDQ5LjMxMSA2Ny4zNzQsNDkuMTU3IDY3LjUxOSw0OS4wNzMgTDE0OS4zNTUsMi4wMDIgQzE0OS40OTksMS45MTkgMTQ5LjY3NywxLjkxOSAxNDkuODIxLDIuMDAyIEwxNTYuNTUsNS44ODcgQzE1Ni43NzQsNi4wMTcgMTU2Ljg1LDYuMzAyIDE1Ni43MjIsNi41MjYgQzE1Ni41OTIsNi43NDkgMTU2LjMwNyw2LjgyNiAxNTYuMDgzLDYuNjk2IEwxNDkuNTg3LDIuOTQ2IEw2OC42ODcsNDkuNDc5IEwxMTMuNjc1LDc1LjQ1MiBMMTE2LjUyMyw3My44MDggQzExNi43MTUsNzMuNjk3IDExNy4xNDMsNzMuMzk5IDExNi45NTgsNzMuMDM1IEMxMTQuNTQyLDY4LjI4NyAxMTQuMyw2My4yMjEgMTE2LjI1OCw1OC4zODUgQzExOS4wNjQsNTEuNDU4IDEyNS4xNDMsNDUuMTQzIDEzMy44NCw0MC4xMjIgQzE0Mi40OTcsMzUuMTI0IDE1My4zNTgsMzEuNjMzIDE2NS4yNDcsMzAuMDI4IEMxNzMuNDQ1LDI4LjkyMSAxODIuMDM3LDI5LjA1OCAxOTAuMDkxLDMwLjQyNSBDMTkwLjgzLDMwLjU1IDE5MS42NTIsMzAuNDMyIDE5Mi4xODYsMzAuMTI0IEwxOTQuNTY3LDI4Ljc1IEwxNjkuNDQyLDE0LjI0NCBDMTY5LjIxOSwxNC4xMTUgMTY5LjE0MiwxMy44MjkgMTY5LjI3MSwxMy42MDYgQzE2OS40LDEzLjM4MiAxNjkuNjg1LDEzLjMwNiAxNjkuOTA5LDEzLjQzNSBMMTk1LjczNCwyOC4zNDUgQzE5NS44NzksMjguNDI4IDE5NS45NjgsMjguNTgzIDE5NS45NjgsMjguNzUgQzE5NS45NjgsMjguOTE2IDE5NS44NzksMjkuMDcxIDE5NS43MzQsMjkuMTU0IEwxOTIuNjUzLDMwLjkzMyBDMTkxLjkzMiwzMS4zNSAxOTAuODksMzEuNTA4IDE4OS45MzUsMzEuMzQ2IEMxODEuOTcyLDI5Ljk5NSAxNzMuNDc4LDI5Ljg2IDE2NS4zNzIsMzAuOTU0IEMxNTMuNjAyLDMyLjU0MyAxNDIuODYsMzUuOTkzIDEzNC4zMDcsNDAuOTMxIEMxMjUuNzkzLDQ1Ljg0NyAxMTkuODUxLDUyLjAwNCAxMTcuMTI0LDU4LjczNiBDMTE1LjI3LDYzLjMxNCAxMTUuNTAxLDY4LjExMiAxMTcuNzksNzIuNjExIEMxMTguMTYsNzMuMzM2IDExNy44NDUsNzQuMTI0IDExNi45OSw3NC42MTcgTDExMy45MDksNzYuMzk3IEMxMTMuODM2LDc2LjQzOCAxMTMuNzU2LDc2LjQ1OSAxMTMuNjc1LDc2LjQ1OSIgaWQ9IkZpbGwtMjQiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTUzLjMxNiwyMS4yNzkgQzE1MC45MDMsMjEuMjc5IDE0OC40OTUsMjAuNzUxIDE0Ni42NjQsMTkuNjkzIEMxNDQuODQ2LDE4LjY0NCAxNDMuODQ0LDE3LjIzMiAxNDMuODQ0LDE1LjcxOCBDMTQzLjg0NCwxNC4xOTEgMTQ0Ljg2LDEyLjc2MyAxNDYuNzA1LDExLjY5OCBMMTU2LjE5OCw2LjA5MSBDMTU2LjMwOSw2LjAyNSAxNTYuNDUyLDYuMDYyIDE1Ni41MTgsNi4xNzMgQzE1Ni41ODMsNi4yODQgMTU2LjU0Nyw2LjQyNyAxNTYuNDM2LDYuNDkzIEwxNDYuOTQsMTIuMTAyIEMxNDUuMjQ0LDEzLjA4MSAxNDQuMzEyLDE0LjM2NSAxNDQuMzEyLDE1LjcxOCBDMTQ0LjMxMiwxNy4wNTggMTQ1LjIzLDE4LjMyNiAxNDYuODk3LDE5LjI4OSBDMTUwLjQ0NiwyMS4zMzggMTU2LjI0LDIxLjMyNyAxNTkuODExLDE5LjI2NSBMMTY5LjU1OSwxMy42MzcgQzE2OS42NywxMy41NzMgMTY5LjgxMywxMy42MTEgMTY5Ljg3OCwxMy43MjMgQzE2OS45NDMsMTMuODM0IDE2OS45MDQsMTMuOTc3IDE2OS43OTMsMTQuMDQyIEwxNjAuMDQ1LDE5LjY3IEMxNTguMTg3LDIwLjc0MiAxNTUuNzQ5LDIxLjI3OSAxNTMuMzE2LDIxLjI3OSIgaWQ9IkZpbGwtMjUiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEzLjY3NSw3NS45OTIgTDY3Ljc2Miw0OS40ODQiIGlkPSJGaWxsLTI2IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTExMy42NzUsNzYuMzQyIEMxMTMuNjE1LDc2LjM0MiAxMTMuNTU1LDc2LjMyNyAxMTMuNSw3Ni4yOTUgTDY3LjU4Nyw0OS43ODcgQzY3LjQxOSw0OS42OSA2Ny4zNjIsNDkuNDc2IDY3LjQ1OSw0OS4zMDkgQzY3LjU1Niw0OS4xNDEgNjcuNzcsNDkuMDgzIDY3LjkzNyw0OS4xOCBMMTEzLjg1LDc1LjY4OCBDMTE0LjAxOCw3NS43ODUgMTE0LjA3NSw3NiAxMTMuOTc4LDc2LjE2NyBDMTEzLjkxNCw3Ni4yNzkgMTEzLjc5Niw3Ni4zNDIgMTEzLjY3NSw3Ni4zNDIiIGlkPSJGaWxsLTI3IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTY3Ljc2Miw0OS40ODQgTDY3Ljc2MiwxMDMuNDg1IEM2Ny43NjIsMTA0LjU3NSA2OC41MzIsMTA1LjkwMyA2OS40ODIsMTA2LjQ1MiBMMTExLjk1NSwxMzAuOTczIEMxMTIuOTA1LDEzMS41MjIgMTEzLjY3NSwxMzEuMDgzIDExMy42NzUsMTI5Ljk5MyBMMTEzLjY3NSw3NS45OTIiIGlkPSJGaWxsLTI4IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTExMi43MjcsMTMxLjU2MSBDMTEyLjQzLDEzMS41NjEgMTEyLjEwNywxMzEuNDY2IDExMS43OCwxMzEuMjc2IEw2OS4zMDcsMTA2Ljc1NSBDNjguMjQ0LDEwNi4xNDIgNjcuNDEyLDEwNC43MDUgNjcuNDEyLDEwMy40ODUgTDY3LjQxMiw0OS40ODQgQzY3LjQxMiw0OS4yOSA2Ny41NjksNDkuMTM0IDY3Ljc2Miw0OS4xMzQgQzY3Ljk1Niw0OS4xMzQgNjguMTEzLDQ5LjI5IDY4LjExMyw0OS40ODQgTDY4LjExMywxMDMuNDg1IEM2OC4xMTMsMTA0LjQ0NSA2OC44MiwxMDUuNjY1IDY5LjY1NywxMDYuMTQ4IEwxMTIuMTMsMTMwLjY3IEMxMTIuNDc0LDEzMC44NjggMTEyLjc5MSwxMzAuOTEzIDExMywxMzAuNzkyIEMxMTMuMjA2LDEzMC42NzMgMTEzLjMyNSwxMzAuMzgxIDExMy4zMjUsMTI5Ljk5MyBMMTEzLjMyNSw3NS45OTIgQzExMy4zMjUsNzUuNzk4IDExMy40ODIsNzUuNjQxIDExMy42NzUsNzUuNjQxIEMxMTMuODY5LDc1LjY0MSAxMTQuMDI1LDc1Ljc5OCAxMTQuMDI1LDc1Ljk5MiBMMTE0LjAyNSwxMjkuOTkzIEMxMTQuMDI1LDEzMC42NDggMTEzLjc4NiwxMzEuMTQ3IDExMy4zNSwxMzEuMzk5IEMxMTMuMTYyLDEzMS41MDcgMTEyLjk1MiwxMzEuNTYxIDExMi43MjcsMTMxLjU2MSIgaWQ9IkZpbGwtMjkiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTEyLjg2LDQwLjUxMiBDMTEyLjg2LDQwLjUxMiAxMTIuODYsNDAuNTEyIDExMi44NTksNDAuNTEyIEMxMTAuNTQxLDQwLjUxMiAxMDguMzYsMzkuOTkgMTA2LjcxNywzOS4wNDEgQzEwNS4wMTIsMzguMDU3IDEwNC4wNzQsMzYuNzI2IDEwNC4wNzQsMzUuMjkyIEMxMDQuMDc0LDMzLjg0NyAxMDUuMDI2LDMyLjUwMSAxMDYuNzU0LDMxLjUwNCBMMTE4Ljc5NSwyNC41NTEgQzEyMC40NjMsMjMuNTg5IDEyMi42NjksMjMuMDU4IDEyNS4wMDcsMjMuMDU4IEMxMjcuMzI1LDIzLjA1OCAxMjkuNTA2LDIzLjU4MSAxMzEuMTUsMjQuNTMgQzEzMi44NTQsMjUuNTE0IDEzMy43OTMsMjYuODQ1IDEzMy43OTMsMjguMjc4IEMxMzMuNzkzLDI5LjcyNCAxMzIuODQxLDMxLjA2OSAxMzEuMTEzLDMyLjA2NyBMMTE5LjA3MSwzOS4wMTkgQzExNy40MDMsMzkuOTgyIDExNS4xOTcsNDAuNTEyIDExMi44Niw0MC41MTIgTDExMi44Niw0MC41MTIgWiBNMTI1LjAwNywyMy43NTkgQzEyMi43OSwyMy43NTkgMTIwLjcwOSwyNC4yNTYgMTE5LjE0NiwyNS4xNTggTDEwNy4xMDQsMzIuMTEgQzEwNS42MDIsMzIuOTc4IDEwNC43NzQsMzQuMTA4IDEwNC43NzQsMzUuMjkyIEMxMDQuNzc0LDM2LjQ2NSAxMDUuNTg5LDM3LjU4MSAxMDcuMDY3LDM4LjQzNCBDMTA4LjYwNSwzOS4zMjMgMTEwLjY2MywzOS44MTIgMTEyLjg1OSwzOS44MTIgTDExMi44NiwzOS44MTIgQzExNS4wNzYsMzkuODEyIDExNy4xNTgsMzkuMzE1IDExOC43MjEsMzguNDEzIEwxMzAuNzYyLDMxLjQ2IEMxMzIuMjY0LDMwLjU5MyAxMzMuMDkyLDI5LjQ2MyAxMzMuMDkyLDI4LjI3OCBDMTMzLjA5MiwyNy4xMDYgMTMyLjI3OCwyNS45OSAxMzAuOCwyNS4xMzYgQzEyOS4yNjEsMjQuMjQ4IDEyNy4yMDQsMjMuNzU5IDEyNS4wMDcsMjMuNzU5IEwxMjUuMDA3LDIzLjc1OSBaIiBpZD0iRmlsbC0zMCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNjUuNjMsMTYuMjE5IEwxNTkuODk2LDE5LjUzIEMxNTYuNzI5LDIxLjM1OCAxNTEuNjEsMjEuMzY3IDE0OC40NjMsMTkuNTUgQzE0NS4zMTYsMTcuNzMzIDE0NS4zMzIsMTQuNzc4IDE0OC40OTksMTIuOTQ5IEwxNTQuMjMzLDkuNjM5IEwxNjUuNjMsMTYuMjE5IiBpZD0iRmlsbC0zMSIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNTQuMjMzLDEwLjQ0OCBMMTY0LjIyOCwxNi4yMTkgTDE1OS41NDYsMTguOTIzIEMxNTguMTEyLDE5Ljc1IDE1Ni4xOTQsMjAuMjA2IDE1NC4xNDcsMjAuMjA2IEMxNTIuMTE4LDIwLjIwNiAxNTAuMjI0LDE5Ljc1NyAxNDguODE0LDE4Ljk0MyBDMTQ3LjUyNCwxOC4xOTkgMTQ2LjgxNCwxNy4yNDkgMTQ2LjgxNCwxNi4yNjkgQzE0Ni44MTQsMTUuMjc4IDE0Ny41MzcsMTQuMzE0IDE0OC44NSwxMy41NTYgTDE1NC4yMzMsMTAuNDQ4IE0xNTQuMjMzLDkuNjM5IEwxNDguNDk5LDEyLjk0OSBDMTQ1LjMzMiwxNC43NzggMTQ1LjMxNiwxNy43MzMgMTQ4LjQ2MywxOS41NSBDMTUwLjAzMSwyMC40NTUgMTUyLjA4NiwyMC45MDcgMTU0LjE0NywyMC45MDcgQzE1Ni4yMjQsMjAuOTA3IDE1OC4zMDYsMjAuNDQ3IDE1OS44OTYsMTkuNTMgTDE2NS42MywxNi4yMTkgTDE1NC4yMzMsOS42MzkiIGlkPSJGaWxsLTMyIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0NS40NDUsNzIuNjY3IEwxNDUuNDQ1LDcyLjY2NyBDMTQzLjY3Miw3Mi42NjcgMTQyLjIwNCw3MS44MTcgMTQxLjIwMiw3MC40MjIgQzE0MS4xMzUsNzAuMzMgMTQxLjE0NSw3MC4xNDcgMTQxLjIyNSw3MC4wNjYgQzE0MS4zMDUsNjkuOTg1IDE0MS40MzIsNjkuOTQ2IDE0MS41MjUsNzAuMDExIEMxNDIuMzA2LDcwLjU1OSAxNDMuMjMxLDcwLjgyMyAxNDQuMjc2LDcwLjgyMiBDMTQ1LjU5OCw3MC44MjIgMTQ3LjAzLDcwLjM3NiAxNDguNTMyLDY5LjUwOSBDMTUzLjg0Miw2Ni40NDMgMTU4LjE2Myw1OC45ODcgMTU4LjE2Myw1Mi44OTQgQzE1OC4xNjMsNTAuOTY3IDE1Ny43MjEsNDkuMzMyIDE1Ni44ODQsNDguMTY4IEMxNTYuODE4LDQ4LjA3NiAxNTYuODI4LDQ3Ljk0OCAxNTYuOTA4LDQ3Ljg2NyBDMTU2Ljk4OCw0Ny43ODYgMTU3LjExNCw0Ny43NzQgMTU3LjIwOCw0Ny44NCBDMTU4Ljg3OCw0OS4wMTIgMTU5Ljc5OCw1MS4yMiAxNTkuNzk4LDU0LjA1OSBDMTU5Ljc5OCw2MC4zMDEgMTU1LjM3Myw2OC4wNDYgMTQ5LjkzMyw3MS4xODYgQzE0OC4zNiw3Mi4wOTQgMTQ2Ljg1LDcyLjY2NyAxNDUuNDQ1LDcyLjY2NyBMMTQ1LjQ0NSw3Mi42NjcgWiBNMTQyLjQ3Niw3MSBDMTQzLjI5LDcxLjY1MSAxNDQuMjk2LDcyLjAwMiAxNDUuNDQ1LDcyLjAwMiBDMTQ2Ljc2Nyw3Mi4wMDIgMTQ4LjE5OCw3MS41NSAxNDkuNyw3MC42ODIgQzE1NS4wMSw2Ny42MTcgMTU5LjMzMSw2MC4xNTkgMTU5LjMzMSw1NC4wNjUgQzE1OS4zMzEsNTIuMDg1IDE1OC44NjgsNTAuNDM1IDE1OC4wMDYsNDkuMjcyIEMxNTguNDE3LDUwLjMwNyAxNTguNjMsNTEuNTMyIDE1OC42Myw1Mi44OTIgQzE1OC42Myw1OS4xMzQgMTU0LjIwNSw2Ni43NjcgMTQ4Ljc2NSw2OS45MDcgQzE0Ny4xOTIsNzAuODE2IDE0NS42ODEsNzEuMjgzIDE0NC4yNzYsNzEuMjgzIEMxNDMuNjM0LDcxLjI4MyAxNDMuMDMzLDcxLjE5MiAxNDIuNDc2LDcxIEwxNDIuNDc2LDcxIFoiIGlkPSJGaWxsLTMzIiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0OC42NDgsNjkuNzA0IEMxNTQuMDMyLDY2LjU5NiAxNTguMzk2LDU5LjA2OCAxNTguMzk2LDUyLjg5MSBDMTU4LjM5Niw1MC44MzkgMTU3LjkxMyw0OS4xOTggMTU3LjA3NCw0OC4wMyBDMTU1LjI4OSw0Ni43NzggMTUyLjY5OSw0Ni44MzYgMTQ5LjgxNiw0OC41MDEgQzE0NC40MzMsNTEuNjA5IDE0MC4wNjgsNTkuMTM3IDE0MC4wNjgsNjUuMzE0IEMxNDAuMDY4LDY3LjM2NSAxNDAuNTUyLDY5LjAwNiAxNDEuMzkxLDcwLjE3NCBDMTQzLjE3Niw3MS40MjcgMTQ1Ljc2NSw3MS4zNjkgMTQ4LjY0OCw2OS43MDQiIGlkPSJGaWxsLTM0IiBmaWxsPSIjRkFGQUZBIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTE0NC4yNzYsNzEuMjc2IEwxNDQuMjc2LDcxLjI3NiBDMTQzLjEzMyw3MS4yNzYgMTQyLjExOCw3MC45NjkgMTQxLjI1Nyw3MC4zNjUgQzE0MS4yMzYsNzAuMzUxIDE0MS4yMTcsNzAuMzMyIDE0MS4yMDIsNzAuMzExIEMxNDAuMzA3LDY5LjA2NyAxMzkuODM1LDY3LjMzOSAxMzkuODM1LDY1LjMxNCBDMTM5LjgzNSw1OS4wNzMgMTQ0LjI2LDUxLjQzOSAxNDkuNyw0OC4yOTggQzE1MS4yNzMsNDcuMzkgMTUyLjc4NCw0Ni45MjkgMTU0LjE4OSw0Ni45MjkgQzE1NS4zMzIsNDYuOTI5IDE1Ni4zNDcsNDcuMjM2IDE1Ny4yMDgsNDcuODM5IEMxNTcuMjI5LDQ3Ljg1NCAxNTcuMjQ4LDQ3Ljg3MyAxNTcuMjYzLDQ3Ljg5NCBDMTU4LjE1Nyw0OS4xMzggMTU4LjYzLDUwLjg2NSAxNTguNjMsNTIuODkxIEMxNTguNjMsNTkuMTMyIDE1NC4yMDUsNjYuNzY2IDE0OC43NjUsNjkuOTA3IEMxNDcuMTkyLDcwLjgxNSAxNDUuNjgxLDcxLjI3NiAxNDQuMjc2LDcxLjI3NiBMMTQ0LjI3Niw3MS4yNzYgWiBNMTQxLjU1OCw3MC4xMDQgQzE0Mi4zMzEsNzAuNjM3IDE0My4yNDUsNzEuMDA1IDE0NC4yNzYsNzEuMDA1IEMxNDUuNTk4LDcxLjAwNSAxNDcuMDMsNzAuNDY3IDE0OC41MzIsNjkuNiBDMTUzLjg0Miw2Ni41MzQgMTU4LjE2Myw1OS4wMzMgMTU4LjE2Myw1Mi45MzkgQzE1OC4xNjMsNTEuMDMxIDE1Ny43MjksNDkuMzg1IDE1Ni45MDcsNDguMjIzIEMxNTYuMTMzLDQ3LjY5MSAxNTUuMjE5LDQ3LjQwOSAxNTQuMTg5LDQ3LjQwOSBDMTUyLjg2Nyw0Ny40MDkgMTUxLjQzNSw0Ny44NDIgMTQ5LjkzMyw0OC43MDkgQzE0NC42MjMsNTEuNzc1IDE0MC4zMDIsNTkuMjczIDE0MC4zMDIsNjUuMzY2IEMxNDAuMzAyLDY3LjI3NiAxNDAuNzM2LDY4Ljk0MiAxNDEuNTU4LDcwLjEwNCBMMTQxLjU1OCw3MC4xMDQgWiIgaWQ9IkZpbGwtMzUiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTUwLjcyLDY1LjM2MSBMMTUwLjM1Nyw2NS4wNjYgQzE1MS4xNDcsNjQuMDkyIDE1MS44NjksNjMuMDQgMTUyLjUwNSw2MS45MzggQzE1My4zMTMsNjAuNTM5IDE1My45NzgsNTkuMDY3IDE1NC40ODIsNTcuNTYzIEwxNTQuOTI1LDU3LjcxMiBDMTU0LjQxMiw1OS4yNDUgMTUzLjczMyw2MC43NDUgMTUyLjkxLDYyLjE3MiBDMTUyLjI2Miw2My4yOTUgMTUxLjUyNSw2NC4zNjggMTUwLjcyLDY1LjM2MSIgaWQ9IkZpbGwtMzYiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTE1LjkxNyw4NC41MTQgTDExNS41NTQsODQuMjIgQzExNi4zNDQsODMuMjQ1IDExNy4wNjYsODIuMTk0IDExNy43MDIsODEuMDkyIEMxMTguNTEsNzkuNjkyIDExOS4xNzUsNzguMjIgMTE5LjY3OCw3Ni43MTcgTDEyMC4xMjEsNzYuODY1IEMxMTkuNjA4LDc4LjM5OCAxMTguOTMsNzkuODk5IDExOC4xMDYsODEuMzI2IEMxMTcuNDU4LDgyLjQ0OCAxMTYuNzIyLDgzLjUyMSAxMTUuOTE3LDg0LjUxNCIgaWQ9IkZpbGwtMzciIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTE0LDEzMC40NzYgTDExNCwxMzAuMDA4IEwxMTQsNzYuMDUyIEwxMTQsNzUuNTg0IEwxMTQsNzYuMDUyIEwxMTQsMTMwLjAwOCBMMTE0LDEzMC40NzYiIGlkPSJGaWxsLTM4IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgICAgICA8ZyBpZD0iSW1wb3J0ZWQtTGF5ZXJzLUNvcHkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDYyLjAwMDAwMCwgMC4wMDAwMDApIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTkuODIyLDM3LjQ3NCBDMTkuODM5LDM3LjMzOSAxOS43NDcsMzcuMTk0IDE5LjU1NSwzNy4wODIgQzE5LjIyOCwzNi44OTQgMTguNzI5LDM2Ljg3MiAxOC40NDYsMzcuMDM3IEwxMi40MzQsNDAuNTA4IEMxMi4zMDMsNDAuNTg0IDEyLjI0LDQwLjY4NiAxMi4yNDMsNDAuNzkzIEMxMi4yNDUsNDAuOTI1IDEyLjI0NSw0MS4yNTQgMTIuMjQ1LDQxLjM3MSBMMTIuMjQ1LDQxLjQxNCBMMTIuMjM4LDQxLjU0MiBDOC4xNDgsNDMuODg3IDUuNjQ3LDQ1LjMyMSA1LjY0Nyw0NS4zMjEgQzUuNjQ2LDQ1LjMyMSAzLjU3LDQ2LjM2NyAyLjg2LDUwLjUxMyBDMi44Niw1MC41MTMgMS45NDgsNTcuNDc0IDEuOTYyLDcwLjI1OCBDMS45NzcsODIuODI4IDIuNTY4LDg3LjMyOCAzLjEyOSw5MS42MDkgQzMuMzQ5LDkzLjI5MyA2LjEzLDkzLjczNCA2LjEzLDkzLjczNCBDNi40NjEsOTMuNzc0IDYuODI4LDkzLjcwNyA3LjIxLDkzLjQ4NiBMODIuNDgzLDQ5LjkzNSBDODQuMjkxLDQ4Ljg2NiA4NS4xNSw0Ni4yMTYgODUuNTM5LDQzLjY1MSBDODYuNzUyLDM1LjY2MSA4Ny4yMTQsMTAuNjczIDg1LjI2NCwzLjc3MyBDODUuMDY4LDMuMDggODQuNzU0LDIuNjkgODQuMzk2LDIuNDkxIEw4Mi4zMSwxLjcwMSBDODEuNTgzLDEuNzI5IDgwLjg5NCwyLjE2OCA4MC43NzYsMi4yMzYgQzgwLjYzNiwyLjMxNyA0MS44MDcsMjQuNTg1IDIwLjAzMiwzNy4wNzIgTDE5LjgyMiwzNy40NzQiIGlkPSJGaWxsLTEiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNODIuMzExLDEuNzAxIEw4NC4zOTYsMi40OTEgQzg0Ljc1NCwyLjY5IDg1LjA2OCwzLjA4IDg1LjI2NCwzLjc3MyBDODcuMjEzLDEwLjY3MyA4Ni43NTEsMzUuNjYgODUuNTM5LDQzLjY1MSBDODUuMTQ5LDQ2LjIxNiA4NC4yOSw0OC44NjYgODIuNDgzLDQ5LjkzNSBMNy4yMSw5My40ODYgQzYuODk3LDkzLjY2NyA2LjU5NSw5My43NDQgNi4zMTQsOTMuNzQ0IEw2LjEzMSw5My43MzMgQzYuMTMxLDkzLjczNCAzLjM0OSw5My4yOTMgMy4xMjgsOTEuNjA5IEMyLjU2OCw4Ny4zMjcgMS45NzcsODIuODI4IDEuOTYzLDcwLjI1OCBDMS45NDgsNTcuNDc0IDIuODYsNTAuNTEzIDIuODYsNTAuNTEzIEMzLjU3LDQ2LjM2NyA1LjY0Nyw0NS4zMjEgNS42NDcsNDUuMzIxIEM1LjY0Nyw0NS4zMjEgOC4xNDgsNDMuODg3IDEyLjIzOCw0MS41NDIgTDEyLjI0NSw0MS40MTQgTDEyLjI0NSw0MS4zNzEgQzEyLjI0NSw0MS4yNTQgMTIuMjQ1LDQwLjkyNSAxMi4yNDMsNDAuNzkzIEMxMi4yNCw0MC42ODYgMTIuMzAyLDQwLjU4MyAxMi40MzQsNDAuNTA4IEwxOC40NDYsMzcuMDM2IEMxOC41NzQsMzYuOTYyIDE4Ljc0NiwzNi45MjYgMTguOTI3LDM2LjkyNiBDMTkuMTQ1LDM2LjkyNiAxOS4zNzYsMzYuOTc5IDE5LjU1NCwzNy4wODIgQzE5Ljc0NywzNy4xOTQgMTkuODM5LDM3LjM0IDE5LjgyMiwzNy40NzQgTDIwLjAzMywzNy4wNzIgQzQxLjgwNiwyNC41ODUgODAuNjM2LDIuMzE4IDgwLjc3NywyLjIzNiBDODAuODk0LDIuMTY4IDgxLjU4MywxLjcyOSA4Mi4zMTEsMS43MDEgTTgyLjMxMSwwLjcwNCBMODIuMjcyLDAuNzA1IEM4MS42NTQsMC43MjggODAuOTg5LDAuOTQ5IDgwLjI5OCwxLjM2MSBMODAuMjc3LDEuMzczIEM4MC4xMjksMS40NTggNTkuNzY4LDEzLjEzNSAxOS43NTgsMzYuMDc5IEMxOS41LDM1Ljk4MSAxOS4yMTQsMzUuOTI5IDE4LjkyNywzNS45MjkgQzE4LjU2MiwzNS45MjkgMTguMjIzLDM2LjAxMyAxNy45NDcsMzYuMTczIEwxMS45MzUsMzkuNjQ0IEMxMS40OTMsMzkuODk5IDExLjIzNiw0MC4zMzQgMTEuMjQ2LDQwLjgxIEwxMS4yNDcsNDAuOTYgTDUuMTY3LDQ0LjQ0NyBDNC43OTQsNDQuNjQ2IDIuNjI1LDQ1Ljk3OCAxLjg3Nyw1MC4zNDUgTDEuODcxLDUwLjM4NCBDMS44NjIsNTAuNDU0IDAuOTUxLDU3LjU1NyAwLjk2NSw3MC4yNTkgQzAuOTc5LDgyLjg3OSAxLjU2OCw4Ny4zNzUgMi4xMzcsOTEuNzI0IEwyLjEzOSw5MS43MzkgQzIuNDQ3LDk0LjA5NCA1LjYxNCw5NC42NjIgNS45NzUsOTQuNzE5IEw2LjAwOSw5NC43MjMgQzYuMTEsOTQuNzM2IDYuMjEzLDk0Ljc0MiA2LjMxNCw5NC43NDIgQzYuNzksOTQuNzQyIDcuMjYsOTQuNjEgNy43MSw5NC4zNSBMODIuOTgzLDUwLjc5OCBDODQuNzk0LDQ5LjcyNyA4NS45ODIsNDcuMzc1IDg2LjUyNSw0My44MDEgQzg3LjcxMSwzNS45ODcgODguMjU5LDEwLjcwNSA4Ni4yMjQsMy41MDIgQzg1Ljk3MSwyLjYwOSA4NS41MiwxLjk3NSA4NC44ODEsMS42MiBMODQuNzQ5LDEuNTU4IEw4Mi42NjQsMC43NjkgQzgyLjU1MSwwLjcyNSA4Mi40MzEsMC43MDQgODIuMzExLDAuNzA0IiBpZD0iRmlsbC0yIiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTY2LjI2NywxMS41NjUgTDY3Ljc2MiwxMS45OTkgTDExLjQyMyw0NC4zMjUiIGlkPSJGaWxsLTMiIGZpbGw9IiNGRkZGRkYiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTIuMjAyLDkwLjU0NSBDMTIuMDI5LDkwLjU0NSAxMS44NjIsOTAuNDU1IDExLjc2OSw5MC4yOTUgQzExLjYzMiw5MC4wNTcgMTEuNzEzLDg5Ljc1MiAxMS45NTIsODkuNjE0IEwzMC4zODksNzguOTY5IEMzMC42MjgsNzguODMxIDMwLjkzMyw3OC45MTMgMzEuMDcxLDc5LjE1MiBDMzEuMjA4LDc5LjM5IDMxLjEyNyw3OS42OTYgMzAuODg4LDc5LjgzMyBMMTIuNDUxLDkwLjQ3OCBMMTIuMjAyLDkwLjU0NSIgaWQ9IkZpbGwtNCIgZmlsbD0iIzYwN0Q4QiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMy43NjQsNDIuNjU0IEwxMy42NTYsNDIuNTkyIEwxMy43MDIsNDIuNDIxIEwxOC44MzcsMzkuNDU3IEwxOS4wMDcsMzkuNTAyIEwxOC45NjIsMzkuNjczIEwxMy44MjcsNDIuNjM3IEwxMy43NjQsNDIuNjU0IiBpZD0iRmlsbC01IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTguNTIsOTAuMzc1IEw4LjUyLDQ2LjQyMSBMOC41ODMsNDYuMzg1IEw3NS44NCw3LjU1NCBMNzUuODQsNTEuNTA4IEw3NS43NzgsNTEuNTQ0IEw4LjUyLDkwLjM3NSBMOC41Miw5MC4zNzUgWiBNOC43Nyw0Ni41NjQgTDguNzcsODkuOTQ0IEw3NS41OTEsNTEuMzY1IEw3NS41OTEsNy45ODUgTDguNzcsNDYuNTY0IEw4Ljc3LDQ2LjU2NCBaIiBpZD0iRmlsbC02IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTI0Ljk4Niw4My4xODIgQzI0Ljc1Niw4My4zMzEgMjQuMzc0LDgzLjU2NiAyNC4xMzcsODMuNzA1IEwxMi42MzIsOTAuNDA2IEMxMi4zOTUsOTAuNTQ1IDEyLjQyNiw5MC42NTggMTIuNyw5MC42NTggTDEzLjI2NSw5MC42NTggQzEzLjU0LDkwLjY1OCAxMy45NTgsOTAuNTQ1IDE0LjE5NSw5MC40MDYgTDI1LjcsODMuNzA1IEMyNS45MzcsODMuNTY2IDI2LjEyOCw4My40NTIgMjYuMTI1LDgzLjQ0OSBDMjYuMTIyLDgzLjQ0NyAyNi4xMTksODMuMjIgMjYuMTE5LDgyLjk0NiBDMjYuMTE5LDgyLjY3MiAyNS45MzEsODIuNTY5IDI1LjcwMSw4Mi43MTkgTDI0Ljk4Niw4My4xODIiIGlkPSJGaWxsLTciIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTMuMjY2LDkwLjc4MiBMMTIuNyw5MC43ODIgQzEyLjUsOTAuNzgyIDEyLjM4NCw5MC43MjYgMTIuMzU0LDkwLjYxNiBDMTIuMzI0LDkwLjUwNiAxMi4zOTcsOTAuMzk5IDEyLjU2OSw5MC4yOTkgTDI0LjA3NCw4My41OTcgQzI0LjMxLDgzLjQ1OSAyNC42ODksODMuMjI2IDI0LjkxOCw4My4wNzggTDI1LjYzMyw4Mi42MTQgQzI1LjcyMyw4Mi41NTUgMjUuODEzLDgyLjUyNSAyNS44OTksODIuNTI1IEMyNi4wNzEsODIuNTI1IDI2LjI0NCw4Mi42NTUgMjYuMjQ0LDgyLjk0NiBDMjYuMjQ0LDgzLjE2IDI2LjI0NSw4My4zMDkgMjYuMjQ3LDgzLjM4MyBMMjYuMjUzLDgzLjM4NyBMMjYuMjQ5LDgzLjQ1NiBDMjYuMjQ2LDgzLjUzMSAyNi4yNDYsODMuNTMxIDI1Ljc2Myw4My44MTIgTDE0LjI1OCw5MC41MTQgQzE0LDkwLjY2NSAxMy41NjQsOTAuNzgyIDEzLjI2Niw5MC43ODIgTDEzLjI2Niw5MC43ODIgWiBNMTIuNjY2LDkwLjUzMiBMMTIuNyw5MC41MzMgTDEzLjI2Niw5MC41MzMgQzEzLjUxOCw5MC41MzMgMTMuOTE1LDkwLjQyNSAxNC4xMzIsOTAuMjk5IEwyNS42MzcsODMuNTk3IEMyNS44MDUsODMuNDk5IDI1LjkzMSw4My40MjQgMjUuOTk4LDgzLjM4MyBDMjUuOTk0LDgzLjI5OSAyNS45OTQsODMuMTY1IDI1Ljk5NCw4Mi45NDYgTDI1Ljg5OSw4Mi43NzUgTDI1Ljc2OCw4Mi44MjQgTDI1LjA1NCw4My4yODcgQzI0LjgyMiw4My40MzcgMjQuNDM4LDgzLjY3MyAyNC4yLDgzLjgxMiBMMTIuNjk1LDkwLjUxNCBMMTIuNjY2LDkwLjUzMiBMMTIuNjY2LDkwLjUzMiBaIiBpZD0iRmlsbC04IiBmaWxsPSIjNjA3RDhCIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTEzLjI2Niw4OS44NzEgTDEyLjcsODkuODcxIEMxMi41LDg5Ljg3MSAxMi4zODQsODkuODE1IDEyLjM1NCw4OS43MDUgQzEyLjMyNCw4OS41OTUgMTIuMzk3LDg5LjQ4OCAxMi41NjksODkuMzg4IEwyNC4wNzQsODIuNjg2IEMyNC4zMzIsODIuNTM1IDI0Ljc2OCw4Mi40MTggMjUuMDY3LDgyLjQxOCBMMjUuNjMyLDgyLjQxOCBDMjUuODMyLDgyLjQxOCAyNS45NDgsODIuNDc0IDI1Ljk3OCw4Mi41ODQgQzI2LjAwOCw4Mi42OTQgMjUuOTM1LDgyLjgwMSAyNS43NjMsODIuOTAxIEwxNC4yNTgsODkuNjAzIEMxNCw4OS43NTQgMTMuNTY0LDg5Ljg3MSAxMy4yNjYsODkuODcxIEwxMy4yNjYsODkuODcxIFogTTEyLjY2Niw4OS42MjEgTDEyLjcsODkuNjIyIEwxMy4yNjYsODkuNjIyIEMxMy41MTgsODkuNjIyIDEzLjkxNSw4OS41MTUgMTQuMTMyLDg5LjM4OCBMMjUuNjM3LDgyLjY4NiBMMjUuNjY3LDgyLjY2OCBMMjUuNjMyLDgyLjY2NyBMMjUuMDY3LDgyLjY2NyBDMjQuODE1LDgyLjY2NyAyNC40MTgsODIuNzc1IDI0LjIsODIuOTAxIEwxMi42OTUsODkuNjAzIEwxMi42NjYsODkuNjIxIEwxMi42NjYsODkuNjIxIFoiIGlkPSJGaWxsLTkiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTIuMzcsOTAuODAxIEwxMi4zNyw4OS41NTQgTDEyLjM3LDkwLjgwMSIgaWQ9IkZpbGwtMTAiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNi4xMyw5My45MDEgQzUuMzc5LDkzLjgwOCA0LjgxNiw5My4xNjQgNC42OTEsOTIuNTI1IEMzLjg2LDg4LjI4NyAzLjU0LDgzLjc0MyAzLjUyNiw3MS4xNzMgQzMuNTExLDU4LjM4OSA0LjQyMyw1MS40MjggNC40MjMsNTEuNDI4IEM1LjEzNCw0Ny4yODIgNy4yMSw0Ni4yMzYgNy4yMSw0Ni4yMzYgQzcuMjEsNDYuMjM2IDgxLjY2NywzLjI1IDgyLjA2OSwzLjAxNyBDODIuMjkyLDIuODg4IDg0LjU1NiwxLjQzMyA4NS4yNjQsMy45NCBDODcuMjE0LDEwLjg0IDg2Ljc1MiwzNS44MjcgODUuNTM5LDQzLjgxOCBDODUuMTUsNDYuMzgzIDg0LjI5MSw0OS4wMzMgODIuNDgzLDUwLjEwMSBMNy4yMSw5My42NTMgQzYuODI4LDkzLjg3NCA2LjQ2MSw5My45NDEgNi4xMyw5My45MDEgQzYuMTMsOTMuOTAxIDMuMzQ5LDkzLjQ2IDMuMTI5LDkxLjc3NiBDMi41NjgsODcuNDk1IDEuOTc3LDgyLjk5NSAxLjk2Miw3MC40MjUgQzEuOTQ4LDU3LjY0MSAyLjg2LDUwLjY4IDIuODYsNTAuNjggQzMuNTcsNDYuNTM0IDUuNjQ3LDQ1LjQ4OSA1LjY0Nyw0NS40ODkgQzUuNjQ2LDQ1LjQ4OSA4LjA2NSw0NC4wOTIgMTIuMjQ1LDQxLjY3OSBMMTMuMTE2LDQxLjU2IEwxOS43MTUsMzcuNzMgTDE5Ljc2MSwzNy4yNjkgTDYuMTMsOTMuOTAxIiBpZD0iRmlsbC0xMSIgZmlsbD0iI0ZBRkFGQSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik02LjMxNyw5NC4xNjEgTDYuMTAyLDk0LjE0OCBMNi4xMDEsOTQuMTQ4IEw1Ljg1Nyw5NC4xMDEgQzUuMTM4LDkzLjk0NSAzLjA4NSw5My4zNjUgMi44ODEsOTEuODA5IEMyLjMxMyw4Ny40NjkgMS43MjcsODIuOTk2IDEuNzEzLDcwLjQyNSBDMS42OTksNTcuNzcxIDIuNjA0LDUwLjcxOCAyLjYxMyw1MC42NDggQzMuMzM4LDQ2LjQxNyA1LjQ0NSw0NS4zMSA1LjUzNSw0NS4yNjYgTDEyLjE2Myw0MS40MzkgTDEzLjAzMyw0MS4zMiBMMTkuNDc5LDM3LjU3OCBMMTkuNTEzLDM3LjI0NCBDMTkuNTI2LDM3LjEwNyAxOS42NDcsMzcuMDA4IDE5Ljc4NiwzNy4wMjEgQzE5LjkyMiwzNy4wMzQgMjAuMDIzLDM3LjE1NiAyMC4wMDksMzcuMjkzIEwxOS45NSwzNy44ODIgTDEzLjE5OCw0MS44MDEgTDEyLjMyOCw0MS45MTkgTDUuNzcyLDQ1LjcwNCBDNS43NDEsNDUuNzIgMy43ODIsNDYuNzcyIDMuMTA2LDUwLjcyMiBDMy4wOTksNTAuNzgyIDIuMTk4LDU3LjgwOCAyLjIxMiw3MC40MjQgQzIuMjI2LDgyLjk2MyAyLjgwOSw4Ny40MiAzLjM3Myw5MS43MjkgQzMuNDY0LDkyLjQyIDQuMDYyLDkyLjg4MyA0LjY4Miw5My4xODEgQzQuNTY2LDkyLjk4NCA0LjQ4Niw5Mi43NzYgNC40NDYsOTIuNTcyIEMzLjY2NSw4OC41ODggMy4yOTEsODQuMzcgMy4yNzYsNzEuMTczIEMzLjI2Miw1OC41MiA0LjE2Nyw1MS40NjYgNC4xNzYsNTEuMzk2IEM0LjkwMSw0Ny4xNjUgNy4wMDgsNDYuMDU5IDcuMDk4LDQ2LjAxNCBDNy4wOTQsNDYuMDE1IDgxLjU0MiwzLjAzNCA4MS45NDQsMi44MDIgTDgxLjk3MiwyLjc4NSBDODIuODc2LDIuMjQ3IDgzLjY5MiwyLjA5NyA4NC4zMzIsMi4zNTIgQzg0Ljg4NywyLjU3MyA4NS4yODEsMy4wODUgODUuNTA0LDMuODcyIEM4Ny41MTgsMTEgODYuOTY0LDM2LjA5MSA4NS43ODUsNDMuODU1IEM4NS4yNzgsNDcuMTk2IDg0LjIxLDQ5LjM3IDgyLjYxLDUwLjMxNyBMNy4zMzUsOTMuODY5IEM2Ljk5OSw5NC4wNjMgNi42NTgsOTQuMTYxIDYuMzE3LDk0LjE2MSBMNi4zMTcsOTQuMTYxIFogTTYuMTcsOTMuNjU0IEM2LjQ2Myw5My42OSA2Ljc3NCw5My42MTcgNy4wODUsOTMuNDM3IEw4Mi4zNTgsNDkuODg2IEM4NC4xODEsNDguODA4IDg0Ljk2LDQ1Ljk3MSA4NS4yOTIsNDMuNzggQzg2LjQ2NiwzNi4wNDkgODcuMDIzLDExLjA4NSA4NS4wMjQsNC4wMDggQzg0Ljg0NiwzLjM3NyA4NC41NTEsMi45NzYgODQuMTQ4LDIuODE2IEM4My42NjQsMi42MjMgODIuOTgyLDIuNzY0IDgyLjIyNywzLjIxMyBMODIuMTkzLDMuMjM0IEM4MS43OTEsMy40NjYgNy4zMzUsNDYuNDUyIDcuMzM1LDQ2LjQ1MiBDNy4zMDQsNDYuNDY5IDUuMzQ2LDQ3LjUyMSA0LjY2OSw1MS40NzEgQzQuNjYyLDUxLjUzIDMuNzYxLDU4LjU1NiAzLjc3NSw3MS4xNzMgQzMuNzksODQuMzI4IDQuMTYxLDg4LjUyNCA0LjkzNiw5Mi40NzYgQzUuMDI2LDkyLjkzNyA1LjQxMiw5My40NTkgNS45NzMsOTMuNjE1IEM2LjA4Nyw5My42NCA2LjE1OCw5My42NTIgNi4xNjksOTMuNjU0IEw2LjE3LDkzLjY1NCBMNi4xNyw5My42NTQgWiIgaWQ9IkZpbGwtMTIiIGZpbGw9IiM0NTVBNjQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNy4zMTcsNjguOTgyIEM3LjgwNiw2OC43MDEgOC4yMDIsNjguOTI2IDguMjAyLDY5LjQ4NyBDOC4yMDIsNzAuMDQ3IDcuODA2LDcwLjczIDcuMzE3LDcxLjAxMiBDNi44MjksNzEuMjk0IDYuNDMzLDcxLjA2OSA2LjQzMyw3MC41MDggQzYuNDMzLDY5Ljk0OCA2LjgyOSw2OS4yNjUgNy4zMTcsNjguOTgyIiBpZD0iRmlsbC0xMyIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik02LjkyLDcxLjEzMyBDNi42MzEsNzEuMTMzIDYuNDMzLDcwLjkwNSA2LjQzMyw3MC41MDggQzYuNDMzLDY5Ljk0OCA2LjgyOSw2OS4yNjUgNy4zMTcsNjguOTgyIEM3LjQ2LDY4LjkgNy41OTUsNjguODYxIDcuNzE0LDY4Ljg2MSBDOC4wMDMsNjguODYxIDguMjAyLDY5LjA5IDguMjAyLDY5LjQ4NyBDOC4yMDIsNzAuMDQ3IDcuODA2LDcwLjczIDcuMzE3LDcxLjAxMiBDNy4xNzQsNzEuMDk0IDcuMDM5LDcxLjEzMyA2LjkyLDcxLjEzMyBNNy43MTQsNjguNjc0IEM3LjU1Nyw2OC42NzQgNy4zOTIsNjguNzIzIDcuMjI0LDY4LjgyMSBDNi42NzYsNjkuMTM4IDYuMjQ2LDY5Ljg3OSA2LjI0Niw3MC41MDggQzYuMjQ2LDcwLjk5NCA2LjUxNyw3MS4zMiA2LjkyLDcxLjMyIEM3LjA3OCw3MS4zMiA3LjI0Myw3MS4yNzEgNy40MTEsNzEuMTc0IEM3Ljk1OSw3MC44NTcgOC4zODksNzAuMTE3IDguMzg5LDY5LjQ4NyBDOC4zODksNjkuMDAxIDguMTE3LDY4LjY3NCA3LjcxNCw2OC42NzQiIGlkPSJGaWxsLTE0IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTYuOTIsNzAuOTQ3IEM2LjY0OSw3MC45NDcgNi42MjEsNzAuNjQgNi42MjEsNzAuNTA4IEM2LjYyMSw3MC4wMTcgNi45ODIsNjkuMzkyIDcuNDExLDY5LjE0NSBDNy41MjEsNjkuMDgyIDcuNjI1LDY5LjA0OSA3LjcxNCw2OS4wNDkgQzcuOTg2LDY5LjA0OSA4LjAxNSw2OS4zNTUgOC4wMTUsNjkuNDg3IEM4LjAxNSw2OS45NzggNy42NTIsNzAuNjAzIDcuMjI0LDcwLjg1MSBDNy4xMTUsNzAuOTE0IDcuMDEsNzAuOTQ3IDYuOTIsNzAuOTQ3IE03LjcxNCw2OC44NjEgQzcuNTk1LDY4Ljg2MSA3LjQ2LDY4LjkgNy4zMTcsNjguOTgyIEM2LjgyOSw2OS4yNjUgNi40MzMsNjkuOTQ4IDYuNDMzLDcwLjUwOCBDNi40MzMsNzAuOTA1IDYuNjMxLDcxLjEzMyA2LjkyLDcxLjEzMyBDNy4wMzksNzEuMTMzIDcuMTc0LDcxLjA5NCA3LjMxNyw3MS4wMTIgQzcuODA2LDcwLjczIDguMjAyLDcwLjA0NyA4LjIwMiw2OS40ODcgQzguMjAyLDY5LjA5IDguMDAzLDY4Ljg2MSA3LjcxNCw2OC44NjEiIGlkPSJGaWxsLTE1IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTcuNDQ0LDg1LjM1IEM3LjcwOCw4NS4xOTggNy45MjEsODUuMzE5IDcuOTIxLDg1LjYyMiBDNy45MjEsODUuOTI1IDcuNzA4LDg2LjI5MiA3LjQ0NCw4Ni40NDQgQzcuMTgxLDg2LjU5NyA2Ljk2Nyw4Ni40NzUgNi45NjcsODYuMTczIEM2Ljk2Nyw4NS44NzEgNy4xODEsODUuNTAyIDcuNDQ0LDg1LjM1IiBpZD0iRmlsbC0xNiIgZmlsbD0iI0ZGRkZGRiI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik03LjIzLDg2LjUxIEM3LjA3NCw4Ni41MSA2Ljk2Nyw4Ni4zODcgNi45NjcsODYuMTczIEM2Ljk2Nyw4NS44NzEgNy4xODEsODUuNTAyIDcuNDQ0LDg1LjM1IEM3LjUyMSw4NS4zMDUgNy41OTQsODUuMjg0IDcuNjU4LDg1LjI4NCBDNy44MTQsODUuMjg0IDcuOTIxLDg1LjQwOCA3LjkyMSw4NS42MjIgQzcuOTIxLDg1LjkyNSA3LjcwOCw4Ni4yOTIgNy40NDQsODYuNDQ0IEM3LjM2Nyw4Ni40ODkgNy4yOTQsODYuNTEgNy4yMyw4Ni41MSBNNy42NTgsODUuMDk4IEM3LjU1OCw4NS4wOTggNy40NTUsODUuMTI3IDcuMzUxLDg1LjE4OCBDNy4wMzEsODUuMzczIDYuNzgxLDg1LjgwNiA2Ljc4MSw4Ni4xNzMgQzYuNzgxLDg2LjQ4MiA2Ljk2Niw4Ni42OTcgNy4yMyw4Ni42OTcgQzcuMzMsODYuNjk3IDcuNDMzLDg2LjY2NiA3LjUzOCw4Ni42MDcgQzcuODU4LDg2LjQyMiA4LjEwOCw4NS45ODkgOC4xMDgsODUuNjIyIEM4LjEwOCw4NS4zMTMgNy45MjMsODUuMDk4IDcuNjU4LDg1LjA5OCIgaWQ9IkZpbGwtMTciIGZpbGw9IiM4MDk3QTIiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNy4yMyw4Ni4zMjIgTDcuMTU0LDg2LjE3MyBDNy4xNTQsODUuOTM4IDcuMzMzLDg1LjYyOSA3LjUzOCw4NS41MTIgTDcuNjU4LDg1LjQ3MSBMNy43MzQsODUuNjIyIEM3LjczNCw4NS44NTYgNy41NTUsODYuMTY0IDcuMzUxLDg2LjI4MiBMNy4yMyw4Ni4zMjIgTTcuNjU4LDg1LjI4NCBDNy41OTQsODUuMjg0IDcuNTIxLDg1LjMwNSA3LjQ0NCw4NS4zNSBDNy4xODEsODUuNTAyIDYuOTY3LDg1Ljg3MSA2Ljk2Nyw4Ni4xNzMgQzYuOTY3LDg2LjM4NyA3LjA3NCw4Ni41MSA3LjIzLDg2LjUxIEM3LjI5NCw4Ni41MSA3LjM2Nyw4Ni40ODkgNy40NDQsODYuNDQ0IEM3LjcwOCw4Ni4yOTIgNy45MjEsODUuOTI1IDcuOTIxLDg1LjYyMiBDNy45MjEsODUuNDA4IDcuODE0LDg1LjI4NCA3LjY1OCw4NS4yODQiIGlkPSJGaWxsLTE4IiBmaWxsPSIjODA5N0EyIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTc3LjI3OCw3Ljc2OSBMNzcuMjc4LDUxLjQzNiBMMTAuMjA4LDkwLjE2IEwxMC4yMDgsNDYuNDkzIEw3Ny4yNzgsNy43NjkiIGlkPSJGaWxsLTE5IiBmaWxsPSIjNDU1QTY0Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTEwLjA4Myw5MC4zNzUgTDEwLjA4Myw0Ni40MjEgTDEwLjE0Niw0Ni4zODUgTDc3LjQwMyw3LjU1NCBMNzcuNDAzLDUxLjUwOCBMNzcuMzQxLDUxLjU0NCBMMTAuMDgzLDkwLjM3NSBMMTAuMDgzLDkwLjM3NSBaIE0xMC4zMzMsNDYuNTY0IEwxMC4zMzMsODkuOTQ0IEw3Ny4xNTQsNTEuMzY1IEw3Ny4xNTQsNy45ODUgTDEwLjMzMyw0Ni41NjQgTDEwLjMzMyw0Ni41NjQgWiIgaWQ9IkZpbGwtMjAiIGZpbGw9IiM2MDdEOEIiPjwvcGF0aD4KICAgICAgICAgICAgICAgIDwvZz4KICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xMjUuNzM3LDg4LjY0NyBMMTE4LjA5OCw5MS45ODEgTDExOC4wOTgsODQgTDEwNi42MzksODguNzEzIEwxMDYuNjM5LDk2Ljk4MiBMOTksMTAwLjMxNSBMMTEyLjM2OSwxMDMuOTYxIEwxMjUuNzM3LDg4LjY0NyIgaWQ9IkltcG9ydGVkLUxheWVycy1Db3B5LTIiIGZpbGw9IiM0NTVBNjQiIHNrZXRjaDp0eXBlPSJNU1NoYXBlR3JvdXAiPjwvcGF0aD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+');
|
|
};
|
|
|
|
module.exports = RotateInstructions;
|
|
|
|
},{"./util.js":29}],24:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var SensorSample = _dereq_('./sensor-sample.js');
|
|
var MathUtil = _dereq_('../math-util.js');
|
|
var Util = _dereq_('../util.js');
|
|
|
|
/**
|
|
* An implementation of a simple complementary filter, which fuses gyroscope and
|
|
* accelerometer data from the 'devicemotion' event.
|
|
*
|
|
* Accelerometer data is very noisy, but stable over the long term.
|
|
* Gyroscope data is smooth, but tends to drift over the long term.
|
|
*
|
|
* This fusion is relatively simple:
|
|
* 1. Get orientation estimates from accelerometer by applying a low-pass filter
|
|
* on that data.
|
|
* 2. Get orientation estimates from gyroscope by integrating over time.
|
|
* 3. Combine the two estimates, weighing (1) in the long term, but (2) for the
|
|
* short term.
|
|
*/
|
|
function ComplementaryFilter(kFilter) {
|
|
this.kFilter = kFilter;
|
|
|
|
// Raw sensor measurements.
|
|
this.currentAccelMeasurement = new SensorSample();
|
|
this.currentGyroMeasurement = new SensorSample();
|
|
this.previousGyroMeasurement = new SensorSample();
|
|
|
|
// Set default look direction to be in the correct direction.
|
|
if (Util.isIOS()) {
|
|
this.filterQ = new MathUtil.Quaternion(-1, 0, 0, 1);
|
|
} else {
|
|
this.filterQ = new MathUtil.Quaternion(1, 0, 0, 1);
|
|
}
|
|
this.previousFilterQ = new MathUtil.Quaternion();
|
|
this.previousFilterQ.copy(this.filterQ);
|
|
|
|
// Orientation based on the accelerometer.
|
|
this.accelQ = new MathUtil.Quaternion();
|
|
// Whether or not the orientation has been initialized.
|
|
this.isOrientationInitialized = false;
|
|
// Running estimate of gravity based on the current orientation.
|
|
this.estimatedGravity = new MathUtil.Vector3();
|
|
// Measured gravity based on accelerometer.
|
|
this.measuredGravity = new MathUtil.Vector3();
|
|
|
|
// Debug only quaternion of gyro-based orientation.
|
|
this.gyroIntegralQ = new MathUtil.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 (Util.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;
|
|
|
|
// Convert gyro rotation vector to a quaternion delta.
|
|
var gyroDeltaQ = this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample, deltaT);
|
|
this.gyroIntegralQ.multiply(gyroDeltaQ);
|
|
|
|
// filter_1 = K * (filter_0 + gyro * dT) + (1 - K) * accel.
|
|
this.filterQ.copy(this.previousFilterQ);
|
|
this.filterQ.multiply(gyroDeltaQ);
|
|
|
|
// Calculate the delta between the current estimated gravity and the real
|
|
// gravity vector from accelerometer.
|
|
var invFilterQ = new MathUtil.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();
|
|
|
|
// Compare estimated gravity with measured gravity, get the delta quaternion
|
|
// between the two.
|
|
var deltaQ = new MathUtil.Quaternion();
|
|
deltaQ.setFromUnitVectors(this.estimatedGravity, this.measuredGravity);
|
|
deltaQ.inverse();
|
|
|
|
if (Util.isDebug()) {
|
|
console.log('Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)',
|
|
MathUtil.radToDeg * Util.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));
|
|
}
|
|
|
|
// Calculate the SLERP target: current orientation plus the measured-estimated
|
|
// quaternion delta.
|
|
var targetQ = new MathUtil.Quaternion();
|
|
targetQ.copy(this.filterQ);
|
|
targetQ.multiply(deltaQ);
|
|
|
|
// SLERP factor: 0 is pure gyro, 1 is pure accel.
|
|
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 MathUtil.Vector3();
|
|
normAccel.copy(accel);
|
|
normAccel.normalize();
|
|
var quat = new MathUtil.Quaternion();
|
|
quat.setFromUnitVectors(new MathUtil.Vector3(0, 0, -1), normAccel);
|
|
quat.inverse();
|
|
return quat;
|
|
};
|
|
|
|
ComplementaryFilter.prototype.gyroToQuaternionDelta_ = function(gyro, dt) {
|
|
// Extract axis and angle from the gyroscope data.
|
|
var quat = new MathUtil.Quaternion();
|
|
var axis = new MathUtil.Vector3();
|
|
axis.copy(gyro);
|
|
axis.normalize();
|
|
quat.setFromAxisAngle(axis, gyro.length() * dt);
|
|
return quat;
|
|
};
|
|
|
|
|
|
module.exports = ComplementaryFilter;
|
|
|
|
},{"../math-util.js":20,"../util.js":29,"./sensor-sample.js":27}],25:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
var ComplementaryFilter = _dereq_('./complementary-filter.js');
|
|
var PosePredictor = _dereq_('./pose-predictor.js');
|
|
var TouchPanner = _dereq_('../touch-panner.js');
|
|
var MathUtil = _dereq_('../math-util.js');
|
|
var Util = _dereq_('../util.js');
|
|
|
|
/**
|
|
* The pose sensor, implemented using DeviceMotion APIs.
|
|
*/
|
|
function FusionPoseSensor() {
|
|
this.deviceId = 'webvr-polyfill:fused';
|
|
this.deviceName = 'VR Position Device (webvr-polyfill:fused)';
|
|
|
|
this.accelerometer = new MathUtil.Vector3();
|
|
this.gyroscope = new MathUtil.Vector3();
|
|
|
|
this.start();
|
|
|
|
this.filter = new ComplementaryFilter(window.WebVRConfig.K_FILTER);
|
|
this.posePredictor = new PosePredictor(window.WebVRConfig.PREDICTION_TIME_S);
|
|
this.touchPanner = new TouchPanner();
|
|
|
|
this.filterToWorldQ = new MathUtil.Quaternion();
|
|
|
|
// Set the filter to world transform, depending on OS.
|
|
if (Util.isIOS()) {
|
|
this.filterToWorldQ.setFromAxisAngle(new MathUtil.Vector3(1, 0, 0), Math.PI / 2);
|
|
} else {
|
|
this.filterToWorldQ.setFromAxisAngle(new MathUtil.Vector3(1, 0, 0), -Math.PI / 2);
|
|
}
|
|
|
|
this.inverseWorldToScreenQ = new MathUtil.Quaternion();
|
|
this.worldToScreenQ = new MathUtil.Quaternion();
|
|
this.originalPoseAdjustQ = new MathUtil.Quaternion();
|
|
this.originalPoseAdjustQ.setFromAxisAngle(new MathUtil.Vector3(0, 0, 1),
|
|
-window.orientation * Math.PI / 180);
|
|
|
|
this.setScreenTransform_();
|
|
// Adjust this filter for being in landscape mode.
|
|
if (Util.isLandscapeMode()) {
|
|
this.filterToWorldQ.multiply(this.inverseWorldToScreenQ);
|
|
}
|
|
|
|
// Keep track of a reset transform for resetSensor.
|
|
this.resetQ = new MathUtil.Quaternion();
|
|
|
|
this.isFirefoxAndroid = Util.isFirefoxAndroid();
|
|
this.isIOS = Util.isIOS();
|
|
|
|
this.orientationOut_ = new Float32Array(4);
|
|
}
|
|
|
|
FusionPoseSensor.prototype.getPosition = function() {
|
|
// This PoseSensor doesn't support position
|
|
return null;
|
|
};
|
|
|
|
FusionPoseSensor.prototype.getOrientation = function() {
|
|
// Convert from filter space to the the same system used by the
|
|
// deviceorientation event.
|
|
var orientation = this.filter.getOrientation();
|
|
|
|
// Predict orientation.
|
|
this.predictedQ = this.posePredictor.getPrediction(orientation, this.gyroscope, this.previousTimestampS);
|
|
|
|
// Convert to THREE coordinate system: -Z forward, Y up, X right.
|
|
var out = new MathUtil.Quaternion();
|
|
out.copy(this.filterToWorldQ);
|
|
out.multiply(this.resetQ);
|
|
if (!window.WebVRConfig.TOUCH_PANNER_DISABLED) {
|
|
out.multiply(this.touchPanner.getOrientation());
|
|
}
|
|
out.multiply(this.predictedQ);
|
|
out.multiply(this.worldToScreenQ);
|
|
|
|
// Handle the yaw-only case.
|
|
if (window.WebVRConfig.YAW_ONLY) {
|
|
// Make a quaternion that only turns around the Y-axis.
|
|
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() {
|
|
// Reduce to inverted yaw-only.
|
|
this.resetQ.copy(this.filter.getOrientation());
|
|
this.resetQ.x = 0;
|
|
this.resetQ.y = 0;
|
|
this.resetQ.z *= -1;
|
|
this.resetQ.normalize();
|
|
|
|
// Take into account extra transformations in landscape mode.
|
|
if (Util.isLandscapeMode()) {
|
|
this.resetQ.multiply(this.inverseWorldToScreenQ);
|
|
}
|
|
|
|
// Take into account original pose.
|
|
this.resetQ.multiply(this.originalPoseAdjustQ);
|
|
|
|
if (!window.WebVRConfig.TOUCH_PANNER_DISABLED) {
|
|
this.touchPanner.resetSensor();
|
|
}
|
|
};
|
|
|
|
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 <= Util.MIN_TIMESTEP || deltaS > Util.MAX_TIMESTEP) {
|
|
console.warn('Invalid timestamps detected. Time step between successive ' +
|
|
'gyroscope sensor samples is very small or not monotonic');
|
|
this.previousTimestampS = timestampS;
|
|
return;
|
|
}
|
|
|
|
this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z);
|
|
if (Util.isR7()) {
|
|
this.gyroscope.set(-rotRate.beta, rotRate.alpha, rotRate.gamma);
|
|
} else {
|
|
this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma);
|
|
}
|
|
|
|
// With iOS and Firefox Android, rotationRate is reported in degrees,
|
|
// so we first convert to radians.
|
|
if (this.isIOS || this.isFirefoxAndroid) {
|
|
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_();
|
|
};
|
|
|
|
/**
|
|
* This is only needed if we are in an cross origin iframe on iOS to work around
|
|
* this issue: https://bugs.webkit.org/show_bug.cgi?id=152299.
|
|
*/
|
|
FusionPoseSensor.prototype.onMessage_ = function(event) {
|
|
var message = event.data;
|
|
|
|
// If there's no message type, ignore it.
|
|
if (!message || !message.type) {
|
|
return;
|
|
}
|
|
|
|
// Ignore all messages that aren't devicemotion.
|
|
var type = message.type.toLowerCase();
|
|
if (type !== 'devicemotion') {
|
|
return;
|
|
}
|
|
|
|
// Update device motion.
|
|
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 MathUtil.Vector3(0, 0, 1), -Math.PI / 2);
|
|
break;
|
|
case -90:
|
|
this.worldToScreenQ.setFromAxisAngle(new MathUtil.Vector3(0, 0, 1), Math.PI / 2);
|
|
break;
|
|
case 180:
|
|
// TODO.
|
|
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);
|
|
|
|
// Only listen for postMessages if we're in an iOS and embedded inside a cross
|
|
// domain IFrame. In this case, the polyfill can still work if the containing
|
|
// page sends synthetic devicemotion events. For an example of this, see
|
|
// iframe-message-sender.js in VR View: https://goo.gl/XDtvFZ
|
|
if (Util.isIOS() && Util.isInsideCrossDomainIFrame()) {
|
|
window.addEventListener('message', this.onMessageCallback_);
|
|
}
|
|
window.addEventListener('orientationchange', this.onOrientationChangeCallback_);
|
|
window.addEventListener('devicemotion', this.onDeviceMotionCallback_);
|
|
};
|
|
|
|
FusionPoseSensor.prototype.stop = function() {
|
|
window.removeEventListener('devicemotion', this.onDeviceMotionCallback_);
|
|
window.removeEventListener('orientationchange', this.onOrientationChangeCallback_);
|
|
window.removeEventListener('message', this.onMessageCallback_);
|
|
};
|
|
|
|
module.exports = FusionPoseSensor;
|
|
|
|
},{"../math-util.js":20,"../touch-panner.js":28,"../util.js":29,"./complementary-filter.js":24,"./pose-predictor.js":26}],26:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
var MathUtil = _dereq_('../math-util');
|
|
var Util = _dereq_('../util');
|
|
|
|
/**
|
|
* Given an orientation and the gyroscope data, predicts the future orientation
|
|
* of the head. This makes rendering appear faster.
|
|
*
|
|
* Also see: http://msl.cs.uiuc.edu/~lavalle/papers/LavYerKatAnt14.pdf
|
|
*
|
|
* @param {Number} predictionTimeS time from head movement to the appearance of
|
|
* the corresponding image.
|
|
*/
|
|
function PosePredictor(predictionTimeS) {
|
|
this.predictionTimeS = predictionTimeS;
|
|
|
|
// The quaternion corresponding to the previous state.
|
|
this.previousQ = new MathUtil.Quaternion();
|
|
// Previous time a prediction occurred.
|
|
this.previousTimestampS = null;
|
|
|
|
// The delta quaternion that adjusts the current pose.
|
|
this.deltaQ = new MathUtil.Quaternion();
|
|
// The output quaternion.
|
|
this.outQ = new MathUtil.Quaternion();
|
|
}
|
|
|
|
PosePredictor.prototype.getPrediction = function(currentQ, gyro, timestampS) {
|
|
if (!this.previousTimestampS) {
|
|
this.previousQ.copy(currentQ);
|
|
this.previousTimestampS = timestampS;
|
|
return currentQ;
|
|
}
|
|
|
|
// Calculate axis and angle based on gyroscope rotation rate data.
|
|
var axis = new MathUtil.Vector3();
|
|
axis.copy(gyro);
|
|
axis.normalize();
|
|
|
|
var angularSpeed = gyro.length();
|
|
|
|
// If we're rotating slowly, don't do prediction.
|
|
if (angularSpeed < MathUtil.degToRad * 20) {
|
|
if (Util.isDebug()) {
|
|
console.log('Moving slowly, at %s deg/s: no prediction',
|
|
(MathUtil.radToDeg * angularSpeed).toFixed(1));
|
|
}
|
|
this.outQ.copy(currentQ);
|
|
this.previousQ.copy(currentQ);
|
|
return this.outQ;
|
|
}
|
|
|
|
// Get the predicted angle based on the time delta and latency.
|
|
var deltaT = timestampS - this.previousTimestampS;
|
|
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;
|
|
};
|
|
|
|
|
|
module.exports = PosePredictor;
|
|
|
|
},{"../math-util":20,"../util":29}],27:[function(_dereq_,module,exports){
|
|
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);
|
|
};
|
|
|
|
module.exports = SensorSample;
|
|
|
|
},{}],28:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
var MathUtil = _dereq_('./math-util.js');
|
|
var Util = _dereq_('./util.js');
|
|
|
|
var ROTATE_SPEED = 0.5;
|
|
/**
|
|
* Provides a quaternion responsible for pre-panning the scene before further
|
|
* transformations due to device sensors.
|
|
*/
|
|
function TouchPanner() {
|
|
window.addEventListener('touchstart', this.onTouchStart_.bind(this));
|
|
window.addEventListener('touchmove', this.onTouchMove_.bind(this));
|
|
window.addEventListener('touchend', this.onTouchEnd_.bind(this));
|
|
|
|
this.isTouching = false;
|
|
this.rotateStart = new MathUtil.Vector2();
|
|
this.rotateEnd = new MathUtil.Vector2();
|
|
this.rotateDelta = new MathUtil.Vector2();
|
|
|
|
this.theta = 0;
|
|
this.orientation = new MathUtil.Quaternion();
|
|
}
|
|
|
|
TouchPanner.prototype.getOrientation = function() {
|
|
this.orientation.setFromEulerXYZ(0, 0, this.theta);
|
|
return this.orientation;
|
|
};
|
|
|
|
TouchPanner.prototype.resetSensor = function() {
|
|
this.theta = 0;
|
|
};
|
|
|
|
TouchPanner.prototype.onTouchStart_ = function(e) {
|
|
// Only respond if there is exactly one touch.
|
|
// Note that the Daydream controller passes in a `touchstart` event with
|
|
// no `touches` property, so we must check for that case too.
|
|
if (!e.touches || e.touches.length != 1) {
|
|
return;
|
|
}
|
|
this.rotateStart.set(e.touches[0].pageX, e.touches[0].pageY);
|
|
this.isTouching = true;
|
|
};
|
|
|
|
TouchPanner.prototype.onTouchMove_ = function(e) {
|
|
if (!this.isTouching) {
|
|
return;
|
|
}
|
|
this.rotateEnd.set(e.touches[0].pageX, e.touches[0].pageY);
|
|
this.rotateDelta.subVectors(this.rotateEnd, this.rotateStart);
|
|
this.rotateStart.copy(this.rotateEnd);
|
|
|
|
// On iOS, direction is inverted.
|
|
if (Util.isIOS()) {
|
|
this.rotateDelta.x *= -1;
|
|
}
|
|
|
|
var element = document.body;
|
|
this.theta += 2 * Math.PI * this.rotateDelta.x / element.clientWidth * ROTATE_SPEED;
|
|
};
|
|
|
|
TouchPanner.prototype.onTouchEnd_ = function(e) {
|
|
this.isTouching = false;
|
|
};
|
|
|
|
module.exports = TouchPanner;
|
|
|
|
},{"./math-util.js":20,"./util.js":29}],29:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Util = window.Util || {};
|
|
|
|
Util.MIN_TIMESTEP = 0.001;
|
|
Util.MAX_TIMESTEP = 1;
|
|
|
|
Util.base64 = function(mimeType, base64) {
|
|
return 'data:' + mimeType + ';base64,' + base64;
|
|
};
|
|
|
|
Util.clamp = function(value, min, max) {
|
|
return Math.min(Math.max(min, value), max);
|
|
};
|
|
|
|
Util.lerp = function(a, b, t) {
|
|
return a + ((b - a) * t);
|
|
};
|
|
|
|
/**
|
|
* Light polyfill for `Promise.race`. Returns
|
|
* a promise that resolves when the first promise
|
|
* provided resolves.
|
|
*
|
|
* @param {Array<Promise>} promises
|
|
*/
|
|
Util.race = function(promises) {
|
|
if (Promise.race) {
|
|
return Promise.race(promises);
|
|
}
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
for (var i = 0; i < promises.length; i++) {
|
|
promises[i].then(resolve, reject);
|
|
}
|
|
});
|
|
};
|
|
|
|
Util.isIOS = (function() {
|
|
var isIOS = /iPad|iPhone|iPod/.test(navigator.platform);
|
|
return function() {
|
|
return isIOS;
|
|
};
|
|
})();
|
|
|
|
Util.isWebViewAndroid = (function() {
|
|
var isWebViewAndroid = navigator.userAgent.indexOf('Version') !== -1 &&
|
|
navigator.userAgent.indexOf('Android') !== -1 &&
|
|
navigator.userAgent.indexOf('Chrome') !== -1;
|
|
return function() {
|
|
return isWebViewAndroid;
|
|
};
|
|
})();
|
|
|
|
Util.isSafari = (function() {
|
|
var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
return function() {
|
|
return isSafari;
|
|
};
|
|
})();
|
|
|
|
Util.isFirefoxAndroid = (function() {
|
|
var isFirefoxAndroid = navigator.userAgent.indexOf('Firefox') !== -1 &&
|
|
navigator.userAgent.indexOf('Android') !== -1;
|
|
return function() {
|
|
return isFirefoxAndroid;
|
|
};
|
|
})();
|
|
|
|
Util.isR7 = (function() {
|
|
var isR7 = navigator.userAgent.indexOf('R7 Build') !== -1;
|
|
return function() {
|
|
return isR7;
|
|
};
|
|
})();
|
|
|
|
Util.isLandscapeMode = function() {
|
|
var rtn = (window.orientation == 90 || window.orientation == -90);
|
|
return Util.isR7() ? !rtn : rtn;
|
|
};
|
|
|
|
// Helper method to validate the time steps of sensor timestamps.
|
|
Util.isTimestampDeltaValid = function(timestampDeltaS) {
|
|
if (isNaN(timestampDeltaS)) {
|
|
return false;
|
|
}
|
|
if (timestampDeltaS <= Util.MIN_TIMESTEP) {
|
|
return false;
|
|
}
|
|
if (timestampDeltaS > Util.MAX_TIMESTEP) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
Util.getScreenWidth = function() {
|
|
return Math.max(window.screen.width, window.screen.height) *
|
|
window.devicePixelRatio;
|
|
};
|
|
|
|
Util.getScreenHeight = function() {
|
|
return Math.min(window.screen.width, window.screen.height) *
|
|
window.devicePixelRatio;
|
|
};
|
|
|
|
Util.requestFullscreen = function(element) {
|
|
if (Util.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;
|
|
};
|
|
|
|
Util.exitFullscreen = function() {
|
|
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;
|
|
};
|
|
|
|
Util.getFullscreenElement = function() {
|
|
return document.fullscreenElement ||
|
|
document.webkitFullscreenElement ||
|
|
document.mozFullScreenElement ||
|
|
document.msFullscreenElement;
|
|
};
|
|
|
|
Util.linkProgram = function(gl, vertexSource, fragmentSource, attribLocationMap) {
|
|
// No error checking for brevity.
|
|
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;
|
|
};
|
|
|
|
Util.getProgramUniforms = function(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;
|
|
};
|
|
|
|
Util.orthoMatrix = function (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;
|
|
};
|
|
|
|
Util.copyArray = function (source, dest) {
|
|
for (var i = 0, n = source.length; i < n; i++) {
|
|
dest[i] = source[i];
|
|
}
|
|
};
|
|
|
|
Util.isMobile = function() {
|
|
var check = false;
|
|
(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
|
|
return check;
|
|
};
|
|
|
|
Util.extend = function(dest, src) {
|
|
for (var key in src) {
|
|
if (src.hasOwnProperty(key)) {
|
|
dest[key] = src[key];
|
|
}
|
|
}
|
|
|
|
return dest;
|
|
}
|
|
|
|
Util.safariCssSizeWorkaround = function(canvas) {
|
|
// TODO(smus): Remove this workaround when Safari for iOS is fixed.
|
|
// iOS only workaround (for https://bugs.webkit.org/show_bug.cgi?id=152556).
|
|
//
|
|
// "To the last I grapple with thee;
|
|
// from hell's heart I stab at thee;
|
|
// for hate's sake I spit my last breath at thee."
|
|
// -- Moby Dick, by Herman Melville
|
|
if (Util.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);
|
|
}
|
|
|
|
// Debug only.
|
|
window.Util = Util;
|
|
window.canvas = canvas;
|
|
};
|
|
|
|
Util.isDebug = function() {
|
|
return Util.getQueryParameter('debug');
|
|
};
|
|
|
|
Util.getQueryParameter = function(name) {
|
|
var name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
|
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
|
|
results = regex.exec(location.search);
|
|
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
|
|
};
|
|
|
|
Util.frameDataFromPose = (function() {
|
|
var piOver180 = Math.PI / 180.0;
|
|
var rad45 = Math.PI * 0.25;
|
|
|
|
// Borrowed from glMatrix.
|
|
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) {
|
|
// Quaternion math
|
|
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,
|
|
|
|
// Calculate the determinant
|
|
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, parameters, vrDisplay) {
|
|
mat4_perspectiveFromFieldOfView(projection, parameters ? parameters.fieldOfView : null, vrDisplay.depthNear, vrDisplay.depthFar);
|
|
|
|
var orientation = pose.orientation || defaultOrientation;
|
|
var position = pose.position || defaultPosition;
|
|
|
|
mat4_fromRotationTranslation(view, orientation, position);
|
|
if (parameters)
|
|
mat4_translate(view, view, parameters.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.getEyeParameters("left"), vrDisplay);
|
|
updateEyeMatrices(
|
|
frameData.rightProjectionMatrix, frameData.rightViewMatrix,
|
|
pose, vrDisplay.getEyeParameters("right"), vrDisplay);
|
|
|
|
return true;
|
|
};
|
|
})();
|
|
|
|
Util.isInsideCrossDomainIFrame = function() {
|
|
var isFramed = (window.self !== window.top);
|
|
var refDomain = Util.getDomainFromUrl(document.referrer);
|
|
var thisDomain = Util.getDomainFromUrl(window.location.href);
|
|
|
|
return isFramed && (refDomain !== thisDomain);
|
|
};
|
|
|
|
// From http://stackoverflow.com/a/23945027.
|
|
Util.getDomainFromUrl = function(url) {
|
|
var domain;
|
|
// Find & remove protocol (http, ftp, etc.) and get domain.
|
|
if (url.indexOf("://") > -1) {
|
|
domain = url.split('/')[2];
|
|
}
|
|
else {
|
|
domain = url.split('/')[0];
|
|
}
|
|
|
|
//find & remove port number
|
|
domain = domain.split(':')[0];
|
|
|
|
return domain;
|
|
}
|
|
|
|
module.exports = Util;
|
|
|
|
},{}],30:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var DeviceInfo = _dereq_('./device-info.js');
|
|
var Util = _dereq_('./util.js');
|
|
|
|
var DEFAULT_VIEWER = 'CardboardV1';
|
|
var VIEWER_KEY = 'WEBVR_CARDBOARD_VIEWER';
|
|
var CLASS_NAME = 'webvr-polyfill-viewer-selector';
|
|
|
|
/**
|
|
* Creates a viewer selector with the options specified. Supports being shown
|
|
* and hidden. Generates events when viewer parameters change. Also supports
|
|
* saving the currently selected index in localStorage.
|
|
*/
|
|
function ViewerSelector() {
|
|
// Try to load the selected key from local storage.
|
|
try {
|
|
this.selectedKey = localStorage.getItem(VIEWER_KEY);
|
|
} catch (error) {
|
|
console.error('Failed to load viewer profile: %s', error);
|
|
}
|
|
|
|
//If none exists, or if localstorage is unavailable, use the default key.
|
|
if (!this.selectedKey) {
|
|
this.selectedKey = 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);
|
|
|
|
// Ensure the currently selected item is checked.
|
|
var selected = this.dialog.querySelector('#' + this.selectedKey);
|
|
selected.checked = true;
|
|
|
|
// Show the UI.
|
|
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]);
|
|
|
|
// Attempt to save the viewer profile, but fails in private mode.
|
|
try {
|
|
localStorage.setItem(VIEWER_KEY, this.selectedKey);
|
|
} catch(error) {
|
|
console.error('Failed to save viewer profile: %s', error);
|
|
}
|
|
this.hide();
|
|
};
|
|
|
|
/**
|
|
* Creates the dialog.
|
|
*/
|
|
ViewerSelector.prototype.createDialog_ = function(options) {
|
|
var container = document.createElement('div');
|
|
container.classList.add(CLASS_NAME);
|
|
container.style.display = 'none';
|
|
// Create an overlay that dims the background, and which goes away when you
|
|
// tap it.
|
|
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) {
|
|
/*
|
|
<div class="choice">
|
|
<input id="v1" type="radio" name="field" value="v1">
|
|
<label for="v1">Cardboard V1</label>
|
|
</div>
|
|
*/
|
|
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;
|
|
};
|
|
|
|
module.exports = ViewerSelector;
|
|
|
|
},{"./device-info.js":14,"./util.js":29}],31:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Util = _dereq_('./util.js');
|
|
|
|
/**
|
|
* Android and iOS compatible wakelock implementation.
|
|
*
|
|
* Refactored thanks to dkovalev@.
|
|
*/
|
|
function AndroidWakeLock() {
|
|
var video = document.createElement('video');
|
|
video.setAttribute('loop', '');
|
|
|
|
function addSourceToVideo(element, type, dataURI) {
|
|
var source = document.createElement('source');
|
|
source.src = dataURI;
|
|
source.type = 'video/' + type;
|
|
element.appendChild(source);
|
|
}
|
|
|
|
addSourceToVideo(video,'webm', Util.base64('video/webm', 'GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA='));
|
|
addSourceToVideo(video, 'mp4', Util.base64('video/mp4', 'AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAAG21kYXQAAAGzABAHAAABthADAowdbb9/AAAC6W1vb3YAAABsbXZoZAAAAAB8JbCAfCWwgAAAA+gAAAAAAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIVdHJhawAAAFx0a2hkAAAAD3wlsIB8JbCAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAIAAAACAAAAAABsW1kaWEAAAAgbWRoZAAAAAB8JbCAfCWwgAAAA+gAAAAAVcQAAAAAAC1oZGxyAAAAAAAAAAB2aWRlAAAAAAAAAAAAAAAAVmlkZW9IYW5kbGVyAAAAAVxtaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAEcc3RibAAAALhzdHNkAAAAAAAAAAEAAACobXA0dgAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAIAAgASAAAAEgAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABj//wAAAFJlc2RzAAAAAANEAAEABDwgEQAAAAADDUAAAAAABS0AAAGwAQAAAbWJEwAAAQAAAAEgAMSNiB9FAEQBFGMAAAGyTGF2YzUyLjg3LjQGAQIAAAAYc3R0cwAAAAAAAAABAAAAAQAAAAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAEAAAABAAAAFHN0c3oAAAAAAAAAEwAAAAEAAAAUc3RjbwAAAAAAAAABAAAALAAAAGB1ZHRhAAAAWG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAK2lsc3QAAAAjqXRvbwAAABtkYXRhAAAAAQAAAABMYXZmNTIuNzguMw=='));
|
|
|
|
this.request = function() {
|
|
if (video.paused) {
|
|
video.play();
|
|
}
|
|
};
|
|
|
|
this.release = function() {
|
|
video.pause();
|
|
};
|
|
}
|
|
|
|
function iOSWakeLock() {
|
|
var timer = null;
|
|
|
|
this.request = function() {
|
|
if (!timer) {
|
|
timer = setInterval(function() {
|
|
window.location = window.location;
|
|
setTimeout(window.stop, 0);
|
|
}, 30000);
|
|
}
|
|
}
|
|
|
|
this.release = function() {
|
|
if (timer) {
|
|
clearInterval(timer);
|
|
timer = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function getWakeLock() {
|
|
var userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
|
if (userAgent.match(/iPhone/i) || userAgent.match(/iPod/i)) {
|
|
return iOSWakeLock;
|
|
} else {
|
|
return AndroidWakeLock;
|
|
}
|
|
}
|
|
|
|
module.exports = getWakeLock();
|
|
},{"./util.js":29}],32:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2015 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Util = _dereq_('./util.js');
|
|
var CardboardVRDisplay = _dereq_('./cardboard-vr-display.js');
|
|
var MouseKeyboardVRDisplay = _dereq_('./mouse-keyboard-vr-display.js');
|
|
// Uncomment to add positional tracking via webcam.
|
|
//var WebcamPositionSensorVRDevice = require('./webcam-position-sensor-vr-device.js');
|
|
var VRDisplay = _dereq_('./base.js').VRDisplay;
|
|
var VRFrameData = _dereq_('./base.js').VRFrameData;
|
|
var HMDVRDevice = _dereq_('./base.js').HMDVRDevice;
|
|
var PositionSensorVRDevice = _dereq_('./base.js').PositionSensorVRDevice;
|
|
var VRDisplayHMDDevice = _dereq_('./display-wrappers.js').VRDisplayHMDDevice;
|
|
var VRDisplayPositionSensorDevice = _dereq_('./display-wrappers.js').VRDisplayPositionSensorDevice;
|
|
var version = _dereq_('../package.json').version;
|
|
|
|
function WebVRPolyfill() {
|
|
this.displays = [];
|
|
this.devices = []; // For deprecated objects
|
|
this.devicesPopulated = false;
|
|
this.nativeWebVRAvailable = this.isWebVRAvailable();
|
|
this.nativeLegacyWebVRAvailable = this.isDeprecatedWebVRAvailable();
|
|
this.nativeGetVRDisplaysFunc = this.nativeWebVRAvailable ?
|
|
navigator.getVRDisplays :
|
|
null;
|
|
|
|
if (!this.nativeLegacyWebVRAvailable && !this.nativeWebVRAvailable) {
|
|
this.enablePolyfill();
|
|
if (window.WebVRConfig.ENABLE_DEPRECATED_API) {
|
|
this.enableDeprecatedPolyfill();
|
|
}
|
|
}
|
|
|
|
// Put a shim in place to update the API to 1.1 if needed.
|
|
InstallWebVRSpecShim();
|
|
}
|
|
|
|
WebVRPolyfill.prototype.isWebVRAvailable = function() {
|
|
return ('getVRDisplays' in navigator);
|
|
};
|
|
|
|
WebVRPolyfill.prototype.isDeprecatedWebVRAvailable = function() {
|
|
return ('getVRDevices' in navigator) || ('mozGetVRDevices' in navigator);
|
|
};
|
|
|
|
WebVRPolyfill.prototype.connectDisplay = function(vrDisplay) {
|
|
vrDisplay.fireVRDisplayConnect_();
|
|
this.displays.push(vrDisplay);
|
|
};
|
|
|
|
WebVRPolyfill.prototype.populateDevices = function() {
|
|
if (this.devicesPopulated) {
|
|
return;
|
|
}
|
|
|
|
// Initialize our virtual VR devices.
|
|
var vrDisplay = null;
|
|
|
|
// Add a Cardboard VRDisplay on compatible mobile devices
|
|
if (this.isCardboardCompatible()) {
|
|
vrDisplay = new CardboardVRDisplay();
|
|
|
|
this.connectDisplay(vrDisplay);
|
|
|
|
// For backwards compatibility
|
|
if (window.WebVRConfig.ENABLE_DEPRECATED_API) {
|
|
this.devices.push(new VRDisplayHMDDevice(vrDisplay));
|
|
this.devices.push(new VRDisplayPositionSensorDevice(vrDisplay));
|
|
}
|
|
}
|
|
|
|
// Add a Mouse and Keyboard driven VRDisplay for desktops/laptops
|
|
if (!this.isMobile() && !window.WebVRConfig.MOUSE_KEYBOARD_CONTROLS_DISABLED) {
|
|
vrDisplay = new MouseKeyboardVRDisplay();
|
|
this.connectDisplay(vrDisplay);
|
|
|
|
// For backwards compatibility
|
|
if (window.WebVRConfig.ENABLE_DEPRECATED_API) {
|
|
this.devices.push(new VRDisplayHMDDevice(vrDisplay));
|
|
this.devices.push(new VRDisplayPositionSensorDevice(vrDisplay));
|
|
}
|
|
}
|
|
|
|
// Uncomment to add positional tracking via webcam.
|
|
//if (!this.isMobile() && window.WebVRConfig.ENABLE_DEPRECATED_API) {
|
|
// positionDevice = new WebcamPositionSensorVRDevice();
|
|
// this.devices.push(positionDevice);
|
|
//}
|
|
|
|
this.devicesPopulated = true;
|
|
};
|
|
|
|
WebVRPolyfill.prototype.enablePolyfill = function() {
|
|
// Provide navigator.getVRDisplays.
|
|
navigator.getVRDisplays = this.getVRDisplays.bind(this);
|
|
|
|
// Polyfill native VRDisplay.getFrameData
|
|
if (this.nativeWebVRAvailable && window.VRFrameData) {
|
|
var NativeVRFrameData = window.VRFrameData;
|
|
var nativeFrameData = new window.VRFrameData();
|
|
var nativeGetFrameData = window.VRDisplay.prototype.getFrameData;
|
|
window.VRFrameData = VRFrameData;
|
|
|
|
window.VRDisplay.prototype.getFrameData = function(frameData) {
|
|
if (frameData instanceof NativeVRFrameData) {
|
|
nativeGetFrameData.call(this, frameData);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
Copy frame data from the native object into the polyfilled object.
|
|
*/
|
|
|
|
nativeGetFrameData.call(this, nativeFrameData);
|
|
frameData.pose = nativeFrameData.pose;
|
|
Util.copyArray(nativeFrameData.leftProjectionMatrix, frameData.leftProjectionMatrix);
|
|
Util.copyArray(nativeFrameData.rightProjectionMatrix, frameData.rightProjectionMatrix);
|
|
Util.copyArray(nativeFrameData.leftViewMatrix, frameData.leftViewMatrix);
|
|
Util.copyArray(nativeFrameData.rightViewMatrix, frameData.rightViewMatrix);
|
|
//todo: copy
|
|
};
|
|
}
|
|
|
|
// Provide the `VRDisplay` object.
|
|
window.VRDisplay = VRDisplay;
|
|
|
|
// Provide the `navigator.vrEnabled` property.
|
|
if (navigator && typeof navigator.vrEnabled === 'undefined') {
|
|
var self = this;
|
|
Object.defineProperty(navigator, 'vrEnabled', {
|
|
get: function () {
|
|
return self.isCardboardCompatible() &&
|
|
(self.isFullScreenAvailable() || Util.isIOS());
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!('VRFrameData' in window)) {
|
|
// Provide the VRFrameData object.
|
|
window.VRFrameData = VRFrameData;
|
|
}
|
|
};
|
|
|
|
WebVRPolyfill.prototype.enableDeprecatedPolyfill = function() {
|
|
// Provide navigator.getVRDevices.
|
|
navigator.getVRDevices = this.getVRDevices.bind(this);
|
|
|
|
// Provide the CardboardHMDVRDevice and PositionSensorVRDevice objects.
|
|
window.HMDVRDevice = HMDVRDevice;
|
|
window.PositionSensorVRDevice = PositionSensorVRDevice;
|
|
};
|
|
|
|
WebVRPolyfill.prototype.getVRDisplays = function() {
|
|
this.populateDevices();
|
|
var polyfillDisplays = this.displays;
|
|
|
|
if (!this.nativeWebVRAvailable) {
|
|
return Promise.resolve(polyfillDisplays);
|
|
}
|
|
|
|
// Set up a race condition if this browser has a bug where
|
|
// `navigator.getVRDisplays()` never resolves.
|
|
var timeoutId;
|
|
var vrDisplaysNative = this.nativeGetVRDisplaysFunc.call(navigator);
|
|
var timeoutPromise = new Promise(function(resolve) {
|
|
timeoutId = setTimeout(function() {
|
|
console.warn('Native WebVR implementation detected, but `getVRDisplays()` failed to resolve. Falling back to polyfill.');
|
|
resolve([]);
|
|
}, window.WebVRConfig.GET_VR_DISPLAYS_TIMEOUT);
|
|
});
|
|
|
|
return Util.race([
|
|
vrDisplaysNative,
|
|
timeoutPromise
|
|
]).then(function(nativeDisplays) {
|
|
clearTimeout(timeoutId);
|
|
if (window.WebVRConfig.ALWAYS_APPEND_POLYFILL_DISPLAY) {
|
|
return nativeDisplays.concat(polyfillDisplays);
|
|
} else {
|
|
return nativeDisplays.length > 0 ? nativeDisplays : polyfillDisplays;
|
|
}
|
|
});
|
|
};
|
|
|
|
WebVRPolyfill.prototype.getVRDevices = function() {
|
|
console.warn('getVRDevices is deprecated. Please update your code to use getVRDisplays instead.');
|
|
var self = this;
|
|
return new Promise(function(resolve, reject) {
|
|
try {
|
|
if (!self.devicesPopulated) {
|
|
if (self.nativeWebVRAvailable) {
|
|
return navigator.getVRDisplays(function(displays) {
|
|
for (var i = 0; i < displays.length; ++i) {
|
|
self.devices.push(new VRDisplayHMDDevice(displays[i]));
|
|
self.devices.push(new VRDisplayPositionSensorDevice(displays[i]));
|
|
}
|
|
self.devicesPopulated = true;
|
|
resolve(self.devices);
|
|
}, reject);
|
|
}
|
|
|
|
if (self.nativeLegacyWebVRAvailable) {
|
|
return (navigator.getVRDDevices || navigator.mozGetVRDevices)(function(devices) {
|
|
for (var i = 0; i < devices.length; ++i) {
|
|
if (devices[i] instanceof HMDVRDevice) {
|
|
self.devices.push(devices[i]);
|
|
}
|
|
if (devices[i] instanceof PositionSensorVRDevice) {
|
|
self.devices.push(devices[i]);
|
|
}
|
|
}
|
|
self.devicesPopulated = true;
|
|
resolve(self.devices);
|
|
}, reject);
|
|
}
|
|
}
|
|
|
|
self.populateDevices();
|
|
resolve(self.devices);
|
|
} catch (e) {
|
|
reject(e);
|
|
}
|
|
});
|
|
};
|
|
|
|
WebVRPolyfill.prototype.NativeVRFrameData = window.VRFrameData;
|
|
|
|
/**
|
|
* Determine if a device is mobile.
|
|
*/
|
|
WebVRPolyfill.prototype.isMobile = function() {
|
|
return /Android/i.test(navigator.userAgent) ||
|
|
/iPhone|iPad|iPod/i.test(navigator.userAgent);
|
|
};
|
|
|
|
WebVRPolyfill.prototype.isCardboardCompatible = function() {
|
|
// For now, support all iOS and Android devices.
|
|
// Also enable the WebVRConfig.FORCE_VR flag for debugging.
|
|
return this.isMobile() || window.WebVRConfig.FORCE_ENABLE_VR;
|
|
};
|
|
|
|
WebVRPolyfill.prototype.isFullScreenAvailable = function() {
|
|
return (document.fullscreenEnabled ||
|
|
document.mozFullScreenEnabled ||
|
|
document.webkitFullscreenEnabled ||
|
|
false);
|
|
};
|
|
|
|
// Installs a shim that updates a WebVR 1.0 spec implementation to WebVR 1.1
|
|
function InstallWebVRSpecShim() {
|
|
if ('VRDisplay' in window && !('VRFrameData' in window)) {
|
|
// Provide the VRFrameData object.
|
|
window.VRFrameData = VRFrameData;
|
|
|
|
// A lot of Chrome builds don't have depthNear and depthFar, even
|
|
// though they're in the WebVR 1.0 spec. Patch them in if they're not present.
|
|
if(!('depthNear' in window.VRDisplay.prototype)) {
|
|
window.VRDisplay.prototype.depthNear = 0.01;
|
|
}
|
|
|
|
if(!('depthFar' in window.VRDisplay.prototype)) {
|
|
window.VRDisplay.prototype.depthFar = 10000.0;
|
|
}
|
|
|
|
window.VRDisplay.prototype.getFrameData = function(frameData) {
|
|
return Util.frameDataFromPose(frameData, this.getPose(), this);
|
|
}
|
|
}
|
|
};
|
|
|
|
WebVRPolyfill.InstallWebVRSpecShim = InstallWebVRSpecShim;
|
|
WebVRPolyfill.version = version;
|
|
|
|
module.exports.WebVRPolyfill = WebVRPolyfill;
|
|
|
|
},{"../package.json":8,"./base.js":9,"./cardboard-vr-display.js":12,"./display-wrappers.js":15,"./mouse-keyboard-vr-display.js":21,"./util.js":29}],33:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var EventEmitter = _dereq_('eventemitter3');
|
|
var shaka = _dereq_('shaka-player');
|
|
|
|
var Types = _dereq_('../video-type');
|
|
var Util = _dereq_('../util');
|
|
|
|
var DEFAULT_BITS_PER_SECOND = 1000000;
|
|
|
|
/**
|
|
* Supports regular video URLs (eg. mp4), as well as adaptive manifests like
|
|
* DASH (.mpd) and soon HLS (.m3u8).
|
|
*
|
|
* Events:
|
|
* load(video): When the video is loaded.
|
|
* error(message): If an error occurs.
|
|
*
|
|
* To play/pause/seek/etc, please use the underlying video element.
|
|
*/
|
|
function AdaptivePlayer(params) {
|
|
this.video = document.createElement('video');
|
|
// Loop by default.
|
|
if (params.loop === true) {
|
|
this.video.setAttribute('loop', true);
|
|
}
|
|
|
|
if (params.volume !== undefined) {
|
|
// XXX: .setAttribute('volume', params.volume) doesn't work for some reason.
|
|
this.video.volume = params.volume;
|
|
}
|
|
|
|
// Not muted by default.
|
|
if (params.muted === true) {
|
|
this.video.muted = params.muted;
|
|
}
|
|
|
|
// For FF, make sure we enable preload.
|
|
this.video.setAttribute('preload', 'auto');
|
|
// Enable inline video playback in iOS 10+.
|
|
this.video.setAttribute('playsinline', true);
|
|
this.video.setAttribute('crossorigin', 'anonymous');
|
|
}
|
|
AdaptivePlayer.prototype = new EventEmitter();
|
|
|
|
AdaptivePlayer.prototype.load = function(url) {
|
|
var self = this;
|
|
// TODO(smus): Investigate whether or not differentiation is best done by
|
|
// mimeType after all. Cursory research suggests that adaptive streaming
|
|
// manifest mime types aren't properly supported.
|
|
//
|
|
// For now, make determination based on extension.
|
|
var extension = Util.getExtension(url);
|
|
switch (extension) {
|
|
case 'm3u8': // HLS
|
|
this.type = Types.HLS;
|
|
if (Util.isSafari()) {
|
|
this.loadVideo_(url).then(function() {
|
|
self.emit('load', self.video, self.type);
|
|
}).catch(this.onError_.bind(this));
|
|
} else {
|
|
self.onError_('HLS is only supported on Safari.');
|
|
}
|
|
break;
|
|
case 'mpd': // MPEG-DASH
|
|
this.type = Types.DASH;
|
|
this.loadShakaVideo_(url).then(function() {
|
|
console.log('The video has now been loaded!');
|
|
self.emit('load', self.video, self.type);
|
|
}).catch(this.onError_.bind(this));
|
|
break;
|
|
default: // A regular video, not an adaptive manifest.
|
|
this.type = Types.VIDEO;
|
|
this.loadVideo_(url).then(function() {
|
|
self.emit('load', self.video, self.type);
|
|
}).catch(this.onError_.bind(this));
|
|
break;
|
|
}
|
|
};
|
|
|
|
AdaptivePlayer.prototype.destroy = function() {
|
|
this.video.pause();
|
|
this.video.src = '';
|
|
this.video = null;
|
|
};
|
|
|
|
/*** PRIVATE API ***/
|
|
|
|
AdaptivePlayer.prototype.onError_ = function(e) {
|
|
console.error(e);
|
|
this.emit('error', e);
|
|
};
|
|
|
|
AdaptivePlayer.prototype.loadVideo_ = function(url) {
|
|
var self = this, video = self.video;
|
|
return new Promise(function(resolve, reject) {
|
|
video.src = url;
|
|
video.addEventListener('canplaythrough', resolve);
|
|
video.addEventListener('loadedmetadata', function() {
|
|
self.emit('timeupdate', {
|
|
currentTime: video.currentTime,
|
|
duration: video.duration
|
|
});
|
|
});
|
|
video.addEventListener('error', reject);
|
|
video.load();
|
|
});
|
|
};
|
|
|
|
AdaptivePlayer.prototype.initShaka_ = function() {
|
|
this.player = new shaka.Player(this.video);
|
|
|
|
this.player.configure({
|
|
abr: { defaultBandwidthEstimate: DEFAULT_BITS_PER_SECOND }
|
|
});
|
|
|
|
// Listen for error events.
|
|
this.player.addEventListener('error', this.onError_);
|
|
};
|
|
|
|
AdaptivePlayer.prototype.loadShakaVideo_ = function(url) {
|
|
// Install built-in polyfills to patch browser incompatibilities.
|
|
shaka.polyfill.installAll();
|
|
|
|
if (!shaka.Player.isBrowserSupported()) {
|
|
console.error('Shaka is not supported on this browser.');
|
|
return;
|
|
}
|
|
|
|
this.initShaka_();
|
|
return this.player.load(url);
|
|
};
|
|
|
|
module.exports = AdaptivePlayer;
|
|
|
|
},{"../util":45,"../video-type":46,"eventemitter3":3,"shaka-player":5}],34:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
var Eyes = {
|
|
LEFT: 1,
|
|
RIGHT: 2
|
|
};
|
|
|
|
module.exports = Eyes;
|
|
|
|
},{}],35:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
var EventEmitter = _dereq_('eventemitter3');
|
|
var TWEEN = _dereq_('@tweenjs/tween.js');
|
|
|
|
var Util = _dereq_('../util');
|
|
|
|
// Constants for the focus/blur animation.
|
|
var NORMAL_SCALE = new THREE.Vector3(1, 1, 1);
|
|
var FOCUS_SCALE = new THREE.Vector3(1.2, 1.2, 1.2);
|
|
var FOCUS_DURATION = 200;
|
|
|
|
// Constants for the active/inactive animation.
|
|
var INACTIVE_COLOR = new THREE.Color(1, 1, 1);
|
|
var ACTIVE_COLOR = new THREE.Color(0.8, 0, 0);
|
|
var ACTIVE_DURATION = 100;
|
|
|
|
// Constants for opacity.
|
|
var MAX_INNER_OPACITY = 0.8;
|
|
var MAX_OUTER_OPACITY = 0.5;
|
|
var FADE_START_ANGLE_DEG = 35;
|
|
var FADE_END_ANGLE_DEG = 60;
|
|
/**
|
|
* Responsible for rectangular hot spots that the user can interact with.
|
|
*
|
|
* Specific duties:
|
|
* Adding and removing hotspots.
|
|
* Rendering the hotspots (debug mode only).
|
|
* Notifying when hotspots are interacted with.
|
|
*
|
|
* Emits the following events:
|
|
* click (id): a hotspot is clicked.
|
|
* focus (id): a hotspot is focused.
|
|
* blur (id): a hotspot is no longer hovered over.
|
|
*/
|
|
function HotspotRenderer(worldRenderer) {
|
|
this.worldRenderer = worldRenderer;
|
|
this.scene = worldRenderer.scene;
|
|
|
|
// Note: this event must be added to document.body and not to window for it to
|
|
// work inside iOS iframes.
|
|
var body = document.body;
|
|
// Bind events for hotspot interaction.
|
|
if (!Util.isMobile()) {
|
|
// Only enable mouse events on desktop.
|
|
body.addEventListener('mousedown', this.onMouseDown_.bind(this), false);
|
|
body.addEventListener('mousemove', this.onMouseMove_.bind(this), false);
|
|
body.addEventListener('mouseup', this.onMouseUp_.bind(this), false);
|
|
}
|
|
body.addEventListener('touchstart', this.onTouchStart_.bind(this), false);
|
|
body.addEventListener('touchend', this.onTouchEnd_.bind(this), false);
|
|
|
|
// Add a placeholder for hotspots.
|
|
this.hotspotRoot = new THREE.Object3D();
|
|
// Align the center with the center of the camera too.
|
|
this.hotspotRoot.rotation.y = Math.PI / 2;
|
|
this.scene.add(this.hotspotRoot);
|
|
|
|
// All hotspot IDs.
|
|
this.hotspots = {};
|
|
|
|
// Currently selected hotspots.
|
|
this.selectedHotspots = {};
|
|
|
|
// Hotspots that the last touchstart / mousedown event happened for.
|
|
this.downHotspots = {};
|
|
|
|
// For raycasting. Initialize mouse to be off screen initially.
|
|
this.pointer = new THREE.Vector2(1, 1);
|
|
this.raycaster = new THREE.Raycaster();
|
|
}
|
|
HotspotRenderer.prototype = new EventEmitter();
|
|
|
|
/**
|
|
* @param pitch {Number} The latitude of center, specified in degrees, between
|
|
* -90 and 90, with 0 at the horizon.
|
|
* @param yaw {Number} The longitude of center, specified in degrees, between
|
|
* -180 and 180, with 0 at the image center.
|
|
* @param radius {Number} The radius of the hotspot, specified in meters.
|
|
* @param distance {Number} The distance of the hotspot from camera, specified
|
|
* in meters.
|
|
* @param hotspotId {String} The ID of the hotspot.
|
|
*/
|
|
HotspotRenderer.prototype.add = function(pitch, yaw, radius, distance, id) {
|
|
// If a hotspot already exists with this ID, stop.
|
|
if (this.hotspots[id]) {
|
|
// TODO: Proper error reporting.
|
|
console.error('Attempt to add hotspot with existing id %s.', id);
|
|
return;
|
|
}
|
|
var hotspot = this.createHotspot_(radius, distance);
|
|
hotspot.name = id;
|
|
|
|
// Position the hotspot based on the pitch and yaw specified.
|
|
var quat = new THREE.Quaternion();
|
|
quat.setFromEuler(new THREE.Euler(THREE.Math.degToRad(pitch), THREE.Math.degToRad(yaw), 0, 'ZYX'));
|
|
hotspot.position.applyQuaternion(quat);
|
|
hotspot.lookAt(new THREE.Vector3());
|
|
|
|
this.hotspotRoot.add(hotspot);
|
|
this.hotspots[id] = hotspot;
|
|
}
|
|
|
|
/**
|
|
* Removes a hotspot based on the ID.
|
|
*
|
|
* @param ID {String} Identifier of the hotspot to be removed.
|
|
*/
|
|
HotspotRenderer.prototype.remove = function(id) {
|
|
// If there's no hotspot with this ID, fail.
|
|
if (!this.hotspots[id]) {
|
|
// TODO: Proper error reporting.
|
|
console.error('Attempt to remove non-existing hotspot with id %s.', id);
|
|
return;
|
|
}
|
|
// Remove the mesh from the scene.
|
|
this.hotspotRoot.remove(this.hotspots[id]);
|
|
|
|
// If this hotspot was selected, make sure it gets unselected.
|
|
delete this.selectedHotspots[id];
|
|
delete this.downHotspots[id];
|
|
delete this.hotspots[id];
|
|
this.emit('blur', id);
|
|
};
|
|
|
|
/**
|
|
* Clears all hotspots from the pano. Often called when changing panos.
|
|
*/
|
|
HotspotRenderer.prototype.clearAll = function() {
|
|
for (var id in this.hotspots) {
|
|
this.remove(id);
|
|
}
|
|
};
|
|
|
|
HotspotRenderer.prototype.getCount = function() {
|
|
var count = 0;
|
|
for (var id in this.hotspots) {
|
|
count += 1;
|
|
}
|
|
return count;
|
|
};
|
|
|
|
HotspotRenderer.prototype.update = function(camera) {
|
|
if (this.worldRenderer.isVRMode()) {
|
|
this.pointer.set(0, 0);
|
|
}
|
|
// Update the picking ray with the camera and mouse position.
|
|
this.raycaster.setFromCamera(this.pointer, camera);
|
|
|
|
// Fade hotspots out if they are really far from center to avoid overly
|
|
// distorted visuals.
|
|
this.fadeOffCenterHotspots_(camera);
|
|
|
|
var hotspots = this.hotspotRoot.children;
|
|
|
|
// Go through all hotspots to see if they are currently selected.
|
|
for (var i = 0; i < hotspots.length; i++) {
|
|
var hotspot = hotspots[i];
|
|
//hotspot.lookAt(camera.position);
|
|
var id = hotspot.name;
|
|
// Check if hotspot is intersected with the picking ray.
|
|
var intersects = this.raycaster.intersectObjects(hotspot.children);
|
|
var isIntersected = (intersects.length > 0);
|
|
|
|
// If newly selected, emit a focus event.
|
|
if (isIntersected && !this.selectedHotspots[id]) {
|
|
this.emit('focus', id);
|
|
this.focus_(id);
|
|
}
|
|
// If no longer selected, emit a blur event.
|
|
if (!isIntersected && this.selectedHotspots[id]) {
|
|
this.emit('blur', id);
|
|
this.blur_(id);
|
|
}
|
|
// Update the set of selected hotspots.
|
|
if (isIntersected) {
|
|
this.selectedHotspots[id] = true;
|
|
} else {
|
|
delete this.selectedHotspots[id];
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Toggle whether or not hotspots are visible.
|
|
*/
|
|
HotspotRenderer.prototype.setVisibility = function(isVisible) {
|
|
this.hotspotRoot.visible = isVisible;
|
|
};
|
|
|
|
HotspotRenderer.prototype.onTouchStart_ = function(e) {
|
|
// In VR mode, don't touch the pointer position.
|
|
if (!this.worldRenderer.isVRMode()) {
|
|
this.updateTouch_(e);
|
|
}
|
|
|
|
// Force a camera update to see if any hotspots were selected.
|
|
this.update(this.worldRenderer.camera);
|
|
|
|
this.downHotspots = {};
|
|
for (var id in this.selectedHotspots) {
|
|
this.downHotspots[id] = true;
|
|
this.down_(id);
|
|
}
|
|
return false;
|
|
};
|
|
|
|
HotspotRenderer.prototype.onTouchEnd_ = function(e) {
|
|
// If no hotspots are pressed, emit an empty click event.
|
|
if (Util.isEmptyObject(this.downHotspots)) {
|
|
this.emit('click');
|
|
return;
|
|
}
|
|
|
|
// Only emit a click if the finger was down on the same hotspot before.
|
|
for (var id in this.downHotspots) {
|
|
this.emit('click', id);
|
|
this.up_(id);
|
|
e.preventDefault();
|
|
}
|
|
};
|
|
|
|
HotspotRenderer.prototype.updateTouch_ = function(e) {
|
|
var size = this.getSize_();
|
|
var touch = e.touches[0];
|
|
this.pointer.x = (touch.clientX / size.width) * 2 - 1;
|
|
this.pointer.y = - (touch.clientY / size.height) * 2 + 1;
|
|
};
|
|
|
|
HotspotRenderer.prototype.onMouseDown_ = function(e) {
|
|
this.updateMouse_(e);
|
|
|
|
this.downHotspots = {};
|
|
for (var id in this.selectedHotspots) {
|
|
this.downHotspots[id] = true;
|
|
this.down_(id);
|
|
}
|
|
};
|
|
|
|
HotspotRenderer.prototype.onMouseMove_ = function(e) {
|
|
this.updateMouse_(e);
|
|
};
|
|
|
|
HotspotRenderer.prototype.onMouseUp_ = function(e) {
|
|
this.updateMouse_(e);
|
|
|
|
// If no hotspots are pressed, emit an empty click event.
|
|
if (Util.isEmptyObject(this.downHotspots)) {
|
|
this.emit('click');
|
|
return;
|
|
}
|
|
|
|
// Only emit a click if the mouse was down on the same hotspot before.
|
|
for (var id in this.selectedHotspots) {
|
|
if (id in this.downHotspots) {
|
|
this.emit('click', id);
|
|
this.up_(id);
|
|
}
|
|
}
|
|
};
|
|
|
|
HotspotRenderer.prototype.updateMouse_ = function(e) {
|
|
var size = this.getSize_();
|
|
this.pointer.x = (e.clientX / size.width) * 2 - 1;
|
|
this.pointer.y = - (e.clientY / size.height) * 2 + 1;
|
|
};
|
|
|
|
HotspotRenderer.prototype.getSize_ = function() {
|
|
var canvas = this.worldRenderer.renderer.domElement;
|
|
return this.worldRenderer.renderer.getSize();
|
|
};
|
|
|
|
HotspotRenderer.prototype.createHotspot_ = function(radius, distance) {
|
|
var innerGeometry = new THREE.CircleGeometry(radius, 32);
|
|
|
|
var innerMaterial = new THREE.MeshBasicMaterial({
|
|
color: 0xffffff, side: THREE.DoubleSide, transparent: true,
|
|
opacity: MAX_INNER_OPACITY, depthTest: false
|
|
});
|
|
|
|
var inner = new THREE.Mesh(innerGeometry, innerMaterial);
|
|
inner.name = 'inner';
|
|
|
|
var outerMaterial = new THREE.MeshBasicMaterial({
|
|
color: 0xffffff, side: THREE.DoubleSide, transparent: true,
|
|
opacity: MAX_OUTER_OPACITY, depthTest: false
|
|
});
|
|
var outerGeometry = new THREE.RingGeometry(radius * 0.85, radius, 32);
|
|
var outer = new THREE.Mesh(outerGeometry, outerMaterial);
|
|
outer.name = 'outer';
|
|
|
|
// Position at the extreme end of the sphere.
|
|
var hotspot = new THREE.Object3D();
|
|
hotspot.position.z = -distance;
|
|
hotspot.scale.copy(NORMAL_SCALE);
|
|
|
|
hotspot.add(inner);
|
|
hotspot.add(outer);
|
|
|
|
return hotspot;
|
|
};
|
|
|
|
/**
|
|
* Large aspect ratios tend to cause visually jarring distortions on the sides.
|
|
* Here we fade hotspots out to avoid them.
|
|
*/
|
|
HotspotRenderer.prototype.fadeOffCenterHotspots_ = function(camera) {
|
|
var lookAt = new THREE.Vector3(1, 0, 0);
|
|
lookAt.applyQuaternion(camera.quaternion);
|
|
// Take into account the camera parent too.
|
|
lookAt.applyQuaternion(camera.parent.quaternion);
|
|
|
|
// Go through each hotspot. Calculate how far off center it is.
|
|
for (var id in this.hotspots) {
|
|
var hotspot = this.hotspots[id];
|
|
var angle = hotspot.position.angleTo(lookAt);
|
|
var angleDeg = THREE.Math.radToDeg(angle);
|
|
var isVisible = angleDeg < 45;
|
|
var opacity;
|
|
if (angleDeg < FADE_START_ANGLE_DEG) {
|
|
opacity = 1;
|
|
} else if (angleDeg > FADE_END_ANGLE_DEG) {
|
|
opacity = 0;
|
|
} else {
|
|
// We are in the case START < angle < END. Linearly interpolate.
|
|
var range = FADE_END_ANGLE_DEG - FADE_START_ANGLE_DEG;
|
|
var value = FADE_END_ANGLE_DEG - angleDeg;
|
|
opacity = value / range;
|
|
}
|
|
|
|
// Opacity a function of angle. If angle is large, opacity is zero. At some
|
|
// point, ramp opacity down.
|
|
this.setOpacity_(id, opacity);
|
|
}
|
|
};
|
|
|
|
HotspotRenderer.prototype.focus_ = function(id) {
|
|
var hotspot = this.hotspots[id];
|
|
|
|
// Tween scale of hotspot.
|
|
this.tween = new TWEEN.Tween(hotspot.scale).to(FOCUS_SCALE, FOCUS_DURATION)
|
|
.easing(TWEEN.Easing.Quadratic.InOut)
|
|
.start();
|
|
|
|
if (this.worldRenderer.isVRMode()) {
|
|
this.timeForHospotClick = setTimeout(function () {
|
|
this.emit('click', id);
|
|
}, 1200 )
|
|
}
|
|
};
|
|
|
|
HotspotRenderer.prototype.blur_ = function(id) {
|
|
var hotspot = this.hotspots[id];
|
|
|
|
this.tween = new TWEEN.Tween(hotspot.scale).to(NORMAL_SCALE, FOCUS_DURATION)
|
|
.easing(TWEEN.Easing.Quadratic.InOut)
|
|
.start();
|
|
|
|
if (this.timeForHospotClick) {
|
|
clearTimeout( this.timeForHospotClick );
|
|
}
|
|
};
|
|
|
|
HotspotRenderer.prototype.down_ = function(id) {
|
|
// Become active.
|
|
var hotspot = this.hotspots[id];
|
|
var outer = hotspot.getObjectByName('inner');
|
|
|
|
this.tween = new TWEEN.Tween(outer.material.color).to(ACTIVE_COLOR, ACTIVE_DURATION)
|
|
.start();
|
|
};
|
|
|
|
HotspotRenderer.prototype.up_ = function(id) {
|
|
// Become inactive.
|
|
var hotspot = this.hotspots[id];
|
|
var outer = hotspot.getObjectByName('inner');
|
|
|
|
this.tween = new TWEEN.Tween(outer.material.color).to(INACTIVE_COLOR, ACTIVE_DURATION)
|
|
.start();
|
|
};
|
|
|
|
HotspotRenderer.prototype.setOpacity_ = function(id, opacity) {
|
|
var hotspot = this.hotspots[id];
|
|
var outer = hotspot.getObjectByName('outer');
|
|
var inner = hotspot.getObjectByName('inner');
|
|
|
|
outer.material.opacity = opacity * MAX_OUTER_OPACITY;
|
|
inner.material.opacity = opacity * MAX_INNER_OPACITY;
|
|
};
|
|
|
|
module.exports = HotspotRenderer;
|
|
|
|
},{"../util":45,"@tweenjs/tween.js":1,"eventemitter3":3}],36:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
var EventEmitter = _dereq_('eventemitter3');
|
|
var Message = _dereq_('../message');
|
|
var Util = _dereq_('../util');
|
|
|
|
|
|
/**
|
|
* Sits in an embedded iframe, receiving messages from a containing
|
|
* iFrame. This facilitates an API which provides the following features:
|
|
*
|
|
* Playing and pausing content.
|
|
* Adding hotspots.
|
|
* Sending messages back to the containing iframe when hotspot is clicked
|
|
* Sending analytics events to containing iframe.
|
|
*
|
|
* Note: this script used to also respond to synthetic devicemotion events, but
|
|
* no longer does so. This is because as of iOS 9.2, Safari disallows listening
|
|
* for devicemotion events within cross-device iframes. To work around this, the
|
|
* webvr-polyfill responds to the postMessage event containing devicemotion
|
|
* information (sent by the iframe-message-sender in the VR View API).
|
|
*/
|
|
function IFrameMessageReceiver() {
|
|
window.addEventListener('message', this.onMessage_.bind(this), false);
|
|
}
|
|
IFrameMessageReceiver.prototype = new EventEmitter();
|
|
|
|
IFrameMessageReceiver.prototype.onMessage_ = function(event) {
|
|
if (Util.isDebug()) {
|
|
console.log('onMessage_', event);
|
|
}
|
|
|
|
var message = event.data;
|
|
var type = message.type.toLowerCase();
|
|
var data = message.data;
|
|
|
|
switch (type) {
|
|
case Message.SET_CONTENT:
|
|
case Message.SET_VOLUME:
|
|
case Message.MUTED:
|
|
case Message.ADD_HOTSPOT:
|
|
case Message.PLAY:
|
|
case Message.PAUSE:
|
|
case Message.SET_CURRENT_TIME:
|
|
case Message.GET_POSITION:
|
|
case Message.SET_FULLSCREEN:
|
|
this.emit(type, data);
|
|
break;
|
|
default:
|
|
if (Util.isDebug()) {
|
|
console.warn('Got unknown message of type %s from %s', message.type, message.origin);
|
|
}
|
|
}
|
|
};
|
|
|
|
module.exports = IFrameMessageReceiver;
|
|
|
|
},{"../message":44,"../util":45,"eventemitter3":3}],37:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* Shows a 2D loading indicator while various pieces of EmbedVR load.
|
|
*/
|
|
function LoadingIndicator() {
|
|
this.el = this.build_();
|
|
document.body.appendChild(this.el);
|
|
this.show();
|
|
}
|
|
|
|
LoadingIndicator.prototype.build_ = function() {
|
|
var overlay = document.createElement('div');
|
|
var s = overlay.style;
|
|
s.position = 'fixed';
|
|
s.top = 0;
|
|
s.left = 0;
|
|
s.width = '100%';
|
|
s.height = '100%';
|
|
s.background = '#eee';
|
|
var img = document.createElement('img');
|
|
img.src = 'images/loading.gif';
|
|
var s = img.style;
|
|
s.position = 'absolute';
|
|
s.top = '50%';
|
|
s.left = '50%';
|
|
s.transform = 'translate(-50%, -50%)';
|
|
|
|
overlay.appendChild(img);
|
|
return overlay;
|
|
};
|
|
|
|
LoadingIndicator.prototype.hide = function() {
|
|
this.el.style.display = 'none';
|
|
};
|
|
|
|
LoadingIndicator.prototype.show = function() {
|
|
this.el.style.display = 'block';
|
|
};
|
|
|
|
module.exports = LoadingIndicator;
|
|
|
|
},{}],38:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
// Initialize the loading indicator as quickly as possible to give the user
|
|
// immediate feedback.
|
|
var LoadingIndicator = _dereq_('./loading-indicator');
|
|
var loadIndicator = new LoadingIndicator();
|
|
|
|
var ES6Promise = _dereq_('es6-promise');
|
|
// Polyfill ES6 promises for IE.
|
|
ES6Promise.polyfill();
|
|
|
|
var IFrameMessageReceiver = _dereq_('./iframe-message-receiver');
|
|
var Message = _dereq_('../message');
|
|
var SceneInfo = _dereq_('./scene-info');
|
|
var Stats = _dereq_('../../node_modules/stats-js/build/stats.min');
|
|
var Util = _dereq_('../util');
|
|
var WebVRPolyfill = _dereq_('webvr-polyfill');
|
|
var WorldRenderer = _dereq_('./world-renderer');
|
|
|
|
var receiver = new IFrameMessageReceiver();
|
|
receiver.on(Message.PLAY, onPlayRequest);
|
|
receiver.on(Message.PAUSE, onPauseRequest);
|
|
receiver.on(Message.ADD_HOTSPOT, onAddHotspot);
|
|
receiver.on(Message.SET_CONTENT, onSetContent);
|
|
receiver.on(Message.SET_VOLUME, onSetVolume);
|
|
receiver.on(Message.MUTED, onMuted);
|
|
receiver.on(Message.SET_CURRENT_TIME, onUpdateCurrentTime);
|
|
receiver.on(Message.GET_POSITION, onGetPosition);
|
|
receiver.on(Message.SET_FULLSCREEN, onSetFullscreen);
|
|
|
|
window.addEventListener('load', onLoad);
|
|
|
|
var stats = new Stats();
|
|
var scene = SceneInfo.loadFromGetParams();
|
|
|
|
var worldRenderer = new WorldRenderer(scene);
|
|
worldRenderer.on('error', onRenderError);
|
|
worldRenderer.on('load', onRenderLoad);
|
|
worldRenderer.on('modechange', onModeChange);
|
|
worldRenderer.on('ended', onEnded);
|
|
worldRenderer.on('play', onPlay);
|
|
worldRenderer.hotspotRenderer.on('click', onHotspotClick);
|
|
|
|
window.worldRenderer = worldRenderer;
|
|
|
|
var isReadySent = false;
|
|
var volume = 0;
|
|
|
|
function onLoad() {
|
|
if (!Util.isWebGLEnabled()) {
|
|
showError('WebGL not supported.');
|
|
return;
|
|
}
|
|
|
|
// Load the scene.
|
|
worldRenderer.setScene(scene);
|
|
|
|
if (scene.isDebug) {
|
|
// Show stats.
|
|
showStats();
|
|
}
|
|
|
|
if (scene.isYawOnly) {
|
|
WebVRConfig = window.WebVRConfig || {};
|
|
WebVRConfig.YAW_ONLY = true;
|
|
}
|
|
|
|
requestAnimationFrame(loop);
|
|
}
|
|
|
|
|
|
function onVideoTap() {
|
|
worldRenderer.videoProxy.play();
|
|
hidePlayButton();
|
|
|
|
// Prevent multiple play() calls on the video element.
|
|
document.body.removeEventListener('touchend', onVideoTap);
|
|
}
|
|
|
|
function onRenderLoad(event) {
|
|
if (event.videoElement) {
|
|
|
|
var scene = SceneInfo.loadFromGetParams();
|
|
|
|
// On mobile, tell the user they need to tap to start. Otherwise, autoplay.
|
|
if (Util.isMobile()) {
|
|
// Tell user to tap to start.
|
|
showPlayButton();
|
|
document.body.addEventListener('touchend', onVideoTap);
|
|
} else {
|
|
event.videoElement.play();
|
|
}
|
|
|
|
// Attach to pause and play events, to notify the API.
|
|
event.videoElement.addEventListener('pause', onPause);
|
|
event.videoElement.addEventListener('play', onPlay);
|
|
event.videoElement.addEventListener('timeupdate', onGetCurrentTime);
|
|
event.videoElement.addEventListener('ended', onEnded);
|
|
}
|
|
// Hide loading indicator.
|
|
loadIndicator.hide();
|
|
|
|
// Autopan only on desktop, for photos only, and only if autopan is enabled.
|
|
if (!Util.isMobile() && !worldRenderer.sceneInfo.video && !worldRenderer.sceneInfo.isAutopanOff) {
|
|
worldRenderer.autopan();
|
|
}
|
|
|
|
// Notify the API that we are ready, but only do this once.
|
|
if (!isReadySent) {
|
|
if (event.videoElement) {
|
|
Util.sendParentMessage({
|
|
type: 'ready',
|
|
data: {
|
|
duration: event.videoElement.duration
|
|
}
|
|
});
|
|
} else {
|
|
Util.sendParentMessage({
|
|
type: 'ready'
|
|
});
|
|
}
|
|
|
|
isReadySent = true;
|
|
}
|
|
}
|
|
|
|
function onPlayRequest() {
|
|
if (!worldRenderer.videoProxy) {
|
|
onApiError('Attempt to pause, but no video found.');
|
|
return;
|
|
}
|
|
worldRenderer.videoProxy.play();
|
|
}
|
|
|
|
function onPauseRequest() {
|
|
if (!worldRenderer.videoProxy) {
|
|
onApiError('Attempt to pause, but no video found.');
|
|
return;
|
|
}
|
|
worldRenderer.videoProxy.pause();
|
|
}
|
|
|
|
function onAddHotspot(e) {
|
|
if (Util.isDebug()) {
|
|
console.log('onAddHotspot', e);
|
|
}
|
|
// TODO: Implement some validation?
|
|
|
|
var pitch = parseFloat(e.pitch);
|
|
var yaw = parseFloat(e.yaw);
|
|
var radius = parseFloat(e.radius);
|
|
var distance = parseFloat(e.distance);
|
|
var id = e.id;
|
|
worldRenderer.hotspotRenderer.add(pitch, yaw, radius, distance, id);
|
|
}
|
|
|
|
function onSetContent(e) {
|
|
if (Util.isDebug()) {
|
|
console.log('onSetContent', e);
|
|
}
|
|
// Remove all of the hotspots.
|
|
worldRenderer.hotspotRenderer.clearAll();
|
|
// Fade to black.
|
|
worldRenderer.sphereRenderer.setOpacity(0, 500).then(function() {
|
|
// Then load the new scene.
|
|
var scene = SceneInfo.loadFromAPIParams(e.contentInfo);
|
|
worldRenderer.destroy();
|
|
|
|
// Update the URL to reflect the new scene. This is important particularily
|
|
// on iOS where we use a fake fullscreen mode.
|
|
var url = scene.getCurrentUrl();
|
|
//console.log('Updating url to be %s', url);
|
|
window.history.pushState(null, 'VR View', url);
|
|
|
|
// And set the new scene.
|
|
return worldRenderer.setScene(scene);
|
|
}).then(function() {
|
|
// Then fade the scene back in.
|
|
worldRenderer.sphereRenderer.setOpacity(1, 500);
|
|
});
|
|
}
|
|
|
|
function onSetVolume(e) {
|
|
// Only work for video. If there's no video, send back an error.
|
|
if (!worldRenderer.videoProxy) {
|
|
onApiError('Attempt to set volume, but no video found.');
|
|
return;
|
|
}
|
|
|
|
worldRenderer.videoProxy.setVolume(e.volumeLevel);
|
|
volume = e.volumeLevel;
|
|
Util.sendParentMessage({
|
|
type: 'volumechange',
|
|
data: e.volumeLevel
|
|
});
|
|
}
|
|
|
|
function onMuted(e) {
|
|
// Only work for video. If there's no video, send back an error.
|
|
if (!worldRenderer.videoProxy) {
|
|
onApiError('Attempt to mute, but no video found.');
|
|
return;
|
|
}
|
|
|
|
worldRenderer.videoProxy.mute(e.muteState);
|
|
|
|
Util.sendParentMessage({
|
|
type: 'muted',
|
|
data: e.muteState
|
|
});
|
|
}
|
|
|
|
function onUpdateCurrentTime(time) {
|
|
if (!worldRenderer.videoProxy) {
|
|
onApiError('Attempt to pause, but no video found.');
|
|
return;
|
|
}
|
|
|
|
worldRenderer.videoProxy.setCurrentTime(time);
|
|
onGetCurrentTime();
|
|
}
|
|
|
|
function onGetCurrentTime() {
|
|
var time = worldRenderer.videoProxy.getCurrentTime();
|
|
Util.sendParentMessage({
|
|
type: 'timeupdate',
|
|
data: time
|
|
});
|
|
}
|
|
|
|
function onSetFullscreen() {
|
|
if (!worldRenderer.videoProxy) {
|
|
onApiError('Attempt to set fullscreen, but no video found.');
|
|
return;
|
|
}
|
|
worldRenderer.manager.onFSClick_();
|
|
}
|
|
|
|
function onApiError(message) {
|
|
console.error(message);
|
|
Util.sendParentMessage({
|
|
type: 'error',
|
|
data: {message: message}
|
|
});
|
|
}
|
|
|
|
function onModeChange(mode) {
|
|
Util.sendParentMessage({
|
|
type: 'modechange',
|
|
data: {mode: mode}
|
|
});
|
|
}
|
|
|
|
function onHotspotClick(id) {
|
|
Util.sendParentMessage({
|
|
type: 'click',
|
|
data: {id: id}
|
|
});
|
|
}
|
|
|
|
function onPlay() {
|
|
Util.sendParentMessage({
|
|
type: 'paused',
|
|
data: false
|
|
});
|
|
}
|
|
|
|
function onPause() {
|
|
Util.sendParentMessage({
|
|
type: 'paused',
|
|
data: true
|
|
});
|
|
}
|
|
|
|
function onEnded() {
|
|
Util.sendParentMessage({
|
|
type: 'ended',
|
|
data: true
|
|
});
|
|
}
|
|
|
|
function onSceneError(message) {
|
|
showError('Loader: ' + message);
|
|
}
|
|
|
|
function onRenderError(message) {
|
|
showError('Render: ' + message);
|
|
}
|
|
|
|
function showError(message) {
|
|
// Hide loading indicator.
|
|
loadIndicator.hide();
|
|
|
|
// Sanitize `message` as it could contain user supplied
|
|
// values. Re-add the space character as to not modify the
|
|
// error messages used throughout the codebase.
|
|
message = encodeURI(message).replace(/%20/g, ' ');
|
|
|
|
var error = document.querySelector('#error');
|
|
error.classList.add('visible');
|
|
error.querySelector('.message').innerHTML = message;
|
|
|
|
error.querySelector('.title').innerHTML = 'Error';
|
|
}
|
|
|
|
function hideError() {
|
|
var error = document.querySelector('#error');
|
|
error.classList.remove('visible');
|
|
}
|
|
|
|
function showPlayButton() {
|
|
var playButton = document.querySelector('#play-overlay');
|
|
playButton.classList.add('visible');
|
|
}
|
|
|
|
function hidePlayButton() {
|
|
var playButton = document.querySelector('#play-overlay');
|
|
playButton.classList.remove('visible');
|
|
}
|
|
|
|
function showStats() {
|
|
stats.setMode(0); // 0: fps, 1: ms
|
|
|
|
// Align bottom-left.
|
|
stats.domElement.style.position = 'absolute';
|
|
stats.domElement.style.left = '0px';
|
|
stats.domElement.style.bottom = '0px';
|
|
document.body.appendChild(stats.domElement);
|
|
}
|
|
|
|
function loop(time) {
|
|
// Use the VRDisplay RAF if it is present.
|
|
if (worldRenderer.vrDisplay) {
|
|
worldRenderer.vrDisplay.requestAnimationFrame(loop);
|
|
} else {
|
|
requestAnimationFrame(loop);
|
|
}
|
|
|
|
stats.begin();
|
|
// Update the video if needed.
|
|
if (worldRenderer.videoProxy) {
|
|
worldRenderer.videoProxy.update(time);
|
|
}
|
|
worldRenderer.render(time);
|
|
worldRenderer.submitFrame();
|
|
stats.end();
|
|
}
|
|
function onGetPosition() {
|
|
Util.sendParentMessage({
|
|
type: 'getposition',
|
|
data: {
|
|
Yaw: worldRenderer.camera.rotation.y * 180 / Math.PI,
|
|
Pitch: worldRenderer.camera.rotation.x * 180 / Math.PI
|
|
}
|
|
});
|
|
}
|
|
|
|
},{"../../node_modules/stats-js/build/stats.min":6,"../message":44,"../util":45,"./iframe-message-receiver":36,"./loading-indicator":37,"./scene-info":40,"./world-renderer":43,"es6-promise":2,"webvr-polyfill":22}],39:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
function ReticleRenderer(camera) {
|
|
this.camera = camera;
|
|
|
|
this.reticle = this.createReticle_();
|
|
// In front of the hotspot itself, which is at r=0.99.
|
|
this.reticle.position.z = -0.97;
|
|
camera.add(this.reticle);
|
|
|
|
this.setVisibility(false);
|
|
}
|
|
|
|
ReticleRenderer.prototype.setVisibility = function(isVisible) {
|
|
// TODO: Tween the transition.
|
|
this.reticle.visible = isVisible;
|
|
};
|
|
|
|
ReticleRenderer.prototype.createReticle_ = function() {
|
|
// Make a torus.
|
|
var geometry = new THREE.TorusGeometry(0.02, 0.005, 10, 20);
|
|
var material = new THREE.MeshBasicMaterial({color: 0x000000});
|
|
var torus = new THREE.Mesh(geometry, material);
|
|
|
|
return torus;
|
|
};
|
|
|
|
module.exports = ReticleRenderer;
|
|
|
|
},{}],40:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Util = _dereq_('../util');
|
|
|
|
var CAMEL_TO_UNDERSCORE = {
|
|
video: 'video',
|
|
image: 'image',
|
|
preview: 'preview',
|
|
loop: 'loop',
|
|
volume: 'volume',
|
|
muted: 'muted',
|
|
isStereo: 'is_stereo',
|
|
defaultYaw: 'default_yaw',
|
|
isYawOnly: 'is_yaw_only',
|
|
isDebug: 'is_debug',
|
|
isVROff: 'is_vr_off',
|
|
isAutopanOff: 'is_autopan_off',
|
|
hideFullscreenButton: 'hide_fullscreen_button'
|
|
};
|
|
|
|
/**
|
|
* Contains all information about a given scene.
|
|
*/
|
|
function SceneInfo(opt_params) {
|
|
var params = opt_params || {};
|
|
params.player = {
|
|
loop: opt_params.loop,
|
|
volume: opt_params.volume,
|
|
muted: opt_params.muted
|
|
};
|
|
|
|
this.image = params.image !== undefined ? encodeURI(params.image) : undefined;
|
|
this.preview = params.preview !== undefined ? encodeURI(params.preview) : undefined;
|
|
this.video = params.video !== undefined ? encodeURI(params.video) : undefined;
|
|
this.defaultYaw = THREE.Math.degToRad(params.defaultYaw || 0);
|
|
|
|
this.isStereo = Util.parseBoolean(params.isStereo);
|
|
this.isYawOnly = Util.parseBoolean(params.isYawOnly);
|
|
this.isDebug = Util.parseBoolean(params.isDebug);
|
|
this.isVROff = Util.parseBoolean(params.isVROff);
|
|
this.isAutopanOff = Util.parseBoolean(params.isAutopanOff);
|
|
this.loop = Util.parseBoolean(params.player.loop);
|
|
this.volume = parseFloat(
|
|
params.player.volume ? params.player.volume : '1');
|
|
this.muted = Util.parseBoolean(params.player.muted);
|
|
this.hideFullscreenButton = Util.parseBoolean(params.hideFullscreenButton);
|
|
}
|
|
|
|
SceneInfo.loadFromGetParams = function() {
|
|
var params = {};
|
|
for (var camelCase in CAMEL_TO_UNDERSCORE) {
|
|
var underscore = CAMEL_TO_UNDERSCORE[camelCase];
|
|
params[camelCase] = Util.getQueryParameter(underscore)
|
|
|| ((window.WebVRConfig && window.WebVRConfig.PLAYER) ? window.WebVRConfig.PLAYER[underscore] : "");
|
|
}
|
|
var scene = new SceneInfo(params);
|
|
if (!scene.isValid()) {
|
|
console.warn('Invalid scene: %s', scene.errorMessage);
|
|
}
|
|
return scene;
|
|
};
|
|
|
|
SceneInfo.loadFromAPIParams = function(underscoreParams) {
|
|
var params = {};
|
|
for (var camelCase in CAMEL_TO_UNDERSCORE) {
|
|
var underscore = CAMEL_TO_UNDERSCORE[camelCase];
|
|
if (underscoreParams[underscore]) {
|
|
params[camelCase] = underscoreParams[underscore];
|
|
}
|
|
}
|
|
var scene = new SceneInfo(params);
|
|
if (!scene.isValid()) {
|
|
console.warn('Invalid scene: %s', scene.errorMessage);
|
|
}
|
|
return scene;
|
|
};
|
|
|
|
SceneInfo.prototype.isValid = function() {
|
|
// Either it's an image or a video.
|
|
if (!this.image && !this.video) {
|
|
this.errorMessage = 'Either image or video URL must be specified.';
|
|
return false;
|
|
}
|
|
if (this.image && !this.isValidImage_(this.image)) {
|
|
this.errorMessage = 'Invalid image URL: ' + this.image;
|
|
return false;
|
|
}
|
|
this.errorMessage = null;
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* Generates a URL to reflect this scene.
|
|
*/
|
|
SceneInfo.prototype.getCurrentUrl = function() {
|
|
var url = location.protocol + '//' + location.host + location.pathname + '?';
|
|
for (var camelCase in CAMEL_TO_UNDERSCORE) {
|
|
var underscore = CAMEL_TO_UNDERSCORE[camelCase];
|
|
var value = this[camelCase];
|
|
if (value !== undefined) {
|
|
url += underscore + '=' + value + '&';
|
|
}
|
|
}
|
|
// Chop off the trailing ampersand.
|
|
return url.substring(0, url.length - 1);
|
|
};
|
|
|
|
SceneInfo.prototype.isValidImage_ = function(imageUrl) {
|
|
return true;
|
|
};
|
|
|
|
module.exports = SceneInfo;
|
|
|
|
},{"../util":45}],41:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Eyes = _dereq_('./eyes');
|
|
var TWEEN = _dereq_('@tweenjs/tween.js');
|
|
var Util = _dereq_('../util');
|
|
var VideoType = _dereq_('../video-type');
|
|
|
|
function SphereRenderer(scene) {
|
|
this.scene = scene;
|
|
|
|
// Create a transparent mask.
|
|
this.createOpacityMask_();
|
|
}
|
|
|
|
/**
|
|
* Sets the photosphere based on the image in the source. Supports stereo and
|
|
* mono photospheres.
|
|
*
|
|
* @return {Promise}
|
|
*/
|
|
SphereRenderer.prototype.setPhotosphere = function(src, opt_params) {
|
|
return new Promise(function(resolve, reject) {
|
|
this.resolve = resolve;
|
|
this.reject = reject;
|
|
|
|
var params = opt_params || {};
|
|
|
|
this.isStereo = !!params.isStereo;
|
|
this.src = src;
|
|
|
|
// Load texture.
|
|
var loader = new THREE.TextureLoader();
|
|
loader.crossOrigin = 'anonymous';
|
|
loader.load(src, this.onTextureLoaded_.bind(this), undefined,
|
|
this.onTextureError_.bind(this));
|
|
}.bind(this));
|
|
};
|
|
|
|
/**
|
|
* @return {Promise} Yeah.
|
|
*/
|
|
SphereRenderer.prototype.set360Video = function (videoElement, videoType, opt_params) {
|
|
return new Promise(function(resolve, reject) {
|
|
this.resolve = resolve;
|
|
this.reject = reject;
|
|
|
|
var params = opt_params || {};
|
|
|
|
this.isStereo = !!params.isStereo;
|
|
|
|
// Load the video texture.
|
|
var videoTexture = new THREE.VideoTexture(videoElement);
|
|
videoTexture.minFilter = THREE.LinearFilter;
|
|
videoTexture.magFilter = THREE.LinearFilter;
|
|
videoTexture.generateMipmaps = false;
|
|
|
|
if (Util.isSafari() && videoType === VideoType.HLS) {
|
|
// fix black screen issue on safari
|
|
videoTexture.format = THREE.RGBAFormat;
|
|
videoTexture.flipY = false;
|
|
} else {
|
|
videoTexture.format = THREE.RGBFormat;
|
|
}
|
|
|
|
videoTexture.needsUpdate = true;
|
|
|
|
this.onTextureLoaded_(videoTexture);
|
|
}.bind(this));
|
|
};
|
|
|
|
/**
|
|
* Set the opacity of the panorama.
|
|
*
|
|
* @param {Number} opacity How opaque we want the panorama to be. 0 means black,
|
|
* 1 means full color.
|
|
* @param {Number} duration Number of milliseconds the transition should take.
|
|
*
|
|
* @return {Promise} When the opacity change is complete.
|
|
*/
|
|
SphereRenderer.prototype.setOpacity = function(opacity, duration) {
|
|
var scene = this.scene;
|
|
// If we want the opacity
|
|
var overlayOpacity = 1 - opacity;
|
|
return new Promise(function(resolve, reject) {
|
|
var mask = scene.getObjectByName('opacityMask');
|
|
var tween = new TWEEN.Tween({opacity: mask.material.opacity})
|
|
.to({opacity: overlayOpacity}, duration)
|
|
.easing(TWEEN.Easing.Quadratic.InOut);
|
|
tween.onUpdate(function(e) {
|
|
mask.material.opacity = this.opacity;
|
|
});
|
|
tween.onComplete(resolve).start();
|
|
});
|
|
};
|
|
|
|
SphereRenderer.prototype.onTextureLoaded_ = function(texture) {
|
|
var sphereLeft;
|
|
var sphereRight;
|
|
if (this.isStereo) {
|
|
sphereLeft = this.createPhotosphere_(texture, {offsetY: 0.5, scaleY: 0.5});
|
|
sphereRight = this.createPhotosphere_(texture, {offsetY: 0, scaleY: 0.5});
|
|
} else {
|
|
sphereLeft = this.createPhotosphere_(texture);
|
|
sphereRight = this.createPhotosphere_(texture);
|
|
}
|
|
|
|
// Display in left and right eye respectively.
|
|
sphereLeft.layers.set(Eyes.LEFT);
|
|
sphereLeft.eye = Eyes.LEFT;
|
|
sphereLeft.name = 'eyeLeft';
|
|
sphereRight.layers.set(Eyes.RIGHT);
|
|
sphereRight.eye = Eyes.RIGHT;
|
|
sphereRight.name = 'eyeRight';
|
|
|
|
|
|
this.scene.getObjectByName('photo').children = [sphereLeft, sphereRight];
|
|
|
|
this.resolve();
|
|
};
|
|
|
|
SphereRenderer.prototype.onTextureError_ = function(error) {
|
|
this.reject('Unable to load texture from "' + this.src + '"');
|
|
};
|
|
|
|
|
|
SphereRenderer.prototype.createPhotosphere_ = function(texture, opt_params) {
|
|
var p = opt_params || {};
|
|
p.scaleX = p.scaleX || 1;
|
|
p.scaleY = p.scaleY || 1;
|
|
p.offsetX = p.offsetX || 0;
|
|
p.offsetY = p.offsetY || 0;
|
|
p.phiStart = p.phiStart || 0;
|
|
p.phiLength = p.phiLength || Math.PI * 2;
|
|
p.thetaStart = p.thetaStart || 0;
|
|
p.thetaLength = p.thetaLength || Math.PI;
|
|
|
|
var geometry = new THREE.SphereGeometry(1, 48, 48,
|
|
p.phiStart, p.phiLength, p.thetaStart, p.thetaLength);
|
|
geometry.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1));
|
|
var uvs = geometry.faceVertexUvs[0];
|
|
for (var i = 0; i < uvs.length; i ++) {
|
|
for (var j = 0; j < 3; j ++) {
|
|
uvs[i][j].x *= p.scaleX;
|
|
uvs[i][j].x += p.offsetX;
|
|
uvs[i][j].y *= p.scaleY;
|
|
uvs[i][j].y += p.offsetY;
|
|
}
|
|
}
|
|
|
|
var material;
|
|
if (texture.format === THREE.RGBAFormat && texture.flipY === false) {
|
|
material = new THREE.ShaderMaterial({
|
|
uniforms: {
|
|
texture: { value: texture }
|
|
},
|
|
vertexShader: [
|
|
"varying vec2 vUV;",
|
|
"void main() {",
|
|
" vUV = vec2( uv.x, 1.0 - uv.y );",
|
|
" gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
|
|
"}"
|
|
].join("\n"),
|
|
fragmentShader: [
|
|
"uniform sampler2D texture;",
|
|
"varying vec2 vUV;",
|
|
"void main() {",
|
|
" gl_FragColor = texture2D( texture, vUV )" + (Util.isIOS() ? ".bgra" : "") + ";",
|
|
"}"
|
|
].join("\n")
|
|
});
|
|
} else {
|
|
material = new THREE.MeshBasicMaterial({ map: texture });
|
|
}
|
|
var out = new THREE.Mesh(geometry, material);
|
|
//out.visible = false;
|
|
out.renderOrder = -1;
|
|
return out;
|
|
};
|
|
|
|
SphereRenderer.prototype.createOpacityMask_ = function() {
|
|
var geometry = new THREE.SphereGeometry(0.49, 48, 48);
|
|
var material = new THREE.MeshBasicMaterial({
|
|
color: 0x000000, side: THREE.DoubleSide, opacity: 0, transparent: true});
|
|
var opacityMask = new THREE.Mesh(geometry, material);
|
|
opacityMask.name = 'opacityMask';
|
|
opacityMask.renderOrder = 1;
|
|
|
|
this.scene.add(opacityMask);
|
|
return opacityMask;
|
|
};
|
|
|
|
module.exports = SphereRenderer;
|
|
|
|
},{"../util":45,"../video-type":46,"./eyes":34,"@tweenjs/tween.js":1}],42:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Util = _dereq_('../util');
|
|
|
|
/**
|
|
* A proxy class for working around the fact that as soon as a video is play()ed
|
|
* on iOS, Safari auto-fullscreens the video.
|
|
*
|
|
* TODO(smus): The entire raison d'etre for this class is to work around this
|
|
* issue. Once Safari implements some way to suppress this fullscreen player, we
|
|
* can remove this code.
|
|
*/
|
|
function VideoProxy(videoElement) {
|
|
this.videoElement = videoElement;
|
|
// True if we're currently manually advancing the playhead (only on iOS).
|
|
this.isFakePlayback = false;
|
|
|
|
// When the video started playing.
|
|
this.startTime = null;
|
|
}
|
|
|
|
VideoProxy.prototype.play = function() {
|
|
if (Util.isIOS9OrLess()) {
|
|
this.startTime = performance.now();
|
|
this.isFakePlayback = true;
|
|
|
|
// Make an audio element to playback just the audio part.
|
|
this.audioElement = new Audio();
|
|
this.audioElement.src = this.videoElement.src;
|
|
this.audioElement.play();
|
|
} else {
|
|
this.videoElement.play().then(function(e) {
|
|
console.log('Playing video.', e);
|
|
});
|
|
}
|
|
};
|
|
|
|
VideoProxy.prototype.pause = function() {
|
|
if (Util.isIOS9OrLess() && this.isFakePlayback) {
|
|
this.isFakePlayback = true;
|
|
|
|
this.audioElement.pause();
|
|
} else {
|
|
this.videoElement.pause();
|
|
}
|
|
};
|
|
|
|
VideoProxy.prototype.setVolume = function(volumeLevel) {
|
|
if (this.videoElement) {
|
|
// On iOS 10, the VideoElement.volume property is read-only. So we special
|
|
// case muting and unmuting.
|
|
if (Util.isIOS()) {
|
|
this.videoElement.muted = (volumeLevel === 0);
|
|
} else {
|
|
this.videoElement.volume = volumeLevel;
|
|
}
|
|
}
|
|
if (this.audioElement) {
|
|
this.audioElement.volume = volumeLevel;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Set the attribute mute of the elements according with the muteState param.
|
|
*
|
|
* @param bool muteState
|
|
*/
|
|
VideoProxy.prototype.mute = function(muteState) {
|
|
if (this.videoElement) {
|
|
this.videoElement.muted = muteState;
|
|
}
|
|
if (this.audioElement) {
|
|
this.audioElement.muted = muteState;
|
|
}
|
|
};
|
|
|
|
VideoProxy.prototype.getCurrentTime = function() {
|
|
return Util.isIOS9OrLess() ? this.audioElement.currentTime : this.videoElement.currentTime;
|
|
};
|
|
|
|
/**
|
|
*
|
|
* @param {Object} time
|
|
*/
|
|
VideoProxy.prototype.setCurrentTime = function(time) {
|
|
if (this.videoElement) {
|
|
this.videoElement.currentTime = time.currentTime;
|
|
}
|
|
if (this.audioElement) {
|
|
this.audioElement.currentTime = time.currentTime;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Called on RAF to progress playback.
|
|
*/
|
|
VideoProxy.prototype.update = function() {
|
|
// Fakes playback for iOS only.
|
|
if (!this.isFakePlayback) {
|
|
return;
|
|
}
|
|
var duration = this.videoElement.duration;
|
|
var now = performance.now();
|
|
var delta = now - this.startTime;
|
|
var deltaS = delta / 1000;
|
|
this.videoElement.currentTime = deltaS;
|
|
|
|
// Loop through the video
|
|
if (deltaS > duration) {
|
|
this.startTime = now;
|
|
this.videoElement.currentTime = 0;
|
|
// Also restart the audio.
|
|
this.audioElement.currentTime = 0;
|
|
}
|
|
};
|
|
|
|
module.exports = VideoProxy;
|
|
|
|
},{"../util":45}],43:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
var AdaptivePlayer = _dereq_('./adaptive-player');
|
|
var EventEmitter = _dereq_('eventemitter3');
|
|
var Eyes = _dereq_('./eyes');
|
|
var HotspotRenderer = _dereq_('./hotspot-renderer');
|
|
var ReticleRenderer = _dereq_('./reticle-renderer');
|
|
var SphereRenderer = _dereq_('./sphere-renderer');
|
|
var TWEEN = _dereq_('@tweenjs/tween.js');
|
|
var Util = _dereq_('../util');
|
|
var VideoProxy = _dereq_('./video-proxy');
|
|
var WebVRManager = _dereq_('webvr-boilerplate');
|
|
|
|
var AUTOPAN_DURATION = 3000;
|
|
var AUTOPAN_ANGLE = 0.4;
|
|
|
|
/**
|
|
* The main WebGL rendering entry point. Manages the scene, camera, VR-related
|
|
* rendering updates. Interacts with the WebVRManager.
|
|
*
|
|
* Coordinates the other renderers: SphereRenderer, HotspotRenderer,
|
|
* ReticleRenderer.
|
|
*
|
|
* Also manages the AdaptivePlayer and VideoProxy.
|
|
*
|
|
* Emits the following events:
|
|
* load: when the scene is loaded.
|
|
* error: if there is an error loading the scene.
|
|
* modechange(Boolean isVR): if the mode (eg. VR, fullscreen, etc) changes.
|
|
*/
|
|
function WorldRenderer(params) {
|
|
this.init_(params.hideFullscreenButton);
|
|
|
|
this.sphereRenderer = new SphereRenderer(this.scene);
|
|
this.hotspotRenderer = new HotspotRenderer(this);
|
|
this.hotspotRenderer.on('focus', this.onHotspotFocus_.bind(this));
|
|
this.hotspotRenderer.on('blur', this.onHotspotBlur_.bind(this));
|
|
this.reticleRenderer = new ReticleRenderer(this.camera);
|
|
|
|
// Get the VR Display as soon as we initialize.
|
|
navigator.getVRDisplays().then(function(displays) {
|
|
if (displays.length > 0) {
|
|
this.vrDisplay = displays[0];
|
|
}
|
|
}.bind(this));
|
|
|
|
}
|
|
WorldRenderer.prototype = new EventEmitter();
|
|
|
|
WorldRenderer.prototype.render = function(time) {
|
|
this.controls.update();
|
|
TWEEN.update(time);
|
|
this.effect.render(this.scene, this.camera);
|
|
this.hotspotRenderer.update(this.camera);
|
|
};
|
|
|
|
/**
|
|
* @return {Promise} When the scene is fully loaded.
|
|
*/
|
|
WorldRenderer.prototype.setScene = function(scene) {
|
|
var self = this;
|
|
var promise = new Promise(function(resolve, reject) {
|
|
self.sceneResolve = resolve;
|
|
self.sceneReject = reject;
|
|
});
|
|
|
|
if (!scene || !scene.isValid()) {
|
|
this.didLoadFail_(scene.errorMessage);
|
|
return;
|
|
}
|
|
|
|
var params = {
|
|
isStereo: scene.isStereo,
|
|
loop: scene.loop,
|
|
volume: scene.volume,
|
|
muted: scene.muted
|
|
};
|
|
|
|
this.setDefaultYaw_(scene.defaultYaw || 0);
|
|
|
|
// Disable VR mode if explicitly disabled, or if we're loading a video on iOS
|
|
// 9 or earlier.
|
|
if (scene.isVROff || (scene.video && Util.isIOS9OrLess())) {
|
|
this.manager.setVRCompatibleOverride(false);
|
|
}
|
|
|
|
// Set various callback overrides in iOS.
|
|
if (Util.isIOS()) {
|
|
this.manager.setFullscreenCallback(function() {
|
|
Util.sendParentMessage({type: 'enter-fullscreen'});
|
|
});
|
|
this.manager.setExitFullscreenCallback(function() {
|
|
Util.sendParentMessage({type: 'exit-fullscreen'});
|
|
});
|
|
this.manager.setVRCallback(function() {
|
|
Util.sendParentMessage({type: 'enter-vr'});
|
|
});
|
|
}
|
|
|
|
// If we're dealing with an image, and not a video.
|
|
if (scene.image && !scene.video) {
|
|
if (scene.preview) {
|
|
// First load the preview.
|
|
this.sphereRenderer.setPhotosphere(scene.preview, params).then(function() {
|
|
// As soon as something is loaded, emit the load event to hide the
|
|
// loading progress bar.
|
|
self.didLoad_();
|
|
// Then load the full resolution image.
|
|
self.sphereRenderer.setPhotosphere(scene.image, params);
|
|
}).catch(self.didLoadFail_.bind(self));
|
|
} else {
|
|
// No preview -- go straight to rendering the full image.
|
|
this.sphereRenderer.setPhotosphere(scene.image, params).then(function() {
|
|
self.didLoad_();
|
|
}).catch(self.didLoadFail_.bind(self));
|
|
}
|
|
} else if (scene.video) {
|
|
if (Util.isIE11()) {
|
|
// On IE 11, if an 'image' param is provided, load it instead of showing
|
|
// an error.
|
|
//
|
|
// TODO(smus): Once video textures are supported, remove this fallback.
|
|
if (scene.image) {
|
|
this.sphereRenderer.setPhotosphere(scene.image, params).then(function() {
|
|
self.didLoad_();
|
|
}).catch(self.didLoadFail_.bind(self));
|
|
} else {
|
|
this.didLoadFail_('Video is not supported on IE11.');
|
|
}
|
|
} else {
|
|
this.player = new AdaptivePlayer(params);
|
|
this.player.on('load', function(videoElement, videoType) {
|
|
self.sphereRenderer.set360Video(videoElement, videoType, params).then(function() {
|
|
self.didLoad_({videoElement: videoElement});
|
|
}).catch(self.didLoadFail_.bind(self));
|
|
});
|
|
this.player.on('error', function(error) {
|
|
self.didLoadFail_('Video load error: ' + error);
|
|
});
|
|
this.player.load(scene.video);
|
|
|
|
this.videoProxy = new VideoProxy(this.player.video);
|
|
}
|
|
}
|
|
|
|
this.sceneInfo = scene;
|
|
if (Util.isDebug()) {
|
|
console.log('Loaded scene', scene);
|
|
}
|
|
|
|
return promise;
|
|
};
|
|
|
|
WorldRenderer.prototype.isVRMode = function() {
|
|
return !!this.vrDisplay && this.vrDisplay.isPresenting;
|
|
};
|
|
|
|
WorldRenderer.prototype.submitFrame = function() {
|
|
if (this.isVRMode()) {
|
|
this.vrDisplay.submitFrame();
|
|
}
|
|
};
|
|
|
|
WorldRenderer.prototype.disposeEye_ = function(eye) {
|
|
if (eye) {
|
|
if (eye.material.map) {
|
|
eye.material.map.dispose();
|
|
}
|
|
eye.material.dispose();
|
|
eye.geometry.dispose();
|
|
}
|
|
};
|
|
|
|
WorldRenderer.prototype.dispose = function() {
|
|
var eyeLeft = this.scene.getObjectByName('eyeLeft');
|
|
this.disposeEye_(eyeLeft);
|
|
var eyeRight = this.scene.getObjectByName('eyeRight');
|
|
this.disposeEye_(eyeRight);
|
|
};
|
|
|
|
WorldRenderer.prototype.destroy = function() {
|
|
if (this.player) {
|
|
this.player.removeAllListeners();
|
|
this.player.destroy();
|
|
this.player = null;
|
|
}
|
|
var photo = this.scene.getObjectByName('photo');
|
|
var eyeLeft = this.scene.getObjectByName('eyeLeft');
|
|
var eyeRight = this.scene.getObjectByName('eyeRight');
|
|
|
|
if (eyeLeft) {
|
|
this.disposeEye_(eyeLeft);
|
|
photo.remove(eyeLeft);
|
|
this.scene.remove(eyeLeft);
|
|
}
|
|
|
|
if (eyeRight) {
|
|
this.disposeEye_(eyeRight);
|
|
photo.remove(eyeRight);
|
|
this.scene.remove(eyeRight);
|
|
}
|
|
};
|
|
|
|
WorldRenderer.prototype.didLoad_ = function(opt_event) {
|
|
var event = opt_event || {};
|
|
this.emit('load', event);
|
|
if (this.sceneResolve) {
|
|
this.sceneResolve();
|
|
}
|
|
};
|
|
|
|
WorldRenderer.prototype.didLoadFail_ = function(message) {
|
|
this.emit('error', message);
|
|
if (this.sceneReject) {
|
|
this.sceneReject(message);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Sets the default yaw.
|
|
* @param {Number} angleRad The yaw in radians.
|
|
*/
|
|
WorldRenderer.prototype.setDefaultYaw_ = function(angleRad) {
|
|
// Rotate the camera parent to take into account the scene's rotation.
|
|
// By default, it should be at the center of the image.
|
|
var display = this.controls.getVRDisplay();
|
|
// For desktop, we subtract the current display Y axis
|
|
var theta = display.theta_ || 0;
|
|
// For devices with orientation we make the current view center
|
|
if (display.poseSensor_) {
|
|
display.poseSensor_.resetPose();
|
|
}
|
|
this.camera.parent.rotation.y = (Math.PI / 2.0) + angleRad - theta;
|
|
};
|
|
|
|
/**
|
|
* Do the initial camera tween to rotate the camera, giving an indication that
|
|
* there is live content there (on desktop only).
|
|
*/
|
|
WorldRenderer.prototype.autopan = function(duration) {
|
|
var targetY = this.camera.parent.rotation.y - AUTOPAN_ANGLE;
|
|
var tween = new TWEEN.Tween(this.camera.parent.rotation)
|
|
.to({y: targetY}, AUTOPAN_DURATION)
|
|
.easing(TWEEN.Easing.Quadratic.Out)
|
|
.start();
|
|
};
|
|
|
|
WorldRenderer.prototype.init_ = function(hideFullscreenButton) {
|
|
var container = document.querySelector('body');
|
|
var aspect = window.innerWidth / window.innerHeight;
|
|
var camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 100);
|
|
camera.layers.enable(1);
|
|
|
|
var cameraDummy = new THREE.Object3D();
|
|
cameraDummy.add(camera);
|
|
|
|
// Antialiasing disabled to improve performance.
|
|
var renderer = new THREE.WebGLRenderer({antialias: false});
|
|
renderer.setClearColor(0x000000, 0);
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
renderer.setPixelRatio(window.devicePixelRatio);
|
|
|
|
container.appendChild(renderer.domElement);
|
|
|
|
var controls = new THREE.VRControls(camera);
|
|
var effect = new THREE.VREffect(renderer);
|
|
|
|
// Disable eye separation.
|
|
effect.scale = 0;
|
|
effect.setSize(window.innerWidth, window.innerHeight);
|
|
|
|
// Present submission of frames automatically. This is done manually in
|
|
// submitFrame().
|
|
effect.autoSubmitFrame = false;
|
|
|
|
this.camera = camera;
|
|
this.renderer = renderer;
|
|
this.effect = effect;
|
|
this.controls = controls;
|
|
this.manager = new WebVRManager(renderer, effect, {predistorted: false, hideButton: hideFullscreenButton});
|
|
|
|
this.scene = this.createScene_();
|
|
this.scene.add(this.camera.parent);
|
|
|
|
|
|
// Watch the resize event.
|
|
window.addEventListener('resize', this.onResize_.bind(this));
|
|
|
|
// Prevent context menu.
|
|
window.addEventListener('contextmenu', this.onContextMenu_.bind(this));
|
|
|
|
window.addEventListener('vrdisplaypresentchange',
|
|
this.onVRDisplayPresentChange_.bind(this));
|
|
};
|
|
|
|
WorldRenderer.prototype.onResize_ = function() {
|
|
this.effect.setSize(window.innerWidth, window.innerHeight);
|
|
this.camera.aspect = window.innerWidth / window.innerHeight;
|
|
this.camera.updateProjectionMatrix();
|
|
};
|
|
|
|
WorldRenderer.prototype.onVRDisplayPresentChange_ = function(e) {
|
|
if (Util.isDebug()) {
|
|
console.log('onVRDisplayPresentChange_');
|
|
}
|
|
var isVR = this.isVRMode();
|
|
|
|
// If the mode changed to VR and there is at least one hotspot, show reticle.
|
|
var isReticleVisible = isVR && this.hotspotRenderer.getCount() > 0;
|
|
this.reticleRenderer.setVisibility(isReticleVisible);
|
|
|
|
// Resize the renderer for good measure.
|
|
this.onResize_();
|
|
|
|
// Analytics.
|
|
if (window.analytics) {
|
|
analytics.logModeChanged(isVR);
|
|
}
|
|
|
|
// When exiting VR mode from iOS, make sure we emit back an exit-fullscreen event.
|
|
if (!isVR && Util.isIOS()) {
|
|
Util.sendParentMessage({type: 'exit-fullscreen'});
|
|
}
|
|
|
|
// Emit a mode change event back to any listeners.
|
|
this.emit('modechange', isVR);
|
|
};
|
|
|
|
WorldRenderer.prototype.createScene_ = function(opt_params) {
|
|
var scene = new THREE.Scene();
|
|
|
|
// Add a group for the photosphere.
|
|
var photoGroup = new THREE.Object3D();
|
|
photoGroup.name = 'photo';
|
|
scene.add(photoGroup);
|
|
|
|
return scene;
|
|
};
|
|
|
|
WorldRenderer.prototype.onHotspotFocus_ = function(id) {
|
|
// Set the default cursor to be a pointer.
|
|
this.setCursor_('pointer');
|
|
};
|
|
|
|
WorldRenderer.prototype.onHotspotBlur_ = function(id) {
|
|
// Reset the default cursor to be the default one.
|
|
this.setCursor_('');
|
|
};
|
|
|
|
WorldRenderer.prototype.setCursor_ = function(cursor) {
|
|
this.renderer.domElement.style.cursor = cursor;
|
|
};
|
|
|
|
WorldRenderer.prototype.onContextMenu_ = function(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
return false;
|
|
};
|
|
|
|
module.exports = WorldRenderer;
|
|
|
|
},{"../util":45,"./adaptive-player":33,"./eyes":34,"./hotspot-renderer":35,"./reticle-renderer":39,"./sphere-renderer":41,"./video-proxy":42,"@tweenjs/tween.js":1,"eventemitter3":3,"webvr-boilerplate":7}],44:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* Messages from the API to the embed.
|
|
*/
|
|
var Message = {
|
|
PLAY: 'play',
|
|
PAUSE: 'pause',
|
|
TIMEUPDATE: 'timeupdate',
|
|
ADD_HOTSPOT: 'addhotspot',
|
|
SET_CONTENT: 'setimage',
|
|
SET_VOLUME: 'setvolume',
|
|
MUTED: 'muted',
|
|
SET_CURRENT_TIME: 'setcurrenttime',
|
|
DEVICE_MOTION: 'devicemotion',
|
|
GET_POSITION: 'getposition',
|
|
SET_FULLSCREEN: 'setfullscreen',
|
|
};
|
|
|
|
module.exports = Message;
|
|
|
|
},{}],45:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
var Util = window.Util || {};
|
|
|
|
Util.isDataURI = function(src) {
|
|
return src && src.indexOf('data:') == 0;
|
|
};
|
|
|
|
Util.generateUUID = function() {
|
|
function s4() {
|
|
return Math.floor((1 + Math.random()) * 0x10000)
|
|
.toString(16)
|
|
.substring(1);
|
|
}
|
|
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
|
s4() + '-' + s4() + s4() + s4();
|
|
};
|
|
|
|
Util.isMobile = function() {
|
|
var check = false;
|
|
(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
|
|
return check;
|
|
};
|
|
|
|
Util.isIOS = function() {
|
|
return /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
|
|
};
|
|
|
|
Util.isSafari = function() {
|
|
return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
};
|
|
|
|
Util.cloneObject = function(obj) {
|
|
var out = {};
|
|
for (key in obj) {
|
|
out[key] = obj[key];
|
|
}
|
|
return out;
|
|
};
|
|
|
|
Util.hashCode = function(s) {
|
|
return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);
|
|
};
|
|
|
|
Util.loadTrackSrc = function(context, src, callback, opt_progressCallback) {
|
|
var request = new XMLHttpRequest();
|
|
request.open('GET', src, true);
|
|
request.responseType = 'arraybuffer';
|
|
|
|
// Decode asynchronously.
|
|
request.onload = function() {
|
|
context.decodeAudioData(request.response, function(buffer) {
|
|
callback(buffer);
|
|
}, function(e) {
|
|
console.error(e);
|
|
});
|
|
};
|
|
if (opt_progressCallback) {
|
|
request.onprogress = function(e) {
|
|
var percent = e.loaded / e.total;
|
|
opt_progressCallback(percent);
|
|
};
|
|
}
|
|
request.send();
|
|
};
|
|
|
|
Util.isPow2 = function(n) {
|
|
return (n & (n - 1)) == 0;
|
|
};
|
|
|
|
Util.capitalize = function(s) {
|
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
};
|
|
|
|
Util.isIFrame = function() {
|
|
try {
|
|
return window.self !== window.top;
|
|
} catch (e) {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
// From http://goo.gl/4WX3tg
|
|
Util.getQueryParameter = function(name) {
|
|
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
|
|
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
|
|
results = regex.exec(location.search);
|
|
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
|
|
};
|
|
|
|
|
|
// From http://stackoverflow.com/questions/11871077/proper-way-to-detect-webgl-support.
|
|
Util.isWebGLEnabled = function() {
|
|
var canvas = document.createElement('canvas');
|
|
try { gl = canvas.getContext("webgl"); }
|
|
catch (x) { gl = null; }
|
|
|
|
if (gl == null) {
|
|
try { gl = canvas.getContext("experimental-webgl"); experimental = true; }
|
|
catch (x) { gl = null; }
|
|
}
|
|
return !!gl;
|
|
};
|
|
|
|
Util.clone = function(obj) {
|
|
return JSON.parse(JSON.stringify(obj));
|
|
};
|
|
|
|
// From http://stackoverflow.com/questions/10140604/fastest-hypotenuse-in-javascript
|
|
Util.hypot = Math.hypot || function(x, y) {
|
|
return Math.sqrt(x*x + y*y);
|
|
};
|
|
|
|
// From http://stackoverflow.com/a/17447718/693934
|
|
Util.isIE11 = function() {
|
|
return navigator.userAgent.match(/Trident/);
|
|
};
|
|
|
|
Util.getRectCenter = function(rect) {
|
|
return new THREE.Vector2(rect.x + rect.width/2, rect.y + rect.height/2);
|
|
};
|
|
|
|
Util.getScreenWidth = function() {
|
|
return Math.max(window.screen.width, window.screen.height) *
|
|
window.devicePixelRatio;
|
|
};
|
|
|
|
Util.getScreenHeight = function() {
|
|
return Math.min(window.screen.width, window.screen.height) *
|
|
window.devicePixelRatio;
|
|
};
|
|
|
|
Util.isIOS9OrLess = function() {
|
|
if (!Util.isIOS()) {
|
|
return false;
|
|
}
|
|
var re = /(iPhone|iPad|iPod) OS ([\d_]+)/;
|
|
var iOSVersion = navigator.userAgent.match(re);
|
|
if (!iOSVersion) {
|
|
return false;
|
|
}
|
|
// Get the last group.
|
|
var versionString = iOSVersion[iOSVersion.length - 1];
|
|
var majorVersion = parseFloat(versionString);
|
|
return majorVersion <= 9;
|
|
};
|
|
|
|
Util.getExtension = function(url) {
|
|
return url.split('.').pop().split('?')[0];
|
|
};
|
|
|
|
Util.createGetParams = function(params) {
|
|
var out = '?';
|
|
for (var k in params) {
|
|
var paramString = k + '=' + params[k] + '&';
|
|
out += paramString;
|
|
}
|
|
// Remove the trailing ampersand.
|
|
out.substring(0, params.length - 2);
|
|
return out;
|
|
};
|
|
|
|
Util.sendParentMessage = function(message) {
|
|
if (window.parent) {
|
|
parent.postMessage(message, '*');
|
|
}
|
|
};
|
|
|
|
Util.parseBoolean = function(value) {
|
|
if (value == 'false' || value == 0) {
|
|
return false;
|
|
} else if (value == 'true' || value == 1) {
|
|
return true;
|
|
} else {
|
|
return !!value;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @param base {String} An absolute directory root.
|
|
* @param relative {String} A relative path.
|
|
*
|
|
* @returns {String} An absolute path corresponding to the rootPath.
|
|
*
|
|
* From http://stackoverflow.com/a/14780463/693934.
|
|
*/
|
|
Util.relativeToAbsolutePath = function(base, relative) {
|
|
var stack = base.split('/');
|
|
var parts = relative.split('/');
|
|
for (var i = 0; i < parts.length; i++) {
|
|
if (parts[i] == '.') {
|
|
continue;
|
|
}
|
|
if (parts[i] == '..') {
|
|
stack.pop();
|
|
} else {
|
|
stack.push(parts[i]);
|
|
}
|
|
}
|
|
return stack.join('/');
|
|
};
|
|
|
|
/**
|
|
* @return {Boolean} True iff the specified path is an absolute path.
|
|
*/
|
|
Util.isPathAbsolute = function(path) {
|
|
return ! /^(?:\/|[a-z]+:\/\/)/.test(path);
|
|
}
|
|
|
|
Util.isEmptyObject = function(obj) {
|
|
return Object.getOwnPropertyNames(obj).length == 0;
|
|
};
|
|
|
|
Util.isDebug = function() {
|
|
return Util.parseBoolean(Util.getQueryParameter('debug'));
|
|
};
|
|
|
|
Util.getCurrentScript = function() {
|
|
// Note: in IE11, document.currentScript doesn't work, so we fall back to this
|
|
// hack, taken from https://goo.gl/TpExuH.
|
|
if (!document.currentScript) {
|
|
console.warn('This browser does not support document.currentScript. Trying fallback.');
|
|
}
|
|
return document.currentScript || document.scripts[document.scripts.length - 1];
|
|
}
|
|
|
|
|
|
module.exports = Util;
|
|
|
|
},{}],46:[function(_dereq_,module,exports){
|
|
/*
|
|
* Copyright 2016 Google Inc. All Rights Reserved.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* Video Types
|
|
*/
|
|
var VideoTypes = {
|
|
HLS: 1,
|
|
DASH: 2,
|
|
VIDEO: 3
|
|
};
|
|
|
|
module.exports = VideoTypes;
|
|
},{}]},{},[38]);
|