aboutsummaryrefslogtreecommitdiff
path: root/assets/clapprio/clappr.js
diff options
context:
space:
mode:
authorFlorian Larysch2016-12-29 02:04:25 +0100
committerFlorian Larysch2016-12-29 02:04:25 +0100
commit14cd8a861efe666ab1d8fab44327b38a67fbd162 (patch)
treecd45bbb56a3edf80916962eebc189383e31c7e1e /assets/clapprio/clappr.js
parent7f0e67758967cace904fca142581176afca1272c (diff)
add clappr
Diffstat (limited to '')
-rw-r--r--assets/clapprio/clappr.js31516
1 files changed, 31516 insertions, 0 deletions
diff --git a/assets/clapprio/clappr.js b/assets/clapprio/clappr.js
new file mode 100644
index 0000000..1ee0b0a
--- /dev/null
+++ b/assets/clapprio/clappr.js
@@ -0,0 +1,31516 @@
+(function webpackUniversalModuleDefinition(root, factory) {
+ if(typeof exports === 'object' && typeof module === 'object')
+ module.exports = factory();
+ else if(typeof define === 'function' && define.amd)
+ define([], factory);
+ else if(typeof exports === 'object')
+ exports["Clappr"] = factory();
+ else
+ root["Clappr"] = factory();
+})(this, function() {
+return /******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId])
+/******/ return installedModules[moduleId].exports;
+
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ exports: {},
+/******/ id: moduleId,
+/******/ loaded: false
+/******/ };
+
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ // Flag the module as loaded
+/******/ module.loaded = true;
+
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+
+
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "<%=baseUrl%>/";
+
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _player = __webpack_require__(1);
+
+ var _player2 = _interopRequireDefault(_player);
+
+ var _utils = __webpack_require__(2);
+
+ var _utils2 = _interopRequireDefault(_utils);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ var _container_plugin = __webpack_require__(85);
+
+ var _container_plugin2 = _interopRequireDefault(_container_plugin);
+
+ var _core_plugin = __webpack_require__(105);
+
+ var _core_plugin2 = _interopRequireDefault(_core_plugin);
+
+ var _ui_core_plugin = __webpack_require__(100);
+
+ var _ui_core_plugin2 = _interopRequireDefault(_ui_core_plugin);
+
+ var _ui_container_plugin = __webpack_require__(80);
+
+ var _ui_container_plugin2 = _interopRequireDefault(_ui_container_plugin);
+
+ var _base_object = __webpack_require__(4);
+
+ var _base_object2 = _interopRequireDefault(_base_object);
+
+ var _ui_object = __webpack_require__(18);
+
+ var _ui_object2 = _interopRequireDefault(_ui_object);
+
+ var _browser = __webpack_require__(3);
+
+ var _browser2 = _interopRequireDefault(_browser);
+
+ var _container = __webpack_require__(22);
+
+ var _container2 = _interopRequireDefault(_container);
+
+ var _core = __webpack_require__(13);
+
+ var _core2 = _interopRequireDefault(_core);
+
+ var _loader = __webpack_require__(48);
+
+ var _loader2 = _interopRequireDefault(_loader);
+
+ var _mediator = __webpack_require__(30);
+
+ var _mediator2 = _interopRequireDefault(_mediator);
+
+ var _media_control = __webpack_require__(27);
+
+ var _media_control2 = _interopRequireDefault(_media_control);
+
+ var _player_info = __webpack_require__(45);
+
+ var _player_info2 = _interopRequireDefault(_player_info);
+
+ var _base_flash_playback = __webpack_require__(56);
+
+ var _base_flash_playback2 = _interopRequireDefault(_base_flash_playback);
+
+ var _flash = __webpack_require__(54);
+
+ var _flash2 = _interopRequireDefault(_flash);
+
+ var _flashls = __webpack_require__(63);
+
+ var _flashls2 = _interopRequireDefault(_flashls);
+
+ var _hls = __webpack_require__(67);
+
+ var _hls2 = _interopRequireDefault(_hls);
+
+ var _html5_audio = __webpack_require__(61);
+
+ var _html5_audio2 = _interopRequireDefault(_html5_audio);
+
+ var _html5_video = __webpack_require__(51);
+
+ var _html5_video2 = _interopRequireDefault(_html5_video);
+
+ var _html_img = __webpack_require__(71);
+
+ var _html_img2 = _interopRequireDefault(_html_img);
+
+ var _no_op = __webpack_require__(74);
+
+ var _no_op2 = _interopRequireDefault(_no_op);
+
+ var _poster = __webpack_require__(90);
+
+ var _poster2 = _interopRequireDefault(_poster);
+
+ var _log = __webpack_require__(6);
+
+ var _log2 = _interopRequireDefault(_log);
+
+ var _styler = __webpack_require__(15);
+
+ var _styler2 = _interopRequireDefault(_styler);
+
+ var _vendor = __webpack_require__(8);
+
+ var _vendor2 = _interopRequireDefault(_vendor);
+
+ var _template = __webpack_require__(17);
+
+ var _template2 = _interopRequireDefault(_template);
+
+ var _clapprZepto = __webpack_require__(16);
+
+ var _clapprZepto2 = _interopRequireDefault(_clapprZepto);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ var version = ("0.2.64"); // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ exports.default = {
+ Player: _player2.default,
+ Mediator: _mediator2.default,
+ Events: _events2.default,
+ Browser: _browser2.default,
+ PlayerInfo: _player_info2.default,
+ MediaControl: _media_control2.default,
+ ContainerPlugin: _container_plugin2.default,
+ UIContainerPlugin: _ui_container_plugin2.default,
+ CorePlugin: _core_plugin2.default,
+ UICorePlugin: _ui_core_plugin2.default,
+ Playback: _playback2.default,
+ Container: _container2.default,
+ Core: _core2.default,
+ Loader: _loader2.default,
+ BaseObject: _base_object2.default,
+ UIObject: _ui_object2.default,
+ Utils: _utils2.default,
+ BaseFlashPlayback: _base_flash_playback2.default,
+ Flash: _flash2.default,
+ FlasHLS: _flashls2.default,
+ HLS: _hls2.default,
+ HTML5Audio: _html5_audio2.default,
+ HTML5Video: _html5_video2.default,
+ HTMLImg: _html_img2.default,
+ NoOp: _no_op2.default,
+ Poster: _poster2.default,
+ Log: _log2.default,
+ Styler: _styler2.default,
+ Vendor: _vendor2.default,
+ version: version,
+ template: _template2.default,
+ $: _clapprZepto2.default
+ };
+ module.exports = exports['default'];
+
+/***/ },
+/* 1 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _utils = __webpack_require__(2);
+
+ var _base_object = __webpack_require__(4);
+
+ var _base_object2 = _interopRequireDefault(_base_object);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _browser = __webpack_require__(3);
+
+ var _browser2 = _interopRequireDefault(_browser);
+
+ var _core_factory = __webpack_require__(11);
+
+ var _core_factory2 = _interopRequireDefault(_core_factory);
+
+ var _loader = __webpack_require__(48);
+
+ var _loader2 = _interopRequireDefault(_loader);
+
+ var _player_info = __webpack_require__(45);
+
+ var _player_info2 = _interopRequireDefault(_player_info);
+
+ var _clapprZepto = __webpack_require__(16);
+
+ var _clapprZepto2 = _interopRequireDefault(_clapprZepto);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var baseUrl = (0, _utils.currentScriptUrl)().replace(/\/[^\/]+$/, '');
+
+ /**
+ * @class Player
+ * @constructor
+ * @extends BaseObject
+ * @module components
+ * @example
+ * ### Using the Player
+ *
+ * Add the following script on your HTML:
+ * ```html
+ * <head>
+ * <script type="text/javascript" src="http://cdn.clappr.io/latest/clappr.min.js"></script>
+ * </head>
+ * ```
+ * Now, create the player:
+ * ```html
+ * <body>
+ * <div id="player"></div>
+ * <script>
+ * var player = new Clappr.Player({source: "http://your.video/here.mp4", parentId: "#player"});
+ * </script>
+ * </body>
+ * ```
+ */
+
+ var Player = function (_BaseObject) {
+ _inherits(Player, _BaseObject);
+
+ _createClass(Player, [{
+ key: 'loader',
+ set: function set(loader) {
+ this._loader = loader;
+ },
+ get: function get() {
+ if (!this._loader) {
+ this._loader = new _loader2.default(this.options.plugins || {}, this.options.playerId);
+ }
+ return this._loader;
+ }
+
+ /**
+ * Determine if the playback has ended.
+ * @property ended
+ * @type Boolean
+ */
+
+ }, {
+ key: 'ended',
+ get: function get() {
+ return this.core.mediaControl.container.ended;
+ }
+
+ /**
+ * Determine if the playback is having to buffer in order for
+ * playback to be smooth.
+ * (i.e if a live stream is playing smoothly, this will be false)
+ * @property buffering
+ * @type Boolean
+ */
+
+ }, {
+ key: 'buffering',
+ get: function get() {
+ return this.core.mediaControl.container.buffering;
+ }
+
+ /*
+ * determine if the player is ready.
+ * @property isReady
+ * @type {Boolean} `true` if the player is ready. ie PLAYER_READY event has fired
+ */
+
+ }, {
+ key: 'isReady',
+ get: function get() {
+ return !!this._ready;
+ }
+
+ /**
+ * An events map that allows the user to add custom callbacks in player's options.
+ * @property eventsMapping
+ * @type {Object}
+ */
+
+ }, {
+ key: 'eventsMapping',
+ get: function get() {
+ return {
+ onReady: _events2.default.PLAYER_READY,
+ onResize: _events2.default.PLAYER_RESIZE,
+ onPlay: _events2.default.PLAYER_PLAY,
+ onPause: _events2.default.PLAYER_PAUSE,
+ onStop: _events2.default.PLAYER_STOP,
+ onEnded: _events2.default.PLAYER_ENDED,
+ onSeek: _events2.default.PLAYER_SEEK,
+ onError: _events2.default.PLAYER_ERROR,
+ onTimeUpdate: _events2.default.PLAYER_TIMEUPDATE,
+ onVolumeUpdate: _events2.default.PLAYER_VOLUMEUPDATE
+ };
+ }
+
+ /**
+ * ## Player's constructor
+ *
+ * You might pass the options object to build the player.
+ * ```javascript
+ * var options = {source: "http://example.com/video.mp4", param1: "val1"};
+ * var player = new Clappr.Player(options);
+ * ```
+ *
+ * @method constructor
+ * @param {Object} options Data
+ * options to build a player instance
+ * @param {Number} [options.width]
+ * player's width **default**: `640`
+ * @param {Number} [options.height]
+ * player's height **default**: `360`
+ * @param {String} [options.parentId]
+ * the id of the element on the page that the player should be inserted into
+ * @param {Object} [options.parent]
+ * a reference to a dom element that the player should be inserted into
+ * @param {String} [options.source]
+ * The media source URL, or {source: <<source URL>>, mimeType: <<source mime type>>}
+ * @param {Object} [options.sources]
+ * An array of media source URL's, or an array of {source: <<source URL>>, mimeType: <<source mime type>>}
+ * @param {Boolean} [options.autoPlay]
+ * automatically play after page load **default**: `false`
+ * @param {Boolean} [options.loop]
+ * automatically replay after it ends **default**: `false`
+ * @param {Boolean} [options.chromeless]
+ * player acts in chromeless mode **default**: `false`
+ * @param {Boolean} [options.allowUserInteraction]
+ * whether or not the player should handle click events when in chromeless mode **default**: `false` on desktops browsers, `true` on mobile.
+ * @param {Boolean} [options.disableKeyboardShortcuts]
+ * disable keyboard shortcuts. **default**: `false`. `true` if `allowUserInteraction` is `false`.
+ * @param {Boolean} [options.muted]
+ * start the video muted **default**: `false`
+ * @param {String} [options.mimeType]
+ * add `mimeType: "application/vnd.apple.mpegurl"` if you need to use a url without extension.
+ * @param {String} [options.actualLiveTime]
+ * show duration and seek time relative to actual time.
+ * @param {String} [options.actualLiveServerTime]
+ * specify server time as a string, format: "2015/11/26 06:01:03". This option is meant to be used with actualLiveTime.
+ * @param {Boolean} [options.persistConfig]
+ * persist player's settings (volume) through the same domain **default**: `true`
+ * @param {String} [options.preload]
+ * video will be preloaded according to `preload` attribute options **default**: `'metadata'`
+ * @param {Number} [options.maxBufferLength]
+ * the default behavior for the **HLS playback** is to keep buffering indefinitely, even on VoD.
+ * This replicates the behavior for progressive download, which continues buffering when pausing the video, thus making the video available for playback even on slow networks.
+ * To change this behavior use `maxBufferLength` where **value is in seconds**.
+ * @param {String} [options.gaAccount]
+ * enable Google Analytics events dispatch **(play/pause/stop/buffering/etc)** by adding your `gaAccount`
+ * @param {String} [options.gaTrackerName]
+ * besides `gaAccount` you can optionally, pass your favorite trackerName as `gaTrackerName`
+ * @param {Object} [options.mediacontrol]
+ * customize control bar colors, example: `mediacontrol: {seekbar: "#E113D3", buttons: "#66B2FF"}`
+ * @param {Boolean} [options.hideMediaControl]
+ * control media control auto hide **default**: `true`
+ * @param {Boolean} [options.hideVolumeBar]
+ * when embedded with width less than 320, volume bar will hide. You can force this behavior for all sizes by adding `true` **default**: `false`
+ * @param {String} [options.watermark]
+ * put `watermark: 'http://url/img.png'` on your embed parameters to automatically add watermark on your video.
+ * You can customize corner position by defining position parameter. Positions can be `bottom-left`, `bottom-right`, `top-left` and `top-right`.
+ * @param {String} [options.watermarkLink]
+ * `watermarkLink: 'http://example.net/'` - define URL to open when the watermark is clicked. If not provided watermark will not be clickable.
+ * @param {Boolean} [options.disableVideoTagContextMenu]
+ * disables the context menu (right click) on the video element if a HTML5Video playback is used.
+ * @param {Boolean} [options.autoSeekFromUrl]
+ * Automatically seek to the seconds provided in the url (e.g example.com?t=100) **default**: `true`
+ * @param {Boolean} [options.exitFullscreenOnEnd]
+ * Automatically exit full screen when the media finishes. **default**: `true`
+ * @param {String} [options.poster]
+ * define a poster by adding its address `poster: 'http://url/img.png'`. It will appear after video embed, disappear on play and go back when user stops the video.
+ * @param {String} [options.playbackNotSupportedMessage]
+ * define a custom message to be displayed when a playback is not supported.
+ * @param {Object} [options.events]
+ * Specify listeners which will be registered with their corresponding player events.
+ * E.g. onReady -> "PLAYER_READY", onTimeUpdate -> "PLAYER_TIMEUPDATE"
+ */
+
+ }]);
+
+ function Player(options) {
+ _classCallCheck(this, Player);
+
+ var _this = _possibleConstructorReturn(this, _BaseObject.call(this, options));
+
+ var defaultOptions = { playerId: (0, _utils.uniqueId)(''), persistConfig: true, width: 640, height: 360, baseUrl: baseUrl, allowUserInteraction: _browser2.default.isMobile };
+ _this._options = _clapprZepto2.default.extend(defaultOptions, options);
+ _this.options.sources = _this._normalizeSources(options);
+ if (!_this.options.chromeless) {
+ // "allowUserInteraction" cannot be false if not in chromeless mode.
+ _this.options.allowUserInteraction = true;
+ }
+ if (!_this.options.allowUserInteraction) {
+ // if user iteraction is not allowed ensure keyboard shortcuts are disabled
+ _this.options.disableKeyboardShortcuts = true;
+ }
+ _this._registerOptionEventListeners();
+ _this._coreFactory = new _core_factory2.default(_this);
+ _this.playerInfo = _player_info2.default.getInstance(_this.options.playerId);
+ _this.playerInfo.currentSize = { width: options.width, height: options.height };
+ _this.playerInfo.options = _this.options;
+ if (_this.options.parentId) {
+ _this.setParentId(_this.options.parentId);
+ } else if (_this.options.parent) {
+ _this.attachTo(_this.options.parent);
+ }
+ return _this;
+ }
+
+ /**
+ * Specify a `parentId` to the player.
+ * @method setParentId
+ * @param {String} parentId the element parent id.
+ * @return {Player} itself
+ */
+
+
+ Player.prototype.setParentId = function setParentId(parentId) {
+ var el = document.querySelector(parentId);
+ if (el) {
+ this.attachTo(el);
+ }
+ return this;
+ };
+
+ /**
+ * You can use this method to attach the player to a given element. You don't need to do this when you specify it during the player instantiation passing the `parentId` param.
+ * @method attachTo
+ * @param {Object} element a given element.
+ * @return {Player} itself
+ */
+
+
+ Player.prototype.attachTo = function attachTo(element) {
+ this.options.parentElement = element;
+ this.core = this._coreFactory.create();
+ this._addEventListeners();
+ return this;
+ };
+
+ Player.prototype._addEventListeners = function _addEventListeners() {
+ if (!this.core.isReady) {
+ this.listenToOnce(this.core, _events2.default.CORE_READY, this._onReady);
+ } else {
+ this._onReady();
+ }
+ this.listenTo(this.core.mediaControl, _events2.default.MEDIACONTROL_CONTAINERCHANGED, this._containerChanged);
+ this.listenTo(this.core, _events2.default.CORE_FULLSCREEN, this._onFullscreenChange);
+ return this;
+ };
+
+ Player.prototype._addContainerEventListeners = function _addContainerEventListeners() {
+ var container = this.core.mediaControl.container;
+ if (container) {
+ this.listenTo(container, _events2.default.CONTAINER_PLAY, this._onPlay);
+ this.listenTo(container, _events2.default.CONTAINER_PAUSE, this._onPause);
+ this.listenTo(container, _events2.default.CONTAINER_STOP, this._onStop);
+ this.listenTo(container, _events2.default.CONTAINER_ENDED, this._onEnded);
+ this.listenTo(container, _events2.default.CONTAINER_SEEK, this._onSeek);
+ this.listenTo(container, _events2.default.CONTAINER_ERROR, this._onError);
+ this.listenTo(container, _events2.default.CONTAINER_TIMEUPDATE, this._onTimeUpdate);
+ this.listenTo(container, _events2.default.CONTAINER_VOLUME, this._onVolumeUpdate);
+ }
+ return this;
+ };
+
+ Player.prototype._registerOptionEventListeners = function _registerOptionEventListeners() {
+ var _this2 = this;
+
+ var userEvents = this.options.events || {};
+ Object.keys(userEvents).forEach(function (userEvent) {
+ var eventType = _this2.eventsMapping[userEvent];
+ if (eventType) {
+ var eventFunction = userEvents[userEvent];
+ eventFunction = typeof eventFunction === 'function' && eventFunction;
+ eventFunction && _this2.on(eventType, eventFunction);
+ }
+ });
+ return this;
+ };
+
+ Player.prototype._containerChanged = function _containerChanged() {
+ this.stopListening();
+ this._addEventListeners();
+ };
+
+ Player.prototype._onReady = function _onReady() {
+ this._ready = true;
+ this._addContainerEventListeners();
+ this.trigger(_events2.default.PLAYER_READY);
+ };
+
+ Player.prototype._onFullscreenChange = function _onFullscreenChange(fullscreen) {
+ this.trigger(_events2.default.PLAYER_FULLSCREEN, fullscreen);
+ };
+
+ Player.prototype._onVolumeUpdate = function _onVolumeUpdate(volume) {
+ this.trigger(_events2.default.PLAYER_VOLUMEUPDATE, volume);
+ };
+
+ Player.prototype._onPlay = function _onPlay() {
+ this.trigger(_events2.default.PLAYER_PLAY);
+ };
+
+ Player.prototype._onPause = function _onPause() {
+ this.trigger(_events2.default.PLAYER_PAUSE);
+ };
+
+ Player.prototype._onStop = function _onStop() {
+ this.trigger(_events2.default.PLAYER_STOP, this.getCurrentTime());
+ };
+
+ Player.prototype._onEnded = function _onEnded() {
+ this.trigger(_events2.default.PLAYER_ENDED);
+ };
+
+ Player.prototype._onSeek = function _onSeek(time) {
+ this.trigger(_events2.default.PLAYER_SEEK, time);
+ };
+
+ Player.prototype._onTimeUpdate = function _onTimeUpdate(timeProgress) {
+ this.trigger(_events2.default.PLAYER_TIMEUPDATE, timeProgress);
+ };
+
+ Player.prototype._onError = function _onError(error) {
+ this.trigger(_events2.default.PLAYER_ERROR, error);
+ };
+
+ Player.prototype._normalizeSources = function _normalizeSources(options) {
+ var sources = options.sources || (options.source !== undefined ? [options.source] : []);
+ return sources.length === 0 ? [{ source: '', mimeType: '' }] : sources;
+ };
+
+ /**
+ * resizes the current player canvas.
+ * @method resize
+ * @param {Object} size should be a literal object with `height` and `width`.
+ * @return {Player} itself
+ * @example
+ * ```javascript
+ * player.resize({height: 360, width: 640})
+ * ```
+ */
+
+
+ Player.prototype.resize = function resize(size) {
+ this.core.resize(size);
+ return this;
+ };
+
+ /**
+ * loads a new source.
+ * @method load
+ * @param {Array|String} sources source or sources of video.
+ * An array item can be a string or {source: <<source URL>>, mimeType: <<source mime type>>}
+ * @param {String} mimeType a mime type, example: `'application/vnd.apple.mpegurl'`
+ * @param {Boolean} [autoPlay=false] whether playing should be started immediately
+ * @return {Player} itself
+ */
+
+
+ Player.prototype.load = function load(sources, mimeType, autoPlay) {
+ if (autoPlay !== undefined) {
+ this.configure({ autoPlay: !!autoPlay });
+ }
+ this.core.load(sources, mimeType);
+ return this;
+ };
+
+ /**
+ * destroys the current player and removes it from the DOM.
+ * @method destroy
+ * @return {Player} itself
+ */
+
+
+ Player.prototype.destroy = function destroy() {
+ this.core.destroy();
+ return this;
+ };
+
+ /**
+ * plays the current video (`source`).
+ * @method play
+ * @return {Player} itself
+ */
+
+
+ Player.prototype.play = function play() {
+ this.core.mediaControl.container.play();
+ return this;
+ };
+
+ /**
+ * pauses the current video (`source`).
+ * @method pause
+ * @return {Player} itself
+ */
+
+
+ Player.prototype.pause = function pause() {
+ this.core.mediaControl.container.pause();
+ return this;
+ };
+
+ /**
+ * stops the current video (`source`).
+ * @method stop
+ * @return {Player} itself
+ */
+
+
+ Player.prototype.stop = function stop() {
+ this.core.mediaControl.container.stop();
+ return this;
+ };
+
+ /**
+ * seeks the current video (`source`). For example, `player.seek(120)` will seek to second 120 (2minutes) of the current video.
+ * @method seek
+ * @param {Number} time should be a number between 0 and the video duration.
+ * @return {Player} itself
+ */
+
+
+ Player.prototype.seek = function seek(time) {
+ this.core.mediaControl.container.seek(time);
+ return this;
+ };
+
+ /**
+ * seeks the current video (`source`). For example, `player.seek(50)` will seek to the middle of the current video.
+ * @method seekPercentage
+ * @param {Number} time should be a number between 0 and 100.
+ * @return {Player} itself
+ */
+
+
+ Player.prototype.seekPercentage = function seekPercentage(percentage) {
+ this.core.mediaControl.container.seekPercentage(percentage);
+ return this;
+ };
+
+ /**
+ * Set the volume for the current video (`source`).
+ * @method setVolume
+ * @param {Number} volume should be a number between 0 and 100, 0 being mute and 100 the max volume.
+ * @return {Player} itself
+ */
+
+
+ Player.prototype.setVolume = function setVolume(volume) {
+ if (this.core && this.core.mediaControl) {
+ this.core.mediaControl.setVolume(volume);
+ }
+ return this;
+ };
+
+ /**
+ * Get the volume for the current video
+ * @method getVolume
+ * @return {Number} volume should be a number between 0 and 100, 0 being mute and 100 the max volume.
+ */
+
+
+ Player.prototype.getVolume = function getVolume() {
+ return this.core && this.core.mediaControl ? this.core.mediaControl.volume : 0;
+ };
+
+ /**
+ * mutes the current video (`source`).
+ * @method mute
+ * @return {Player} itself
+ */
+
+
+ Player.prototype.mute = function mute() {
+ this._mutedVolume = this.getVolume();
+ this.setVolume(0);
+ return this;
+ };
+
+ /**
+ * unmutes the current video (`source`).
+ * @method unmute
+ * @return {Player} itself
+ */
+
+
+ Player.prototype.unmute = function unmute() {
+ this.setVolume(typeof this._mutedVolume === 'number' ? this._mutedVolume : 100);
+ this._mutedVolume = null;
+ return this;
+ };
+
+ /**
+ * checks if the player is playing.
+ * @method isPlaying
+ * @return {Boolean} `true` if the current source is playing, otherwise `false`
+ */
+
+
+ Player.prototype.isPlaying = function isPlaying() {
+ return this.core.mediaControl.container.isPlaying();
+ };
+
+ /**
+ * returns `true` if DVR is enable otherwise `false`.
+ * @method isDvrEnabled
+ * @return {Boolean}
+ */
+
+
+ Player.prototype.isDvrEnabled = function isDvrEnabled() {
+ return this.core.mediaControl.container.isDvrEnabled();
+ };
+
+ /**
+ * returns `true` if DVR is in use otherwise `false`.
+ * @method isDvrInUse
+ * @return {Boolean}
+ */
+
+
+ Player.prototype.isDvrInUse = function isDvrInUse() {
+ return this.core.mediaControl.container.isDvrInUse();
+ };
+
+ /**
+ * enables to configure a player after its creation
+ * @method configure
+ * @param {Object} options all the options to change in form of a javascript object
+ * @return {Player} itself
+ */
+
+
+ Player.prototype.configure = function configure(options) {
+ this.core.configure(options);
+ return this;
+ };
+
+ /**
+ * get a plugin by its name.
+ * @method getPlugin
+ * @param {String} name of the plugin.
+ * @return {Object} the plugin instance
+ * @example
+ * ```javascript
+ * var poster = player.getPlugin('poster');
+ * poster.hidePlayButton();
+ * ```
+ */
+
+
+ Player.prototype.getPlugin = function getPlugin(name) {
+ var plugins = this.core.plugins.concat(this.core.mediaControl.container.plugins);
+ return plugins.filter(function (plugin) {
+ return plugin.name === name;
+ })[0];
+ };
+
+ /**
+ * the current time in seconds.
+ * @method getCurrentTime
+ * @return {Number} current time (in seconds) of the current source
+ */
+
+
+ Player.prototype.getCurrentTime = function getCurrentTime() {
+ return this.core.mediaControl.container.getCurrentTime();
+ };
+
+ /**
+ * The time that "0" now represents relative to when playback started.
+ * For a stream with a sliding window this will increase as content is
+ * removed from the beginning.
+ * @method getStartTimeOffset
+ * @return {Number} time (in seconds) that time "0" represents.
+ */
+
+
+ Player.prototype.getStartTimeOffset = function getStartTimeOffset() {
+ return this.core.mediaControl.container.getStartTimeOffset();
+ };
+
+ /**
+ * the duration time in seconds.
+ * @method getDuration
+ * @return {Number} duration time (in seconds) of the current source
+ */
+
+
+ Player.prototype.getDuration = function getDuration() {
+ return this.core.mediaControl.container.getDuration();
+ };
+
+ return Player;
+ }(_base_object2.default);
+
+ exports.default = Player;
+ module.exports = exports['default'];
+
+/***/ },
+/* 2 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+ exports.cancelAnimationFrame = exports.requestAnimationFrame = exports.QueryString = exports.Config = exports.Fullscreen = undefined;
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ exports.extend = extend;
+ exports.formatTime = formatTime;
+ exports.seekStringToSeconds = seekStringToSeconds;
+ exports.uniqueId = uniqueId;
+ exports.isNumber = isNumber;
+ exports.currentScriptUrl = currentScriptUrl;
+ exports.getBrowserLanguage = getBrowserLanguage;
+ exports.now = now;
+ exports.removeArrayItem = removeArrayItem;
+
+ var _browser = __webpack_require__(3);
+
+ var _browser2 = _interopRequireDefault(_browser);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+ /*jshint -W079 */
+
+ function assign(obj, source) {
+ if (source) {
+ for (var prop in source) {
+ var propDescriptor = Object.getOwnPropertyDescriptor(source, prop);
+ propDescriptor ? Object.defineProperty(obj, prop, propDescriptor) : obj[prop] = source[prop];
+ }
+ }
+ return obj;
+ }
+
+ function extend(parent, properties) {
+ var Surrogate = function (_parent) {
+ _inherits(Surrogate, _parent);
+
+ function Surrogate() {
+ _classCallCheck(this, Surrogate);
+
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ var _this = _possibleConstructorReturn(this, _parent.call.apply(_parent, [this].concat(args)));
+
+ if (properties.initialize) {
+ properties.initialize.apply(_this, args);
+ }
+ return _this;
+ }
+
+ return Surrogate;
+ }(parent);
+
+ assign(Surrogate.prototype, properties);
+ return Surrogate;
+ }
+
+ function formatTime(time, paddedHours) {
+ if (!isFinite(time)) {
+ return '--:--';
+ }
+ time = time * 1000;
+ time = parseInt(time / 1000);
+ var seconds = time % 60;
+ time = parseInt(time / 60);
+ var minutes = time % 60;
+ time = parseInt(time / 60);
+ var hours = time % 24;
+ var days = parseInt(time / 24);
+ var out = '';
+ if (days && days > 0) {
+ out += days + ':';
+ if (hours < 1) {
+ out += '00:';
+ }
+ }
+ if (hours && hours > 0 || paddedHours) {
+ out += ('0' + hours).slice(-2) + ':';
+ }
+ out += ('0' + minutes).slice(-2) + ':';
+ out += ('0' + seconds).slice(-2);
+ return out.trim();
+ }
+
+ var Fullscreen = exports.Fullscreen = {
+ isFullscreen: function isFullscreen() {
+ return !!(document.webkitFullscreenElement || document.webkitIsFullScreen || document.mozFullScreen || document.msFullscreenElement);
+ },
+ requestFullscreen: function requestFullscreen(el) {
+ if (el.requestFullscreen) {
+ el.requestFullscreen();
+ } else if (el.webkitRequestFullscreen) {
+ el.webkitRequestFullscreen();
+ } else if (el.mozRequestFullScreen) {
+ el.mozRequestFullScreen();
+ } else if (el.msRequestFullscreen) {
+ el.msRequestFullscreen();
+ } else if (el.querySelector && el.querySelector('video') && el.querySelector('video').webkitEnterFullScreen) {
+ el.querySelector('video').webkitEnterFullScreen();
+ }
+ },
+ cancelFullscreen: function cancelFullscreen() {
+ if (document.exitFullscreen) {
+ document.exitFullscreen();
+ } else if (document.webkitCancelFullScreen) {
+ document.webkitCancelFullScreen();
+ } else if (document.webkitExitFullscreen) {
+ document.webkitExitFullscreen();
+ } else if (document.mozCancelFullScreen) {
+ document.mozCancelFullScreen();
+ } else if (document.msExitFullscreen) {
+ document.msExitFullscreen();
+ }
+ },
+ fullscreenEnabled: function fullscreenEnabled() {
+ return !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled);
+ }
+ };
+
+ var Config = exports.Config = function () {
+ function Config() {
+ _classCallCheck(this, Config);
+ }
+
+ Config._defaultConfig = function _defaultConfig() {
+ return {
+ volume: {
+ value: 100,
+ parse: parseInt
+ }
+ };
+ };
+
+ Config._defaultValueFor = function _defaultValueFor(key) {
+ try {
+ return this._defaultConfig()[key].parse(this._defaultConfig()[key].value);
+ } catch (e) {
+ return undefined;
+ }
+ };
+
+ Config._createKeyspace = function _createKeyspace(key) {
+ return 'clappr.' + document.domain + '.' + key;
+ };
+
+ Config.restore = function restore(key) {
+ if (_browser2.default.hasLocalstorage && localStorage[this._createKeyspace(key)]) {
+ return this._defaultConfig()[key].parse(localStorage[this._createKeyspace(key)]);
+ }
+ return this._defaultValueFor(key);
+ };
+
+ Config.persist = function persist(key, value) {
+ if (_browser2.default.hasLocalstorage) {
+ try {
+ localStorage[this._createKeyspace(key)] = value;
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }
+ };
+
+ return Config;
+ }();
+
+ var QueryString = exports.QueryString = function () {
+ function QueryString() {
+ _classCallCheck(this, QueryString);
+ }
+
+ QueryString.parse = function parse(paramsString) {
+ var match = void 0;
+ var pl = /\+/g,
+ // Regex for replacing addition symbol with a space
+ search = /([^&=]+)=?([^&]*)/g,
+ decode = function decode(s) {
+ return decodeURIComponent(s.replace(pl, ' '));
+ },
+ params = {};
+ while (match = search.exec(paramsString)) {
+ // eslint-disable-line no-cond-assign
+ params[decode(match[1]).toLowerCase()] = decode(match[2]);
+ }
+ return params;
+ };
+
+ _createClass(QueryString, null, [{
+ key: 'params',
+ get: function get() {
+ var query = window.location.search.substring(1);
+ if (query !== this.query) {
+ this._urlParams = this.parse(query);
+ this.query = query;
+ }
+ return this._urlParams;
+ }
+ }, {
+ key: 'hashParams',
+ get: function get() {
+ var hash = window.location.hash.substring(1);
+ if (hash !== this.hash) {
+ this._hashParams = this.parse(hash);
+ this.hash = hash;
+ }
+ return this._hashParams;
+ }
+ }]);
+
+ return QueryString;
+ }();
+
+ function seekStringToSeconds() {
+ var paramName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 't';
+
+ var seconds = 0;
+ var seekString = QueryString.params[paramName] || QueryString.hashParams[paramName] || '';
+ var parts = seekString.match(/[0-9]+[hms]+/g) || [];
+ if (parts.length > 0) {
+ (function () {
+ var factor = { 'h': 3600, 'm': 60, 's': 1 };
+ parts.forEach(function (el) {
+ if (el) {
+ var suffix = el[el.length - 1];
+ var time = parseInt(el.slice(0, el.length - 1), 10);
+ seconds += time * factor[suffix];
+ }
+ });
+ })();
+ } else if (seekString) {
+ seconds = parseInt(seekString, 10);
+ }
+ return seconds;
+ }
+
+ var idsCounter = {};
+
+ function uniqueId(prefix) {
+ idsCounter[prefix] || (idsCounter[prefix] = 0);
+ var id = ++idsCounter[prefix];
+ return prefix + id;
+ }
+
+ function isNumber(value) {
+ return value - parseFloat(value) + 1 >= 0;
+ }
+
+ function currentScriptUrl() {
+ var scripts = document.getElementsByTagName('script');
+ return scripts.length ? scripts[scripts.length - 1].src : '';
+ }
+
+ var requestAnimationFrame = exports.requestAnimationFrame = (window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || function (fn) {
+ window.setTimeout(fn, 1000 / 60);
+ }).bind(window);
+
+ var cancelAnimationFrame = exports.cancelAnimationFrame = (window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || window.clearTimeout).bind(window);
+
+ function getBrowserLanguage() {
+ return window.navigator && window.navigator.language;
+ }
+
+ function now() {
+ if (window.performance && window.performance.now) {
+ return performance.now();
+ }
+ return Date.now();
+ }
+
+ // remove the item from the array if it exists in the array
+ function removeArrayItem(arr, item) {
+ var i = arr.indexOf(item);
+ if (i >= 0) {
+ arr.splice(i, 1);
+ }
+ }
+
+ exports.default = {
+ Config: Config,
+ Fullscreen: Fullscreen,
+ QueryString: QueryString,
+ extend: extend,
+ formatTime: formatTime,
+ seekStringToSeconds: seekStringToSeconds,
+ uniqueId: uniqueId,
+ currentScriptUrl: currentScriptUrl,
+ isNumber: isNumber,
+ requestAnimationFrame: requestAnimationFrame,
+ cancelAnimationFrame: cancelAnimationFrame,
+ getBrowserLanguage: getBrowserLanguage,
+ now: now,
+ removeArrayItem: removeArrayItem
+ };
+
+/***/ },
+/* 3 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+ // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var Browser = {};
+
+ var hasLocalstorage = function hasLocalstorage() {
+ try {
+ localStorage.setItem('clappr', 'clappr');
+ localStorage.removeItem('clappr');
+ return true;
+ } catch (e) {
+ return false;
+ }
+ };
+
+ var hasFlash = function hasFlash() {
+ try {
+ var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
+ return !!fo;
+ } catch (e) {
+ return !!(navigator.mimeTypes && navigator.mimeTypes['application/x-shockwave-flash'] !== undefined && navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin);
+ }
+ };
+
+ var getBrowserInfo = function getBrowserInfo() {
+ var ua = navigator.userAgent;
+ var parts = ua.match(/\b(playstation 4|nx|opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [],
+ extra = void 0;
+ if (/trident/i.test(parts[1])) {
+ extra = /\brv[ :]+(\d+)/g.exec(ua) || [];
+ return { name: 'IE', version: parseInt(extra[1] || '') };
+ } else if (parts[1] === 'Chrome') {
+ extra = ua.match(/\bOPR\/(\d+)/);
+ if (extra != null) {
+ return { name: 'Opera', version: parseInt(extra[1]) };
+ }
+ }
+ parts = parts[2] ? [parts[1], parts[2]] : [navigator.appName, navigator.appVersion, '-?'];
+
+ if (extra = ua.match(/version\/(\d+)/i)) {
+ parts.splice(1, 1, extra[1]);
+ }
+ return { name: parts[0], version: parseInt(parts[1]) };
+ };
+
+ var browserInfo = getBrowserInfo();
+
+ Browser.isSafari = /safari/i.test(navigator.userAgent) && navigator.userAgent.indexOf('Chrome') === -1;
+ Browser.isChrome = /chrome/i.test(navigator.userAgent);
+ Browser.isFirefox = /firefox/i.test(navigator.userAgent);
+ Browser.isLegacyIE = !!window.ActiveXObject;
+ Browser.isIE = Browser.isLegacyIE || /trident.*rv:1\d/i.test(navigator.userAgent);
+ Browser.isIE11 = /trident.*rv:11/i.test(navigator.userAgent);
+ Browser.isChromecast = Browser.isChrome && /CrKey/i.test(navigator.userAgent);
+ Browser.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone|IEMobile|Opera Mini/i.test(navigator.userAgent);
+ Browser.isiOS = /iPad|iPhone|iPod/i.test(navigator.userAgent);
+ Browser.isAndroid = /Android/i.test(navigator.userAgent);
+ Browser.isWindowsPhone = /Windows Phone/i.test(navigator.userAgent);
+ Browser.isWin8App = /MSAppHost/i.test(navigator.userAgent);
+ Browser.isWiiU = /WiiU/i.test(navigator.userAgent);
+ Browser.isPS4 = /PlayStation 4/i.test(navigator.userAgent);
+ Browser.hasLocalstorage = hasLocalstorage();
+ Browser.hasFlash = hasFlash();
+
+ Browser.name = browserInfo.name;
+ Browser.version = browserInfo.version;
+
+ exports.default = Browser;
+ module.exports = exports['default'];
+
+/***/ },
+/* 4 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _utils = __webpack_require__(2);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ /**
+ * @class BaseObject
+ * @constructor
+ * @extends Events
+ * @module base
+ */
+ var BaseObject = function (_Events) {
+ _inherits(BaseObject, _Events);
+
+ _createClass(BaseObject, [{
+ key: 'options',
+
+ /**
+ * returns the object options
+ * @property options
+ * @type Object
+ */
+ get: function get() {
+ return this._options;
+ }
+
+ /**
+ * @method constructor
+ * @param {Object} options
+ */
+
+ }]);
+
+ function BaseObject() {
+ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+ _classCallCheck(this, BaseObject);
+
+ var _this = _possibleConstructorReturn(this, _Events.call(this, options));
+
+ _this._options = options;
+ _this.uniqueId = (0, _utils.uniqueId)('o');
+ return _this;
+ }
+ /**
+ * a unique id prefixed with `'o'`, `o1, o232`
+ *
+ * @property uniqueId
+ * @type String
+ */
+
+
+ return BaseObject;
+ }(_events2.default);
+
+ exports.default = BaseObject;
+ module.exports = exports['default'];
+
+/***/ },
+/* 5 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var _log = __webpack_require__(6);
+
+ var _log2 = _interopRequireDefault(_log);
+
+ var _utils = __webpack_require__(2);
+
+ var _lodash = __webpack_require__(10);
+
+ var _lodash2 = _interopRequireDefault(_lodash);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var slice = Array.prototype.slice;
+
+ var eventSplitter = /\s+/;
+
+ var eventsApi = function eventsApi(obj, action, name, rest) {
+ if (!name) {
+ return true;
+ }
+
+ // Handle event maps.
+ if ((typeof name === 'undefined' ? 'undefined' : _typeof(name)) === 'object') {
+ for (var key in name) {
+ obj[action].apply(obj, [key, name[key]].concat(rest));
+ }
+ return false;
+ }
+
+ // Handle space separated event names.
+ if (eventSplitter.test(name)) {
+ var names = name.split(eventSplitter);
+ for (var i = 0, l = names.length; i < l; i++) {
+ obj[action].apply(obj, [names[i]].concat(rest));
+ }
+ return false;
+ }
+
+ return true;
+ };
+
+ var triggerEvents = function triggerEvents(events, args, klass, name) {
+ var ev = void 0,
+ i = -1;
+ var l = events.length,
+ a1 = args[0],
+ a2 = args[1],
+ a3 = args[2];
+ run();
+
+ function run() {
+ try {
+ switch (args.length) {
+ case 0:
+ while (++i < l) {
+ (ev = events[i]).callback.call(ev.ctx);
+ }return;
+ case 1:
+ while (++i < l) {
+ (ev = events[i]).callback.call(ev.ctx, a1);
+ }return;
+ case 2:
+ while (++i < l) {
+ (ev = events[i]).callback.call(ev.ctx, a1, a2);
+ }return;
+ case 3:
+ while (++i < l) {
+ (ev = events[i]).callback.call(ev.ctx, a1, a2, a3);
+ }return;
+ default:
+ while (++i < l) {
+ (ev = events[i]).callback.apply(ev.ctx, args);
+ }return;
+ }
+ } catch (exception) {
+ _log2.default.error.apply(_log2.default, [klass, 'error on event', name, 'trigger', '-', exception]);
+ run();
+ }
+ }
+ };
+
+ /**
+ * @class Events
+ * @constructor
+ * @module base
+ */
+
+ var Events = function () {
+ function Events() {
+ _classCallCheck(this, Events);
+ }
+
+ /**
+ * listen to an event indefinitely, if you want to stop you need to call `off`
+ * @method on
+ * @param {String} name
+ * @param {Function} callback
+ * @param {Object} context
+ */
+ Events.prototype.on = function on(name, callback, context) {
+ if (!eventsApi(this, 'on', name, [callback, context]) || !callback) {
+ return this;
+ }
+ this._events || (this._events = {});
+ var events = this._events[name] || (this._events[name] = []);
+ events.push({ callback: callback, context: context, ctx: context || this });
+ return this;
+ };
+
+ /**
+ * listen to an event only once
+ * @method once
+ * @param {String} name
+ * @param {Function} callback
+ * @param {Object} context
+ */
+
+
+ Events.prototype.once = function once(name, callback, context) {
+ if (!eventsApi(this, 'once', name, [callback, context]) || !callback) {
+ return this;
+ }
+ var self = this;
+ var once = (0, _lodash2.default)(function () {
+ self.off(name, once);
+ callback.apply(this, arguments);
+ });
+ once._callback = callback;
+ return this.on(name, once, context);
+ };
+
+ /**
+ * stop listening to an event
+ * @method off
+ * @param {String} name
+ * @param {Function} callback
+ * @param {Object} context
+ */
+
+
+ Events.prototype.off = function off(name, callback, context) {
+ var retain = void 0,
+ ev = void 0,
+ events = void 0,
+ names = void 0,
+ i = void 0,
+ l = void 0,
+ j = void 0,
+ k = void 0;
+ if (!this._events || !eventsApi(this, 'off', name, [callback, context])) {
+ return this;
+ }
+ if (!name && !callback && !context) {
+ this._events = void 0;
+ return this;
+ }
+ names = name ? [name] : Object.keys(this._events);
+ // jshint maxdepth:5
+ for (i = 0, l = names.length; i < l; i++) {
+ name = names[i];
+ events = this._events[name];
+ if (events) {
+ this._events[name] = retain = [];
+ if (callback || context) {
+ for (j = 0, k = events.length; j < k; j++) {
+ ev = events[j];
+ if (callback && callback !== ev.callback && callback !== ev.callback._callback || context && context !== ev.context) {
+ retain.push(ev);
+ }
+ }
+ }
+ if (!retain.length) {
+ delete this._events[name];
+ }
+ }
+ }
+ return this;
+ };
+
+ /**
+ * triggers an event given its `name`
+ * @method trigger
+ * @param {String} name
+ */
+
+
+ Events.prototype.trigger = function trigger(name) {
+ var klass = this.name || this.constructor.name;
+ _log2.default.debug.apply(_log2.default, [klass].concat(Array.prototype.slice.call(arguments)));
+ if (!this._events) {
+ return this;
+ }
+ var args = slice.call(arguments, 1);
+ if (!eventsApi(this, 'trigger', name, args)) {
+ return this;
+ }
+ var events = this._events[name];
+ var allEvents = this._events.all;
+ if (events) {
+ triggerEvents(events, args, klass, name);
+ }
+ if (allEvents) {
+ triggerEvents(allEvents, arguments, klass, name);
+ }
+ return this;
+ };
+
+ /**
+ * stop listening an event for a given object
+ * @method stopListening
+ * @param {Object} obj
+ * @param {String} name
+ * @param {Function} callback
+ */
+
+
+ Events.prototype.stopListening = function stopListening(obj, name, callback) {
+ var listeningTo = this._listeningTo;
+ if (!listeningTo) {
+ return this;
+ }
+ var remove = !name && !callback;
+ if (!callback && (typeof name === 'undefined' ? 'undefined' : _typeof(name)) === 'object') {
+ callback = this;
+ }
+ if (obj) {
+ (listeningTo = {})[obj._listenId] = obj;
+ }
+ for (var id in listeningTo) {
+ obj = listeningTo[id];
+ obj.off(name, callback, this);
+ if (remove || Object.keys(obj._events).length === 0) {
+ delete this._listeningTo[id];
+ }
+ }
+ return this;
+ };
+
+ return Events;
+ }();
+
+ /**
+ * listen to an event indefinitely for a given `obj`
+ * @method listenTo
+ * @param {Object} obj
+ * @param {String} name
+ * @param {Function} callback
+ * @param {Object} context
+ * @example
+ * ```javascript
+ * this.listenTo(this.core.playback, Events.PLAYBACK_PAUSE, this.callback)
+ * ```
+ */
+ /**
+ * listen to an event once for a given `obj`
+ * @method listenToOnce
+ * @param {Object} obj
+ * @param {String} name
+ * @param {Function} callback
+ * @param {Object} context
+ * @example
+ * ```javascript
+ * this.listenToOnce(this.core.playback, Events.PLAYBACK_PAUSE, this.callback)
+ * ```
+ */
+
+
+ exports.default = Events;
+ var listenMethods = { listenTo: 'on', listenToOnce: 'once' };
+
+ Object.keys(listenMethods).forEach(function (method) {
+ Events.prototype[method] = function (obj, name, callback) {
+ var listeningTo = this._listeningTo || (this._listeningTo = {});
+ var id = obj._listenId || (obj._listenId = (0, _utils.uniqueId)('l'));
+ listeningTo[id] = obj;
+ if (!callback && (typeof name === 'undefined' ? 'undefined' : _typeof(name)) === 'object') {
+ callback = this;
+ }
+ obj[listenMethods[method]](name, callback, this);
+ return this;
+ };
+ });
+
+ // PLAYER EVENTS
+ /**
+ * Fired when the player is ready on startup
+ *
+ * @event PLAYER_READY
+ */
+ Events.PLAYER_READY = 'ready';
+ /**
+ * Fired when player resizes
+ *
+ * @event PLAYER_RESIZE
+ * @param {Object} currentSize an object with the current size
+ */
+ Events.PLAYER_RESIZE = 'resize';
+ /**
+ * Fired when player changes its fullscreen state
+ *
+ * @event PLAYER_FULLSCREEN
+ * @param {Boolean} whether or not the player is on fullscreen mode
+ */
+ Events.PLAYER_FULLSCREEN = 'fullscreen';
+ /**
+ * Fired when player starts to play
+ *
+ * @event PLAYER_PLAY
+ */
+ Events.PLAYER_PLAY = 'play';
+ /**
+ * Fired when player pauses
+ *
+ * @event PLAYER_PAUSE
+ */
+ Events.PLAYER_PAUSE = 'pause';
+ /**
+ * Fired when player stops
+ *
+ * @event PLAYER_STOP
+ */
+ Events.PLAYER_STOP = 'stop';
+ /**
+ * Fired when player ends the video
+ *
+ * @event PLAYER_ENDED
+ */
+ Events.PLAYER_ENDED = 'ended';
+ /**
+ * Fired when player seeks the video
+ *
+ * @event PLAYER_SEEK
+ * @param {Number} time the current time in seconds
+ */
+ Events.PLAYER_SEEK = 'seek';
+ /**
+ * Fired when player receives an error
+ *
+ * @event PLAYER_ERROR
+ * @param {Object} error the error
+ */
+ Events.PLAYER_ERROR = 'error';
+ /**
+ * Fired when the time is updated on player
+ *
+ * @event PLAYER_TIMEUPDATE
+ * @param {Object} progress Data
+ * progress object
+ * @param {Number} [progress.current]
+ * current time
+ * @param {Number} [progress.total]
+ * total time
+ */
+ Events.PLAYER_TIMEUPDATE = 'timeupdate';
+ /**
+ * Fired when player updates its volume
+ *
+ * @event PLAYER_VOLUMEUPDATE
+ * @param {Number} volume the current volume
+ */
+ Events.PLAYER_VOLUMEUPDATE = 'volumeupdate';
+
+ // Playback Events
+ /**
+ * Fired when the playback is downloading the media
+ *
+ * @event PLAYBACK_PROGRESS
+ * @param progress {Object}
+ * Data progress object
+ * @param [progress.start] {Number}
+ * start position of buffered content at current position
+ * @param [progress.current] {Number}
+ * end position of buffered content at current position
+ * @param [progress.total] {Number}
+ * total content to be downloaded
+ * @param buffered {Array}
+ * array of buffered segments ({start, end}). [Only for supported playbacks]
+ */
+ Events.PLAYBACK_PROGRESS = 'playback:progress';
+ /**
+ * Fired when the time is updated on playback
+ *
+ * @event PLAYBACK_TIMEUPDATE
+ * @param {Object} progress Data
+ * progress object
+ * @param {Number} [progress.current]
+ * current time
+ * @param {Number} [progress.total]
+ * total time
+ */
+ Events.PLAYBACK_TIMEUPDATE = 'playback:timeupdate';
+ /**
+ * Fired when playback is ready
+ *
+ * @event PLAYBACK_READY
+ */
+ Events.PLAYBACK_READY = 'playback:ready';
+ /**
+ * Fired when the playback starts having to buffer because
+ * playback can currently not be smooth.
+ *
+ * This corresponds to the playback `buffering` property being
+ * `true`.
+ *
+ * @event PLAYBACK_BUFFERING
+ */
+ Events.PLAYBACK_BUFFERING = 'playback:buffering';
+ /**
+ * Fired when the playback has enough in the buffer to be
+ * able to play smoothly, after previously being unable to
+ * do this.
+ *
+ * This corresponds to the playback `buffering` property being
+ * `false`.
+ *
+ * @event PLAYBACK_BUFFERFULL
+ */
+ Events.PLAYBACK_BUFFERFULL = 'playback:bufferfull';
+ /**
+ * Fired when playback changes any settings (volume, seek and etc)
+ *
+ * @event PLAYBACK_SETTINGSUPDATE
+ */
+ Events.PLAYBACK_SETTINGSUPDATE = 'playback:settingsupdate';
+ /**
+ * Fired when playback loaded its metadata
+ *
+ * @event PLAYBACK_LOADEDMETADATA
+ * @param {Object} metadata Data
+ * settings object
+ * @param {Number} [metadata.duration]
+ * the playback duration
+ * @param {Object} [metadata.data]
+ * extra meta data
+ */
+ Events.PLAYBACK_LOADEDMETADATA = 'playback:loadedmetadata';
+ /**
+ * Fired when playback updates its video quality
+ *
+ * @event PLAYBACK_HIGHDEFINITIONUPDATE
+ * @param {Boolean} isHD
+ * true when is on HD, false otherwise
+ */
+ Events.PLAYBACK_HIGHDEFINITIONUPDATE = 'playback:highdefinitionupdate';
+ /**
+ * Fired when playback updates its bitrate
+ *
+ * @event PLAYBACK_BITRATE
+ * @param {Object} bitrate Data
+ * bitrate object
+ * @param {Number} [bitrate.bandwidth]
+ * bitrate bandwidth when it's available
+ * @param {Number} [bitrate.width]
+ * playback width (ex: 720, 640, 1080)
+ * @param {Number} [bitrate.height]
+ * playback height (ex: 240, 480, 720)
+ * @param {Number} [bitrate.level]
+ * playback level when it's available, it could be just a map for width (0 => 240, 1 => 480, 2 => 720)
+ */
+ Events.PLAYBACK_BITRATE = 'playback:bitrate';
+ /**
+ * Fired when the playback has its levels
+ *
+ * @event PLAYBACK_LEVELS_AVAILABLE
+ * @param {Array} levels
+ * the ordered levels, each one with the following format `{id: 1, label: '500kbps'}` ps: id should be a number >= 0
+ * @param {Number} initial
+ * the initial level otherwise -1 (AUTO)
+ */
+ Events.PLAYBACK_LEVELS_AVAILABLE = 'playback:levels:available';
+ /**
+ * Fired when the playback starts to switch level
+ *
+ * @event PLAYBACK_LEVEL_SWITCH_START
+ *
+ */
+ Events.PLAYBACK_LEVEL_SWITCH_START = 'playback:levels:switch:start';
+ /**
+ * Fired when the playback ends the level switch
+ *
+ * @event PLAYBACK_LEVEL_SWITCH_END
+ *
+ */
+ Events.PLAYBACK_LEVEL_SWITCH_END = 'playback:levels:switch:end';
+
+ /**
+ * Fired when playback internal state changes
+ *
+ * @event PLAYBACK_PLAYBACKSTATE
+ * @param {Object} state Data
+ * state object
+ * @param {String} [state.type]
+ * the playback type
+ */
+ Events.PLAYBACK_PLAYBACKSTATE = 'playback:playbackstate';
+ /**
+ * Fired when DVR becomes enabled/disabled.
+ *
+ * @event PLAYBACK_DVR
+ * @param {boolean} state true if dvr enabled
+ */
+ Events.PLAYBACK_DVR = 'playback:dvr';
+ // TODO doc
+ Events.PLAYBACK_MEDIACONTROL_DISABLE = 'playback:mediacontrol:disable';
+ // TODO doc
+ Events.PLAYBACK_MEDIACONTROL_ENABLE = 'playback:mediacontrol:enable';
+ /**
+ * Fired when the media for a playback ends.
+ *
+ * @event PLAYBACK_ENDED
+ * @param {String} name the name of the playback
+ */
+ Events.PLAYBACK_ENDED = 'playback:ended';
+ /**
+ * Fired when user requests `play()`
+ *
+ * @event PLAYBACK_PLAY_INTENT
+ */
+ Events.PLAYBACK_PLAY_INTENT = 'playback:play:intent';
+ /**
+ * Fired when the media for a playback starts playing.
+ * This is not necessarily when the user requests `play()`
+ * The media may have to buffer first.
+ * I.e. `isPlaying()` might return `true` before this event is fired,
+ * because `isPlaying()` represents the intended state.
+ *
+ * @event PLAYBACK_PLAY
+ */
+ Events.PLAYBACK_PLAY = 'playback:play';
+ /**
+ * Fired when the media for a playback pauses.
+ *
+ * @event PLAYBACK_PAUSE
+ */
+ Events.PLAYBACK_PAUSE = 'playback:pause';
+ /**
+ * Fired when the media for a playback is stopped.
+ *
+ * @event PLAYBACK_STOP
+ */
+ Events.PLAYBACK_STOP = 'playback:stop';
+ /**
+ * Fired if an error occurs in the playback.
+ *
+ * @event PLAYBACK_ERROR
+ * @param {Object} error An object containing the error details
+ * @param {String} name Playback name
+ */
+ Events.PLAYBACK_ERROR = 'playback:error';
+ // TODO doc
+ Events.PLAYBACK_STATS_ADD = 'playback:stats:add';
+ // TODO doc
+ Events.PLAYBACK_FRAGMENT_LOADED = 'playback:fragment:loaded';
+ // TODO doc
+ Events.PLAYBACK_LEVEL_SWITCH = 'playback:level:switch';
+
+ /**
+ * Fired when the options were changed for the core
+ *
+ * @event CORE_OPTIONS_CHANGE
+ */
+ Events.CORE_OPTIONS_CHANGE = 'core:options:change';
+ /**
+ * Fired after creating containers, when the core is ready
+ *
+ * @event CORE_READY
+ */
+ Events.CORE_READY = 'core:ready';
+ /**
+ * Fired when the fullscreen state change
+ *
+ * @param {Boolean} whether or not the player is on fullscreen mode
+ * @event CORE_READY
+ */
+ Events.CORE_FULLSCREEN = 'core:fullscreen';
+
+ // Container Events
+ /**
+ * Fired when the container internal state changes
+ *
+ * @event CONTAINER_PLAYBACKSTATE
+ * @param {Object} state Data
+ * state object
+ * @param {String} [state.type]
+ * the playback type
+ */
+ Events.CONTAINER_PLAYBACKSTATE = 'container:playbackstate';
+ Events.CONTAINER_PLAYBACKDVRSTATECHANGED = 'container:dvr';
+ /**
+ * Fired when the container updates its bitrate
+ *
+ * @event CONTAINER_BITRATE
+ * @param {Object} bitrate Data
+ * bitrate object
+ * @param {Number} [bitrate.bandwidth]
+ * bitrate bandwidth when it's available
+ * @param {Number} [bitrate.width]
+ * playback width (ex: 720, 640, 1080)
+ * @param {Number} [bitrate.height]
+ * playback height (ex: 240, 480, 720)
+ * @param {Number} [bitrate.level]
+ * playback level when it's available, it could be just a map for width (0 => 240, 1 => 480, 2 => 720)
+ */
+ Events.CONTAINER_BITRATE = 'container:bitrate';
+ Events.CONTAINER_STATS_REPORT = 'container:stats:report';
+ Events.CONTAINER_DESTROYED = 'container:destroyed';
+ /**
+ * Fired when the container is ready
+ *
+ * @event CONTAINER_READY
+ */
+ Events.CONTAINER_READY = 'container:ready';
+ Events.CONTAINER_ERROR = 'container:error';
+ /**
+ * Fired when the container loaded its metadata
+ *
+ * @event CONTAINER_LOADEDMETADATA
+ * @param {Object} metadata Data
+ * settings object
+ * @param {Number} [metadata.duration]
+ * the playback duration
+ * @param {Object} [metadata.data]
+ * extra meta data
+ */
+ Events.CONTAINER_LOADEDMETADATA = 'container:loadedmetadata';
+ /**
+ * Fired when the time is updated on container
+ *
+ * @event CONTAINER_TIMEUPDATE
+ * @param {Object} progress Data
+ * progress object
+ * @param {Number} [progress.current]
+ * current time
+ * @param {Number} [progress.total]
+ * total time
+ */
+ Events.CONTAINER_TIMEUPDATE = 'container:timeupdate';
+ /**
+ * Fired when the container is downloading the media
+ *
+ * @event CONTAINER_PROGRESS
+ * @param {Object} progress Data
+ * progress object
+ * @param {Number} [progress.start]
+ * initial downloaded content
+ * @param {Number} [progress.current]
+ * current dowloaded content
+ * @param {Number} [progress.total]
+ * total content to be downloaded
+ */
+ Events.CONTAINER_PROGRESS = 'container:progress';
+ Events.CONTAINER_PLAY = 'container:play';
+ Events.CONTAINER_STOP = 'container:stop';
+ Events.CONTAINER_PAUSE = 'container:pause';
+ Events.CONTAINER_ENDED = 'container:ended';
+ Events.CONTAINER_CLICK = 'container:click';
+ Events.CONTAINER_DBLCLICK = 'container:dblclick';
+ Events.CONTAINER_CONTEXTMENU = 'container:contextmenu';
+ Events.CONTAINER_MOUSE_ENTER = 'container:mouseenter';
+ Events.CONTAINER_MOUSE_LEAVE = 'container:mouseleave';
+ /**
+ * Fired when the container seeks the video
+ *
+ * @event CONTAINER_SEEK
+ * @param {Number} time the current time in seconds
+ */
+ Events.CONTAINER_SEEK = 'container:seek';
+ Events.CONTAINER_VOLUME = 'container:volume';
+ Events.CONTAINER_FULLSCREEN = 'container:fullscreen';
+ /**
+ * Fired when container is buffering
+ *
+ * @event CONTAINER_STATE_BUFFERING
+ */
+ Events.CONTAINER_STATE_BUFFERING = 'container:state:buffering';
+ /**
+ * Fired when the container filled the buffer
+ *
+ * @event CONTAINER_STATE_BUFFERFULL
+ */
+ Events.CONTAINER_STATE_BUFFERFULL = 'container:state:bufferfull';
+ /**
+ * Fired when the container changes any settings (volume, seek and etc)
+ *
+ * @event CONTAINER_SETTINGSUPDATE
+ */
+ Events.CONTAINER_SETTINGSUPDATE = 'container:settingsupdate';
+ /**
+ * Fired when container updates its video quality
+ *
+ * @event CONTAINER_HIGHDEFINITIONUPDATE
+ * @param {Boolean} isHD
+ * true when is on HD, false otherwise
+ */
+ Events.CONTAINER_HIGHDEFINITIONUPDATE = 'container:highdefinitionupdate';
+
+ /**
+ * Fired when the media control shows
+ *
+ * @event CONTAINER_MEDIACONTROL_SHOW
+ */
+ Events.CONTAINER_MEDIACONTROL_SHOW = 'container:mediacontrol:show';
+ /**
+ * Fired when the media control hides
+ *
+ * @event CONTAINER_MEDIACONTROL_HIDE
+ */
+ Events.CONTAINER_MEDIACONTROL_HIDE = 'container:mediacontrol:hide';
+
+ Events.CONTAINER_MEDIACONTROL_DISABLE = 'container:mediacontrol:disable';
+ Events.CONTAINER_MEDIACONTROL_ENABLE = 'container:mediacontrol:enable';
+ Events.CONTAINER_STATS_ADD = 'container:stats:add';
+ /**
+ * Fired when the options were changed for the container
+ *
+ * @event CONTAINER_OPTIONS_CHANGE
+ */
+ Events.CONTAINER_OPTIONS_CHANGE = 'container:options:change';
+
+ // MediaControl Events
+ Events.MEDIACONTROL_RENDERED = 'mediacontrol:rendered';
+ /**
+ * Fired when the player enters/exit on fullscreen
+ *
+ * @event MEDIACONTROL_FULLSCREEN
+ */
+ Events.MEDIACONTROL_FULLSCREEN = 'mediacontrol:fullscreen';
+ /**
+ * Fired when the media control shows
+ *
+ * @event MEDIACONTROL_SHOW
+ */
+ Events.MEDIACONTROL_SHOW = 'mediacontrol:show';
+ /**
+ * Fired when the media control hides
+ *
+ * @event MEDIACONTROL_HIDE
+ */
+ Events.MEDIACONTROL_HIDE = 'mediacontrol:hide';
+ /**
+ * Fired when mouse enters on the seekbar
+ *
+ * @event MEDIACONTROL_MOUSEMOVE_SEEKBAR
+ * @param {Object} event
+ * the javascript event
+ */
+ Events.MEDIACONTROL_MOUSEMOVE_SEEKBAR = 'mediacontrol:mousemove:seekbar';
+ /**
+ * Fired when mouse leaves the seekbar
+ *
+ * @event MEDIACONTROL_MOUSELEAVE_SEEKBAR
+ * @param {Object} event
+ * the javascript event
+ */
+ Events.MEDIACONTROL_MOUSELEAVE_SEEKBAR = 'mediacontrol:mouseleave:seekbar';
+ /**
+ * Fired when the media is being played
+ *
+ * @event MEDIACONTROL_PLAYING
+ */
+ Events.MEDIACONTROL_PLAYING = 'mediacontrol:playing';
+ /**
+ * Fired when the media is not being played
+ *
+ * @event MEDIACONTROL_NOTPLAYING
+ */
+ Events.MEDIACONTROL_NOTPLAYING = 'mediacontrol:notplaying';
+ /**
+ * Fired when the container was changed
+ *
+ * @event MEDIACONTROL_CONTAINERCHANGED
+ */
+ Events.MEDIACONTROL_CONTAINERCHANGED = 'mediacontrol:containerchanged';
+
+ // Core Events
+ Events.CORE_CONTAINERS_CREATED = 'core:containers:created';
+ module.exports = exports['default'];
+
+/***/ },
+/* 6 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(7);
+
+/***/ },
+/* 7 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _vendor = __webpack_require__(8);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var BOLD = 'font-weight: bold; font-size: 13px;';
+ var INFO = 'color: #006600;' + BOLD;
+ var DEBUG = 'color: #0000ff;' + BOLD;
+ var WARN = 'color: #ff8000;' + BOLD;
+ var ERROR = 'color: #ff0000;' + BOLD;
+
+ var LEVEL_DEBUG = 0;
+ var LEVEL_INFO = 1;
+ var LEVEL_WARN = 2;
+ var LEVEL_ERROR = 3;
+ var LEVEL_DISABLED = LEVEL_ERROR;
+
+ var COLORS = [DEBUG, INFO, WARN, ERROR, ERROR];
+ var DESCRIPTIONS = ['debug', 'info', 'warn', 'error', 'disabled'];
+
+ var Log = function () {
+ function Log() {
+ var _this = this;
+
+ var level = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : LEVEL_INFO;
+ var offLevel = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : LEVEL_DISABLED;
+
+ _classCallCheck(this, Log);
+
+ this.kibo = new _vendor.Kibo();
+ this.kibo.down(['ctrl shift d'], function () {
+ return _this.onOff();
+ });
+ this.BLACKLIST = ['timeupdate', 'playback:timeupdate', 'playback:progress', 'container:hover', 'container:timeupdate', 'container:progress'];
+ this.level = level;
+ this.offLevel = offLevel;
+ }
+
+ Log.prototype.debug = function debug(klass) {
+ this.log(klass, LEVEL_DEBUG, Array.prototype.slice.call(arguments, 1));
+ };
+
+ Log.prototype.info = function info(klass) {
+ this.log(klass, LEVEL_INFO, Array.prototype.slice.call(arguments, 1));
+ };
+
+ Log.prototype.warn = function warn(klass) {
+ this.log(klass, LEVEL_WARN, Array.prototype.slice.call(arguments, 1));
+ };
+
+ Log.prototype.error = function error(klass) {
+ this.log(klass, LEVEL_ERROR, Array.prototype.slice.call(arguments, 1));
+ };
+
+ Log.prototype.onOff = function onOff() {
+ if (this.level === this.offLevel) {
+ this.level = this.previousLevel;
+ } else {
+ this.previousLevel = this.level;
+ this.level = this.offLevel;
+ }
+ // handle instances where console.log is unavailable
+ if (window.console && window.console.log) {
+ window.console.log('%c[Clappr.Log] set log level to ' + DESCRIPTIONS[this.level], WARN);
+ }
+ };
+
+ Log.prototype.level = function level(newLevel) {
+ this.level = newLevel;
+ };
+
+ Log.prototype.log = function log(klass, level, message) {
+ if (this.BLACKLIST.indexOf(message[0]) >= 0) return;
+ if (level < this.level) return;
+
+ if (!message) {
+ message = klass;
+ klass = null;
+ }
+ var color = COLORS[level];
+ var klassDescription = '';
+ if (klass) {
+ klassDescription = '[' + klass + ']';
+ }
+ if (window.console && window.console.log) {
+ window.console.log.apply(console, ['%c[' + DESCRIPTIONS[level] + ']' + klassDescription, color].concat(message));
+ }
+ };
+
+ return Log;
+ }();
+
+ exports.default = Log;
+
+
+ Log.LEVEL_DEBUG = LEVEL_DEBUG;
+ Log.LEVEL_INFO = LEVEL_INFO;
+ Log.LEVEL_WARN = LEVEL_WARN;
+ Log.LEVEL_ERROR = LEVEL_ERROR;
+
+ Log.getInstance = function () {
+ if (this._instance === undefined) {
+ this._instance = new this();
+ this._instance.previousLevel = this._instance.level;
+ this._instance.level = this._instance.offLevel;
+ }
+ return this._instance;
+ };
+
+ Log.setLevel = function (level) {
+ this.getInstance().level = level;
+ };
+
+ Log.debug = function () {
+ this.getInstance().debug.apply(this.getInstance(), arguments);
+ };
+ Log.info = function () {
+ this.getInstance().info.apply(this.getInstance(), arguments);
+ };
+ Log.warn = function () {
+ this.getInstance().warn.apply(this.getInstance(), arguments);
+ };
+ Log.error = function () {
+ this.getInstance().error.apply(this.getInstance(), arguments);
+ };
+ module.exports = exports['default'];
+
+/***/ },
+/* 8 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _kibo = __webpack_require__(9);
+
+ var _kibo2 = _interopRequireDefault(_kibo);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ exports.default = { Kibo: _kibo2.default };
+ module.exports = exports['default'];
+
+/***/ },
+/* 9 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+ /* eslint-disable */
+ // Kibo is released under the MIT License. Copyright (c) 2013 marquete.
+ // see https://github.com/marquete/kibo
+
+ var Kibo = function Kibo(element) {
+ this.element = element || window.document;
+ this.initialize();
+ };
+
+ Kibo.KEY_NAMES_BY_CODE = {
+ 8: 'backspace', 9: 'tab', 13: 'enter',
+ 16: 'shift', 17: 'ctrl', 18: 'alt',
+ 20: 'caps_lock',
+ 27: 'esc',
+ 32: 'space',
+ 37: 'left', 38: 'up', 39: 'right', 40: 'down',
+ 48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5', 54: '6', 55: '7', 56: '8', 57: '9',
+ 65: 'a', 66: 'b', 67: 'c', 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h', 73: 'i', 74: 'j',
+ 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o', 80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't',
+ 85: 'u', 86: 'v', 87: 'w', 88: 'x', 89: 'y', 90: 'z', 112: 'f1', 113: 'f2', 114: 'f3',
+ 115: 'f4', 116: 'f5', 117: 'f6', 118: 'f7', 119: 'f8', 120: 'f9', 121: 'f10', 122: 'f11', 123: 'f12'
+ };
+
+ Kibo.KEY_CODES_BY_NAME = {};
+ (function () {
+ for (var key in Kibo.KEY_NAMES_BY_CODE) {
+ if (Object.prototype.hasOwnProperty.call(Kibo.KEY_NAMES_BY_CODE, key)) {
+ Kibo.KEY_CODES_BY_NAME[Kibo.KEY_NAMES_BY_CODE[key]] = +key;
+ }
+ }
+ })();
+
+ Kibo.MODIFIERS = ['shift', 'ctrl', 'alt'];
+
+ Kibo.registerEvent = function () {
+ if (document.addEventListener) {
+ return function (element, eventName, func) {
+ element.addEventListener(eventName, func, false);
+ };
+ } else if (document.attachEvent) {
+ return function (element, eventName, func) {
+ element.attachEvent('on' + eventName, func);
+ };
+ }
+ }();
+
+ Kibo.unregisterEvent = function () {
+ if (document.removeEventListener) {
+ return function (element, eventName, func) {
+ element.removeEventListener(eventName, func, false);
+ };
+ } else if (document.detachEvent) {
+ return function (element, eventName, func) {
+ element.detachEvent('on' + eventName, func);
+ };
+ }
+ }();
+
+ Kibo.stringContains = function (string, substring) {
+ return string.indexOf(substring) !== -1;
+ };
+
+ Kibo.neatString = function (string) {
+ return string.replace(/^\s+|\s+$/g, '').replace(/\s+/g, ' ');
+ };
+
+ Kibo.capitalize = function (string) {
+ return string.toLowerCase().replace(/^./, function (match) {
+ return match.toUpperCase();
+ });
+ };
+
+ Kibo.isString = function (what) {
+ return Kibo.stringContains(Object.prototype.toString.call(what), 'String');
+ };
+
+ Kibo.arrayIncludes = function () {
+ if (Array.prototype.indexOf) {
+ return function (haystack, needle) {
+ return haystack.indexOf(needle) !== -1;
+ };
+ } else {
+ return function (haystack, needle) {
+ for (var i = 0; i < haystack.length; i++) {
+ if (haystack[i] === needle) {
+ return true;
+ }
+ }
+ return false;
+ };
+ }
+ }();
+
+ Kibo.extractModifiers = function (keyCombination) {
+ var modifiers, i;
+ modifiers = [];
+ for (i = 0; i < Kibo.MODIFIERS.length; i++) {
+ if (Kibo.stringContains(keyCombination, Kibo.MODIFIERS[i])) {
+ modifiers.push(Kibo.MODIFIERS[i]);
+ }
+ }
+ return modifiers;
+ };
+
+ Kibo.extractKey = function (keyCombination) {
+ var keys, i;
+ keys = Kibo.neatString(keyCombination).split(' ');
+ for (i = 0; i < keys.length; i++) {
+ if (!Kibo.arrayIncludes(Kibo.MODIFIERS, keys[i])) {
+ return keys[i];
+ }
+ }
+ };
+
+ Kibo.modifiersAndKey = function (keyCombination) {
+ var result, key;
+
+ if (Kibo.stringContains(keyCombination, 'any')) {
+ return Kibo.neatString(keyCombination).split(' ').slice(0, 2).join(' ');
+ }
+
+ result = Kibo.extractModifiers(keyCombination);
+
+ key = Kibo.extractKey(keyCombination);
+ if (key && !Kibo.arrayIncludes(Kibo.MODIFIERS, key)) {
+ result.push(key);
+ }
+
+ return result.join(' ');
+ };
+
+ Kibo.keyName = function (keyCode) {
+ return Kibo.KEY_NAMES_BY_CODE[keyCode + ''];
+ };
+
+ Kibo.keyCode = function (keyName) {
+ return +Kibo.KEY_CODES_BY_NAME[keyName];
+ };
+
+ Kibo.prototype.initialize = function () {
+ var i,
+ that = this;
+
+ this.lastKeyCode = -1;
+ this.lastModifiers = {};
+ for (i = 0; i < Kibo.MODIFIERS.length; i++) {
+ this.lastModifiers[Kibo.MODIFIERS[i]] = false;
+ }
+
+ this.keysDown = { any: [] };
+ this.keysUp = { any: [] };
+ this.downHandler = this.handler('down');
+ this.upHandler = this.handler('up');
+
+ Kibo.registerEvent(this.element, 'keydown', this.downHandler);
+ Kibo.registerEvent(this.element, 'keyup', this.upHandler);
+ Kibo.registerEvent(window, 'unload', function unloader() {
+ Kibo.unregisterEvent(that.element, 'keydown', that.downHandler);
+ Kibo.unregisterEvent(that.element, 'keyup', that.upHandler);
+ Kibo.unregisterEvent(window, 'unload', unloader);
+ });
+ };
+
+ Kibo.prototype.handler = function (upOrDown) {
+ var that = this;
+ return function (e) {
+ var i, registeredKeys, lastModifiersAndKey;
+
+ e = e || window.event;
+
+ that.lastKeyCode = e.keyCode;
+ for (i = 0; i < Kibo.MODIFIERS.length; i++) {
+ that.lastModifiers[Kibo.MODIFIERS[i]] = e[Kibo.MODIFIERS[i] + 'Key'];
+ }
+ if (Kibo.arrayIncludes(Kibo.MODIFIERS, Kibo.keyName(that.lastKeyCode))) {
+ that.lastModifiers[Kibo.keyName(that.lastKeyCode)] = true;
+ }
+
+ registeredKeys = that['keys' + Kibo.capitalize(upOrDown)];
+
+ for (i = 0; i < registeredKeys.any.length; i++) {
+ if (registeredKeys.any[i](e) === false && e.preventDefault) {
+ e.preventDefault();
+ }
+ }
+
+ lastModifiersAndKey = that.lastModifiersAndKey();
+ if (registeredKeys[lastModifiersAndKey]) {
+ for (i = 0; i < registeredKeys[lastModifiersAndKey].length; i++) {
+ if (registeredKeys[lastModifiersAndKey][i](e) === false && e.preventDefault) {
+ e.preventDefault();
+ }
+ }
+ }
+ };
+ };
+
+ Kibo.prototype.registerKeys = function (upOrDown, newKeys, func) {
+ var i,
+ keys,
+ registeredKeys = this['keys' + Kibo.capitalize(upOrDown)];
+
+ if (Kibo.isString(newKeys)) {
+ newKeys = [newKeys];
+ }
+
+ for (i = 0; i < newKeys.length; i++) {
+ keys = newKeys[i];
+ keys = Kibo.modifiersAndKey(keys + '');
+
+ if (registeredKeys[keys]) {
+ registeredKeys[keys].push(func);
+ } else {
+ registeredKeys[keys] = [func];
+ }
+ }
+
+ return this;
+ };
+
+ // jshint maxdepth:5
+ Kibo.prototype.unregisterKeys = function (upOrDown, newKeys, func) {
+ var i,
+ j,
+ keys,
+ registeredKeys = this['keys' + Kibo.capitalize(upOrDown)];
+
+ if (Kibo.isString(newKeys)) {
+ newKeys = [newKeys];
+ }
+
+ for (i = 0; i < newKeys.length; i++) {
+ keys = newKeys[i];
+ keys = Kibo.modifiersAndKey(keys + '');
+
+ if (func === null) {
+ delete registeredKeys[keys];
+ } else {
+ if (registeredKeys[keys]) {
+ for (j = 0; j < registeredKeys[keys].length; j++) {
+ if (String(registeredKeys[keys][j]) === String(func)) {
+ registeredKeys[keys].splice(j, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return this;
+ };
+
+ Kibo.prototype.off = function (keys) {
+ return this.unregisterKeys('down', keys, null);
+ };
+
+ Kibo.prototype.delegate = function (upOrDown, keys, func) {
+ return func !== null || func !== undefined ? this.registerKeys(upOrDown, keys, func) : this.unregisterKeys(upOrDown, keys, func);
+ };
+
+ Kibo.prototype.down = function (keys, func) {
+ return this.delegate('down', keys, func);
+ };
+
+ Kibo.prototype.up = function (keys, func) {
+ return this.delegate('up', keys, func);
+ };
+
+ Kibo.prototype.lastKey = function (modifier) {
+ if (!modifier) {
+ return Kibo.keyName(this.lastKeyCode);
+ }
+
+ return this.lastModifiers[modifier];
+ };
+
+ Kibo.prototype.lastModifiersAndKey = function () {
+ var result, i;
+
+ result = [];
+ for (i = 0; i < Kibo.MODIFIERS.length; i++) {
+ if (this.lastKey(Kibo.MODIFIERS[i])) {
+ result.push(Kibo.MODIFIERS[i]);
+ }
+ }
+
+ if (!Kibo.arrayIncludes(result, this.lastKey())) {
+ result.push(this.lastKey());
+ }
+
+ return result.join(' ');
+ };
+
+ exports.default = Kibo;
+ module.exports = exports['default'];
+
+/***/ },
+/* 10 */
+/***/ function(module, exports) {
+
+ /**
+ * lodash (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors <https://jquery.org/>
+ * Released under MIT license <https://lodash.com/license>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+
+ /** Used as the `TypeError` message for "Functions" methods. */
+ var FUNC_ERROR_TEXT = 'Expected a function';
+
+ /** Used as references for various `Number` constants. */
+ var INFINITY = 1 / 0,
+ MAX_INTEGER = 1.7976931348623157e+308,
+ NAN = 0 / 0;
+
+ /** `Object#toString` result references. */
+ var symbolTag = '[object Symbol]';
+
+ /** Used to match leading and trailing whitespace. */
+ var reTrim = /^\s+|\s+$/g;
+
+ /** Used to detect bad signed hexadecimal string values. */
+ var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
+
+ /** Used to detect binary string values. */
+ var reIsBinary = /^0b[01]+$/i;
+
+ /** Used to detect octal string values. */
+ var reIsOctal = /^0o[0-7]+$/i;
+
+ /** Built-in method references without a dependency on `root`. */
+ var freeParseInt = parseInt;
+
+ /** Used for built-in method references. */
+ var objectProto = Object.prototype;
+
+ /**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+ var objectToString = objectProto.toString;
+
+ /**
+ * Creates a function that invokes `func`, with the `this` binding and arguments
+ * of the created function, while it's called less than `n` times. Subsequent
+ * calls to the created function return the result of the last `func` invocation.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Function
+ * @param {number} n The number of calls at which `func` is no longer invoked.
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * jQuery(element).on('click', _.before(5, addContactToList));
+ * // => Allows adding up to 4 contacts to the list.
+ */
+ function before(n, func) {
+ var result;
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ n = toInteger(n);
+ return function() {
+ if (--n > 0) {
+ result = func.apply(this, arguments);
+ }
+ if (n <= 1) {
+ func = undefined;
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Creates a function that is restricted to invoking `func` once. Repeat calls
+ * to the function return the value of the first invocation. The `func` is
+ * invoked with the `this` binding and arguments of the created function.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to restrict.
+ * @returns {Function} Returns the new restricted function.
+ * @example
+ *
+ * var initialize = _.once(createApplication);
+ * initialize();
+ * initialize();
+ * // => `createApplication` is invoked once
+ */
+ function once(func) {
+ return before(2, func);
+ }
+
+ /**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+ function isObject(value) {
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+ }
+
+ /**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+ function isObjectLike(value) {
+ return !!value && typeof value == 'object';
+ }
+
+ /**
+ * Checks if `value` is classified as a `Symbol` primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
+ * @example
+ *
+ * _.isSymbol(Symbol.iterator);
+ * // => true
+ *
+ * _.isSymbol('abc');
+ * // => false
+ */
+ function isSymbol(value) {
+ return typeof value == 'symbol' ||
+ (isObjectLike(value) && objectToString.call(value) == symbolTag);
+ }
+
+ /**
+ * Converts `value` to a finite number.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.12.0
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {number} Returns the converted number.
+ * @example
+ *
+ * _.toFinite(3.2);
+ * // => 3.2
+ *
+ * _.toFinite(Number.MIN_VALUE);
+ * // => 5e-324
+ *
+ * _.toFinite(Infinity);
+ * // => 1.7976931348623157e+308
+ *
+ * _.toFinite('3.2');
+ * // => 3.2
+ */
+ function toFinite(value) {
+ if (!value) {
+ return value === 0 ? value : 0;
+ }
+ value = toNumber(value);
+ if (value === INFINITY || value === -INFINITY) {
+ var sign = (value < 0 ? -1 : 1);
+ return sign * MAX_INTEGER;
+ }
+ return value === value ? value : 0;
+ }
+
+ /**
+ * Converts `value` to an integer.
+ *
+ * **Note:** This method is loosely based on
+ * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {number} Returns the converted integer.
+ * @example
+ *
+ * _.toInteger(3.2);
+ * // => 3
+ *
+ * _.toInteger(Number.MIN_VALUE);
+ * // => 0
+ *
+ * _.toInteger(Infinity);
+ * // => 1.7976931348623157e+308
+ *
+ * _.toInteger('3.2');
+ * // => 3
+ */
+ function toInteger(value) {
+ var result = toFinite(value),
+ remainder = result % 1;
+
+ return result === result ? (remainder ? result - remainder : result) : 0;
+ }
+
+ /**
+ * Converts `value` to a number.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to process.
+ * @returns {number} Returns the number.
+ * @example
+ *
+ * _.toNumber(3.2);
+ * // => 3.2
+ *
+ * _.toNumber(Number.MIN_VALUE);
+ * // => 5e-324
+ *
+ * _.toNumber(Infinity);
+ * // => Infinity
+ *
+ * _.toNumber('3.2');
+ * // => 3.2
+ */
+ function toNumber(value) {
+ if (typeof value == 'number') {
+ return value;
+ }
+ if (isSymbol(value)) {
+ return NAN;
+ }
+ if (isObject(value)) {
+ var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
+ value = isObject(other) ? (other + '') : other;
+ }
+ if (typeof value != 'string') {
+ return value === 0 ? value : +value;
+ }
+ value = value.replace(reTrim, '');
+ var isBinary = reIsBinary.test(value);
+ return (isBinary || reIsOctal.test(value))
+ ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
+ : (reIsBadHex.test(value) ? NAN : +value);
+ }
+
+ module.exports = once;
+
+
+/***/ },
+/* 11 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(12);
+
+/***/ },
+/* 12 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _base_object = __webpack_require__(4);
+
+ var _base_object2 = _interopRequireDefault(_base_object);
+
+ var _core = __webpack_require__(13);
+
+ var _core2 = _interopRequireDefault(_core);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ /**
+ * The Core Factory is responsible for instantiate the core and it's plugins.
+ * @class CoreFactory
+ * @constructor
+ * @extends BaseObject
+ * @module components
+ */
+ var CoreFactory = function (_BaseObject) {
+ _inherits(CoreFactory, _BaseObject);
+
+ _createClass(CoreFactory, [{
+ key: 'loader',
+ get: function get() {
+ return this.player.loader;
+ }
+
+ /**
+ * it builds the core factory
+ * @method constructor
+ * @param {Player} player the player object
+ */
+
+ }]);
+
+ function CoreFactory(player) {
+ _classCallCheck(this, CoreFactory);
+
+ var _this = _possibleConstructorReturn(this, _BaseObject.call(this));
+
+ _this.player = player;
+ _this._options = player.options;
+ return _this;
+ }
+
+ /**
+ * creates a core and its plugins
+ * @method create
+ * @return {Core} created core
+ */
+
+
+ CoreFactory.prototype.create = function create() {
+ this.options.loader = this.loader;
+ this.core = new _core2.default(this.options);
+ this.addCorePlugins();
+ this.core.createContainers(this.options);
+ return this.core;
+ };
+
+ /**
+ * given the core plugins (`loader.corePlugins`) it builds each one
+ * @method addCorePlugins
+ * @return {Core} the core with all plugins
+ */
+
+
+ CoreFactory.prototype.addCorePlugins = function addCorePlugins() {
+ var _this2 = this;
+
+ this.loader.corePlugins.forEach(function (Plugin) {
+ var plugin = new Plugin(_this2.core);
+ _this2.core.addPlugin(plugin);
+ _this2.setupExternalInterface(plugin);
+ });
+ return this.core;
+ };
+
+ CoreFactory.prototype.setupExternalInterface = function setupExternalInterface(plugin) {
+ var externalFunctions = plugin.getExternalInterface();
+ for (var key in externalFunctions) {
+ this.player[key] = externalFunctions[key].bind(plugin);
+ }
+ };
+
+ return CoreFactory;
+ }(_base_object2.default);
+
+ exports.default = CoreFactory;
+ module.exports = exports['default'];
+
+/***/ },
+/* 13 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(14);
+
+/***/ },
+/* 14 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _utils = __webpack_require__(2);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _styler = __webpack_require__(15);
+
+ var _styler2 = _interopRequireDefault(_styler);
+
+ var _ui_object = __webpack_require__(18);
+
+ var _ui_object2 = _interopRequireDefault(_ui_object);
+
+ var _browser = __webpack_require__(3);
+
+ var _browser2 = _interopRequireDefault(_browser);
+
+ var _container_factory = __webpack_require__(20);
+
+ var _container_factory2 = _interopRequireDefault(_container_factory);
+
+ var _media_control = __webpack_require__(27);
+
+ var _media_control2 = _interopRequireDefault(_media_control);
+
+ var _mediator = __webpack_require__(30);
+
+ var _mediator2 = _interopRequireDefault(_mediator);
+
+ var _player_info = __webpack_require__(45);
+
+ var _player_info2 = _interopRequireDefault(_player_info);
+
+ var _clapprZepto = __webpack_require__(16);
+
+ var _clapprZepto2 = _interopRequireDefault(_clapprZepto);
+
+ var _style = __webpack_require__(46);
+
+ var _style2 = _interopRequireDefault(_style);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ /**
+ * The Core is responsible to manage Containers, the mediator, MediaControl
+ * and the player state.
+ * @class Core
+ * @constructor
+ * @extends UIObject
+ * @module components
+ */
+ var Core = function (_UIObject) {
+ _inherits(Core, _UIObject);
+
+ _createClass(Core, [{
+ key: 'events',
+ get: function get() {
+ return {
+ 'webkitfullscreenchange': 'handleFullscreenChange',
+ 'mousemove': 'showMediaControl',
+ 'mouseleave': 'hideMediaControl'
+ };
+ }
+ }, {
+ key: 'attributes',
+ get: function get() {
+ return {
+ 'data-player': '',
+ tabindex: 9999
+ };
+ }
+
+ /**
+ * checks if the core is ready.
+ * @property isReady
+ * @type {Boolean} `true` if the core is ready, otherwise `false`
+ */
+
+ }, {
+ key: 'isReady',
+ get: function get() {
+ return !!this.ready;
+ }
+
+ /**
+ * The internationalization plugin.
+ * @property i18n
+ * @type {Strings}
+ */
+
+ }, {
+ key: 'i18n',
+ get: function get() {
+ return this.getPlugin('strings') || { t: function t(key) {
+ return key;
+ } };
+ }
+ }]);
+
+ function Core(options) {
+ _classCallCheck(this, Core);
+
+ var _this = _possibleConstructorReturn(this, _UIObject.call(this, options));
+
+ _this.playerInfo = _player_info2.default.getInstance(options.playerId);
+ _this.firstResize = true;
+ _this.plugins = [];
+ _this.containers = [];
+ _this.setupMediaControl(null);
+ //FIXME fullscreen api sucks
+ _this._boundFullscreenHandler = function () {
+ return _this.handleFullscreenChange();
+ };
+ (0, _clapprZepto2.default)(document).bind('fullscreenchange', _this._boundFullscreenHandler);
+ (0, _clapprZepto2.default)(document).bind('MSFullscreenChange', _this._boundFullscreenHandler);
+ (0, _clapprZepto2.default)(document).bind('mozfullscreenchange', _this._boundFullscreenHandler);
+ return _this;
+ }
+
+ Core.prototype.createContainers = function createContainers(options) {
+ var _this2 = this;
+
+ this.defer = _clapprZepto2.default.Deferred();
+ this.defer.promise(this);
+ this.containerFactory = new _container_factory2.default(options, options.loader, this.i18n);
+ this.containerFactory.createContainers().then(function (containers) {
+ return _this2.setupContainers(containers);
+ }).then(function (containers) {
+ return _this2.resolveOnContainersReady(containers);
+ });
+ };
+
+ Core.prototype.updateSize = function updateSize() {
+ if (_utils.Fullscreen.isFullscreen()) {
+ this.setFullscreen();
+ } else {
+ this.setPlayerSize();
+ }
+ };
+
+ Core.prototype.setFullscreen = function setFullscreen() {
+ if (!_browser2.default.isiOS) {
+ this.$el.addClass('fullscreen');
+ this.$el.removeAttr('style');
+ this.playerInfo.previousSize = { width: this.options.width, height: this.options.height };
+ this.playerInfo.currentSize = { width: (0, _clapprZepto2.default)(window).width(), height: (0, _clapprZepto2.default)(window).height() };
+ }
+ };
+
+ Core.prototype.setPlayerSize = function setPlayerSize() {
+ this.$el.removeClass('fullscreen');
+ this.playerInfo.currentSize = this.playerInfo.previousSize;
+ this.playerInfo.previousSize = { width: (0, _clapprZepto2.default)(window).width(), height: (0, _clapprZepto2.default)(window).height() };
+ this.resize(this.playerInfo.currentSize);
+ };
+
+ Core.prototype.resize = function resize(options) {
+ if (!(0, _utils.isNumber)(options.height) && !(0, _utils.isNumber)(options.width)) {
+ this.el.style.height = '' + options.height;
+ this.el.style.width = '' + options.width;
+ } else {
+ this.el.style.height = options.height + 'px';
+ this.el.style.width = options.width + 'px';
+ }
+ this.playerInfo.previousSize = { width: this.options.width, height: this.options.height };
+ this.options.width = options.width;
+ this.options.height = options.height;
+ this.playerInfo.currentSize = options;
+ this.triggerResize(this.playerInfo.currentSize);
+ };
+
+ Core.prototype.enableResizeObserver = function enableResizeObserver() {
+ var _this3 = this;
+
+ var checkSizeCallback = function checkSizeCallback() {
+ if (_this3.playerInfo.computedSize.width != _this3.el.clientWidth || _this3.playerInfo.computedSize.height != _this3.el.clientHeight) {
+ _this3.playerInfo.computedSize = { width: _this3.el.clientWidth, height: _this3.el.clientHeight };
+ _this3.triggerResize(_this3.playerInfo.computedSize);
+ }
+ };
+ this.resizeObserverInterval = setInterval(checkSizeCallback, 500);
+ };
+
+ Core.prototype.triggerResize = function triggerResize(newSize) {
+ var thereWasChange = this.firstResize || this.oldHeight !== newSize.height || this.oldWidth !== newSize.width;
+ if (thereWasChange) {
+ _mediator2.default.trigger(this.options.playerId + ':' + _events2.default.PLAYER_RESIZE, newSize);
+ this.oldHeight = newSize.height;
+ this.oldWidth = newSize.width;
+ this.firstResize = false;
+ }
+ };
+
+ Core.prototype.disableResizeObserver = function disableResizeObserver() {
+ if (this.resizeObserverInterval) clearInterval(this.resizeObserverInterval);
+ };
+
+ Core.prototype.resolveOnContainersReady = function resolveOnContainersReady(containers) {
+ var _this4 = this;
+
+ _clapprZepto2.default.when.apply(_clapprZepto2.default, containers).done(function () {
+ _this4.defer.resolve(_this4);
+ _this4.ready = true;
+ _this4.trigger(_events2.default.CORE_READY);
+ });
+ };
+
+ Core.prototype.addPlugin = function addPlugin(plugin) {
+ this.plugins.push(plugin);
+ };
+
+ Core.prototype.hasPlugin = function hasPlugin(name) {
+ return !!this.getPlugin(name);
+ };
+
+ Core.prototype.getPlugin = function getPlugin(name) {
+ return this.plugins.filter(function (plugin) {
+ return plugin.name === name;
+ })[0];
+ };
+
+ Core.prototype.load = function load(sources, mimeType) {
+ var _this5 = this;
+
+ this.options.mimeType = mimeType;
+ sources = sources && sources.constructor === Array ? sources : [sources];
+ this.containers.forEach(function (container) {
+ return container.destroy();
+ });
+ this.mediaControl.container = null;
+ this.containerFactory.options = _clapprZepto2.default.extend(this.options, { sources: sources });
+ this.containerFactory.createContainers().then(function (containers) {
+ _this5.setupContainers(containers);
+ });
+ };
+
+ Core.prototype.destroy = function destroy() {
+ this.disableResizeObserver();
+ this.containers.forEach(function (container) {
+ return container.destroy();
+ });
+ this.plugins.forEach(function (plugin) {
+ return plugin.destroy();
+ });
+ this.$el.remove();
+ this.mediaControl.destroy();
+ (0, _clapprZepto2.default)(document).unbind('fullscreenchange', this._boundFullscreenHandler);
+ (0, _clapprZepto2.default)(document).unbind('MSFullscreenChange', this._boundFullscreenHandler);
+ (0, _clapprZepto2.default)(document).unbind('mozfullscreenchange', this._boundFullscreenHandler);
+ };
+
+ Core.prototype.handleFullscreenChange = function handleFullscreenChange() {
+ this.trigger(_events2.default.CORE_FULLSCREEN, _utils.Fullscreen.isFullscreen());
+ this.updateSize();
+ this.mediaControl.show();
+ };
+
+ Core.prototype.setMediaControlContainer = function setMediaControlContainer(container) {
+ this.mediaControl.setContainer(container);
+ this.mediaControl.render();
+ };
+
+ Core.prototype.disableMediaControl = function disableMediaControl() {
+ this.mediaControl.disable();
+ this.$el.removeClass('nocursor');
+ };
+
+ Core.prototype.enableMediaControl = function enableMediaControl() {
+ this.mediaControl.enable();
+ };
+
+ Core.prototype.removeContainer = function removeContainer(container) {
+ this.stopListening(container);
+ this.containers = this.containers.filter(function (c) {
+ return c !== container;
+ });
+ };
+
+ Core.prototype.appendContainer = function appendContainer(container) {
+ this.listenTo(container, _events2.default.CONTAINER_DESTROYED, this.removeContainer);
+ this.containers.push(container);
+ };
+
+ Core.prototype.setupContainers = function setupContainers(containers) {
+ containers.map(this.appendContainer.bind(this));
+ this.trigger(_events2.default.CORE_CONTAINERS_CREATED);
+ this.renderContainers();
+ this.setupMediaControl(this.getCurrentContainer());
+ this.render();
+ this.$el.appendTo(this.options.parentElement);
+ return this.containers;
+ };
+
+ Core.prototype.renderContainers = function renderContainers() {
+ var _this6 = this;
+
+ this.containers.map(function (container) {
+ return _this6.el.appendChild(container.render().el);
+ });
+ };
+
+ Core.prototype.createContainer = function createContainer(source, options) {
+ var container = this.containerFactory.createContainer(source, options);
+ this.appendContainer(container);
+ this.el.appendChild(container.render().el);
+ return container;
+ };
+
+ Core.prototype.setupMediaControl = function setupMediaControl(container) {
+ if (this.mediaControl) {
+ this.mediaControl.setContainer(container);
+ } else {
+ this.mediaControl = this.createMediaControl(_clapprZepto2.default.extend({ container: container, focusElement: this.el }, this.options));
+ this.listenTo(this.mediaControl, _events2.default.MEDIACONTROL_FULLSCREEN, this.toggleFullscreen);
+ this.listenTo(this.mediaControl, _events2.default.MEDIACONTROL_SHOW, this.onMediaControlShow.bind(this, true));
+ this.listenTo(this.mediaControl, _events2.default.MEDIACONTROL_HIDE, this.onMediaControlShow.bind(this, false));
+ }
+ };
+
+ Core.prototype.createMediaControl = function createMediaControl(options) {
+ if (options.mediacontrol && options.mediacontrol.external) {
+ return new options.mediacontrol.external(options).render();
+ } else {
+ return new _media_control2.default(options).render();
+ }
+ };
+
+ Core.prototype.getCurrentContainer = function getCurrentContainer() {
+ if (!this.mediaControl || !this.mediaControl.container) {
+ return this.containers[0];
+ }
+ return this.mediaControl.container;
+ };
+
+ Core.prototype.getCurrentPlayback = function getCurrentPlayback() {
+ var container = this.getCurrentContainer();
+ return container && container.playback;
+ };
+
+ Core.prototype.getPlaybackType = function getPlaybackType() {
+ var container = this.getCurrentContainer();
+ return container && container.getPlaybackType();
+ };
+
+ Core.prototype.toggleFullscreen = function toggleFullscreen() {
+ if (!_utils.Fullscreen.isFullscreen()) {
+ _utils.Fullscreen.requestFullscreen(this.el);
+ if (!_browser2.default.isiOS) {
+ this.$el.addClass('fullscreen');
+ }
+ } else {
+ _utils.Fullscreen.cancelFullscreen();
+ if (!_browser2.default.isiOS) {
+ this.$el.removeClass('fullscreen nocursor');
+ }
+ }
+ this.mediaControl.show();
+ };
+
+ Core.prototype.showMediaControl = function showMediaControl(event) {
+ this.mediaControl.show(event);
+ };
+
+ Core.prototype.hideMediaControl = function hideMediaControl() {
+ this.mediaControl.hide(this.options.hideMediaControlDelay);
+ };
+
+ Core.prototype.onMediaControlShow = function onMediaControlShow(showing) {
+ this.getCurrentContainer().trigger(showing ? _events2.default.CONTAINER_MEDIACONTROL_SHOW : _events2.default.CONTAINER_MEDIACONTROL_HIDE);
+
+ if (showing) this.$el.removeClass('nocursor');else if (_utils.Fullscreen.isFullscreen()) this.$el.addClass('nocursor');
+ };
+
+ /**
+ * enables to configure the container after its creation
+ * @method configure
+ * @param {Object} options all the options to change in form of a javascript object
+ */
+
+
+ Core.prototype.configure = function configure(options) {
+ var _this7 = this;
+
+ this._options = _clapprZepto2.default.extend(this._options, options);
+ var sources = options.source || options.sources;
+
+ if (sources) {
+ this.load(sources, options.mimeType || this.options.mimeType);
+ } else {
+ this.trigger(_events2.default.CORE_OPTIONS_CHANGE);
+
+ this.containers.forEach(function (container) {
+ container.configure(_this7.options);
+ });
+ }
+ };
+
+ Core.prototype.render = function render() {
+ var style = _styler2.default.getStyleFor(_style2.default, { baseUrl: this.options.baseUrl });
+ this.$el.append(style);
+ this.$el.append(this.mediaControl.render().el);
+
+ this.options.width = this.options.width || this.$el.width();
+ this.options.height = this.options.height || this.$el.height();
+ var size = { width: this.options.width, height: this.options.height };
+ this.playerInfo.previousSize = this.playerInfo.currentSize = this.playerInfo.computedSize = size;
+ this.updateSize();
+
+ this.previousSize = { width: this.$el.width(), height: this.$el.height() };
+
+ this.enableResizeObserver();
+
+ return this;
+ };
+
+ return Core;
+ }(_ui_object2.default);
+
+ exports.default = Core;
+ module.exports = exports['default'];
+
+/***/ },
+/* 15 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _clapprZepto = __webpack_require__(16);
+
+ var _clapprZepto2 = _interopRequireDefault(_clapprZepto);
+
+ var _template = __webpack_require__(17);
+
+ var _template2 = _interopRequireDefault(_template);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var Styler = {
+ getStyleFor: function getStyleFor(style) {
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { baseUrl: '' };
+
+ return (0, _clapprZepto2.default)('<style class="clappr-style"></style>').html((0, _template2.default)(style.toString())(options));
+ }
+ };
+
+ exports.default = Styler;
+ module.exports = exports['default'];
+
+/***/ },
+/* 16 */
+/***/ function(module, exports) {
+
+ /* Zepto v1.1.4-80-ga9184b2 - zepto event ajax callbacks deferred touch selector ie - zeptojs.com/license */
+ var Zepto=function(){function D(t){return null==t?String(t):j[S.call(t)]||"object"}function L(t){return"function"==D(t)}function k(t){return null!=t&&t==t.window}function Z(t){return null!=t&&t.nodeType==t.DOCUMENT_NODE}function $(t){return"object"==D(t)}function F(t){return $(t)&&!k(t)&&Object.getPrototypeOf(t)==Object.prototype}function R(t){return"number"==typeof t.length}function q(t){return s.call(t,function(t){return null!=t})}function W(t){return t.length>0?n.fn.concat.apply([],t):t}function z(t){return t.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function H(t){return t in c?c[t]:c[t]=new RegExp("(^|\\s)"+t+"(\\s|$)")}function _(t,e){return"number"!=typeof e||l[z(t)]?e:e+"px"}function I(t){var e,n;return f[t]||(e=u.createElement(t),u.body.appendChild(e),n=getComputedStyle(e,"").getPropertyValue("display"),e.parentNode.removeChild(e),"none"==n&&(n="block"),f[t]=n),f[t]}function U(t){return"children"in t?a.call(t.children):n.map(t.childNodes,function(t){return 1==t.nodeType?t:void 0})}function X(t,e){var n,i=t?t.length:0;for(n=0;i>n;n++)this[n]=t[n];this.length=i,this.selector=e||""}function B(n,i,r){for(e in i)r&&(F(i[e])||A(i[e]))?(F(i[e])&&!F(n[e])&&(n[e]={}),A(i[e])&&!A(n[e])&&(n[e]=[]),B(n[e],i[e],r)):i[e]!==t&&(n[e]=i[e])}function V(t,e){return null==e?n(t):n(t).filter(e)}function Y(t,e,n,i){return L(e)?e.call(t,n,i):e}function J(t,e,n){null==n?t.removeAttribute(e):t.setAttribute(e,n)}function G(e,n){var i=e.className||"",r=i&&i.baseVal!==t;return n===t?r?i.baseVal:i:void(r?i.baseVal=n:e.className=n)}function K(t){try{return t?"true"==t||("false"==t?!1:"null"==t?null:+t+""==t?+t:/^[\[\{]/.test(t)?n.parseJSON(t):t):t}catch(e){return t}}function Q(t,e){e(t);for(var n=0,i=t.childNodes.length;i>n;n++)Q(t.childNodes[n],e)}var t,e,n,i,N,P,r=[],o=r.concat,s=r.filter,a=r.slice,u=window.document,f={},c={},l={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},h=/^\s*<(\w+|!)[^>]*>/,p=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,d=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,m=/^(?:body|html)$/i,g=/([A-Z])/g,v=["val","css","html","text","data","width","height","offset"],y=["after","prepend","before","append"],w=u.createElement("table"),x=u.createElement("tr"),b={tr:u.createElement("tbody"),tbody:w,thead:w,tfoot:w,td:x,th:x,"*":u.createElement("div")},E=/complete|loaded|interactive/,T=/^[\w-]*$/,j={},S=j.toString,C={},O=u.createElement("div"),M={tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},A=Array.isArray||function(t){return t instanceof Array};return C.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var n=t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(n)return n.call(t,e);var i,r=t.parentNode,o=!r;return o&&(r=O).appendChild(t),i=~C.qsa(r,e).indexOf(t),o&&O.removeChild(t),i},N=function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():""})},P=function(t){return s.call(t,function(e,n){return t.indexOf(e)==n})},C.fragment=function(e,i,r){var o,s,f;return p.test(e)&&(o=n(u.createElement(RegExp.$1))),o||(e.replace&&(e=e.replace(d,"<$1></$2>")),i===t&&(i=h.test(e)&&RegExp.$1),i in b||(i="*"),f=b[i],f.innerHTML=""+e,o=n.each(a.call(f.childNodes),function(){f.removeChild(this)})),F(r)&&(s=n(o),n.each(r,function(t,e){v.indexOf(t)>-1?s[t](e):s.attr(t,e)})),o},C.Z=function(t,e){return new X(t,e)},C.isZ=function(t){return t instanceof C.Z},C.init=function(e,i){var r;if(!e)return C.Z();if("string"==typeof e)if(e=e.trim(),"<"==e[0]&&h.test(e))r=C.fragment(e,RegExp.$1,i),e=null;else{if(i!==t)return n(i).find(e);r=C.qsa(u,e)}else{if(L(e))return n(u).ready(e);if(C.isZ(e))return e;if(A(e))r=q(e);else if($(e))r=[e],e=null;else if(h.test(e))r=C.fragment(e.trim(),RegExp.$1,i),e=null;else{if(i!==t)return n(i).find(e);r=C.qsa(u,e)}}return C.Z(r,e)},n=function(t,e){return C.init(t,e)},n.extend=function(t){var e,n=a.call(arguments,1);return"boolean"==typeof t&&(e=t,t=n.shift()),n.forEach(function(n){B(t,n,e)}),t},C.qsa=function(t,e){var n,i="#"==e[0],r=!i&&"."==e[0],o=i||r?e.slice(1):e,s=T.test(o);return t.getElementById&&s&&i?(n=t.getElementById(o))?[n]:[]:1!==t.nodeType&&9!==t.nodeType&&11!==t.nodeType?[]:a.call(s&&!i&&t.getElementsByClassName?r?t.getElementsByClassName(o):t.getElementsByTagName(e):t.querySelectorAll(e))},n.contains=u.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e&&(e=e.parentNode);)if(e===t)return!0;return!1},n.type=D,n.isFunction=L,n.isWindow=k,n.isArray=A,n.isPlainObject=F,n.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},n.inArray=function(t,e,n){return r.indexOf.call(e,t,n)},n.camelCase=N,n.trim=function(t){return null==t?"":String.prototype.trim.call(t)},n.uuid=0,n.support={},n.expr={},n.noop=function(){},n.map=function(t,e){var n,r,o,i=[];if(R(t))for(r=0;r<t.length;r++)n=e(t[r],r),null!=n&&i.push(n);else for(o in t)n=e(t[o],o),null!=n&&i.push(n);return W(i)},n.each=function(t,e){var n,i;if(R(t)){for(n=0;n<t.length;n++)if(e.call(t[n],n,t[n])===!1)return t}else for(i in t)if(e.call(t[i],i,t[i])===!1)return t;return t},n.grep=function(t,e){return s.call(t,e)},window.JSON&&(n.parseJSON=JSON.parse),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(t,e){j["[object "+e+"]"]=e.toLowerCase()}),n.fn={constructor:C.Z,length:0,forEach:r.forEach,reduce:r.reduce,push:r.push,sort:r.sort,splice:r.splice,indexOf:r.indexOf,concat:function(){var t,e,n=[];for(t=0;t<arguments.length;t++)e=arguments[t],n[t]=C.isZ(e)?e.toArray():e;return o.apply(C.isZ(this)?this.toArray():this,n)},map:function(t){return n(n.map(this,function(e,n){return t.call(e,n,e)}))},slice:function(){return n(a.apply(this,arguments))},ready:function(t){return E.test(u.readyState)&&u.body?t(n):u.addEventListener("DOMContentLoaded",function(){t(n)},!1),this},get:function(e){return e===t?a.call(this):this[e>=0?e:e+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(t){return r.every.call(this,function(e,n){return t.call(e,n,e)!==!1}),this},filter:function(t){return L(t)?this.not(this.not(t)):n(s.call(this,function(e){return C.matches(e,t)}))},add:function(t,e){return n(P(this.concat(n(t,e))))},is:function(t){return this.length>0&&C.matches(this[0],t)},not:function(e){var i=[];if(L(e)&&e.call!==t)this.each(function(t){e.call(this,t)||i.push(this)});else{var r="string"==typeof e?this.filter(e):R(e)&&L(e.item)?a.call(e):n(e);this.forEach(function(t){r.indexOf(t)<0&&i.push(t)})}return n(i)},has:function(t){return this.filter(function(){return $(t)?n.contains(this,t):n(this).find(t).size()})},eq:function(t){return-1===t?this.slice(t):this.slice(t,+t+1)},first:function(){var t=this[0];return t&&!$(t)?t:n(t)},last:function(){var t=this[this.length-1];return t&&!$(t)?t:n(t)},find:function(t){var e,i=this;return e=t?"object"==typeof t?n(t).filter(function(){var t=this;return r.some.call(i,function(e){return n.contains(e,t)})}):1==this.length?n(C.qsa(this[0],t)):this.map(function(){return C.qsa(this,t)}):n()},closest:function(t,e){var i=this[0],r=!1;for("object"==typeof t&&(r=n(t));i&&!(r?r.indexOf(i)>=0:C.matches(i,t));)i=i!==e&&!Z(i)&&i.parentNode;return n(i)},parents:function(t){for(var e=[],i=this;i.length>0;)i=n.map(i,function(t){return(t=t.parentNode)&&!Z(t)&&e.indexOf(t)<0?(e.push(t),t):void 0});return V(e,t)},parent:function(t){return V(P(this.pluck("parentNode")),t)},children:function(t){return V(this.map(function(){return U(this)}),t)},contents:function(){return this.map(function(){return this.contentDocument||a.call(this.childNodes)})},siblings:function(t){return V(this.map(function(t,e){return s.call(U(e.parentNode),function(t){return t!==e})}),t)},empty:function(){return this.each(function(){this.innerHTML=""})},pluck:function(t){return n.map(this,function(e){return e[t]})},show:function(){return this.each(function(){"none"==this.style.display&&(this.style.display=""),"none"==getComputedStyle(this,"").getPropertyValue("display")&&(this.style.display=I(this.nodeName))})},replaceWith:function(t){return this.before(t).remove()},wrap:function(t){var e=L(t);if(this[0]&&!e)var i=n(t).get(0),r=i.parentNode||this.length>1;return this.each(function(o){n(this).wrapAll(e?t.call(this,o):r?i.cloneNode(!0):i)})},wrapAll:function(t){if(this[0]){n(this[0]).before(t=n(t));for(var e;(e=t.children()).length;)t=e.first();n(t).append(this)}return this},wrapInner:function(t){var e=L(t);return this.each(function(i){var r=n(this),o=r.contents(),s=e?t.call(this,i):t;o.length?o.wrapAll(s):r.append(s)})},unwrap:function(){return this.parent().each(function(){n(this).replaceWith(n(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css("display","none")},toggle:function(e){return this.each(function(){var i=n(this);(e===t?"none"==i.css("display"):e)?i.show():i.hide()})},prev:function(t){return n(this.pluck("previousElementSibling")).filter(t||"*")},next:function(t){return n(this.pluck("nextElementSibling")).filter(t||"*")},html:function(t){return 0 in arguments?this.each(function(e){var i=this.innerHTML;n(this).empty().append(Y(this,t,e,i))}):0 in this?this[0].innerHTML:null},text:function(t){return 0 in arguments?this.each(function(e){var n=Y(this,t,e,this.textContent);this.textContent=null==n?"":""+n}):0 in this?this[0].textContent:null},attr:function(n,i){var r;return"string"!=typeof n||1 in arguments?this.each(function(t){if(1===this.nodeType)if($(n))for(e in n)J(this,e,n[e]);else J(this,n,Y(this,i,t,this.getAttribute(n)))}):this.length&&1===this[0].nodeType?!(r=this[0].getAttribute(n))&&n in this[0]?this[0][n]:r:t},removeAttr:function(t){return this.each(function(){1===this.nodeType&&t.split(" ").forEach(function(t){J(this,t)},this)})},prop:function(t,e){return t=M[t]||t,1 in arguments?this.each(function(n){this[t]=Y(this,e,n,this[t])}):this[0]&&this[0][t]},data:function(e,n){var i="data-"+e.replace(g,"-$1").toLowerCase(),r=1 in arguments?this.attr(i,n):this.attr(i);return null!==r?K(r):t},val:function(t){return 0 in arguments?this.each(function(e){this.value=Y(this,t,e,this.value)}):this[0]&&(this[0].multiple?n(this[0]).find("option").filter(function(){return this.selected}).pluck("value"):this[0].value)},offset:function(t){if(t)return this.each(function(e){var i=n(this),r=Y(this,t,e,i.offset()),o=i.offsetParent().offset(),s={top:r.top-o.top,left:r.left-o.left};"static"==i.css("position")&&(s.position="relative"),i.css(s)});if(!this.length)return null;if(!n.contains(u.documentElement,this[0]))return{top:0,left:0};var e=this[0].getBoundingClientRect();return{left:e.left+window.pageXOffset,top:e.top+window.pageYOffset,width:Math.round(e.width),height:Math.round(e.height)}},css:function(t,i){if(arguments.length<2){var r,o=this[0];if(!o)return;if(r=getComputedStyle(o,""),"string"==typeof t)return o.style[N(t)]||r.getPropertyValue(t);if(A(t)){var s={};return n.each(t,function(t,e){s[e]=o.style[N(e)]||r.getPropertyValue(e)}),s}}var a="";if("string"==D(t))i||0===i?a=z(t)+":"+_(t,i):this.each(function(){this.style.removeProperty(z(t))});else for(e in t)t[e]||0===t[e]?a+=z(e)+":"+_(e,t[e])+";":this.each(function(){this.style.removeProperty(z(e))});return this.each(function(){this.style.cssText+=";"+a})},index:function(t){return t?this.indexOf(n(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return t?r.some.call(this,function(t){return this.test(G(t))},H(t)):!1},addClass:function(t){return t?this.each(function(e){if("className"in this){i=[];var r=G(this),o=Y(this,t,e,r);o.split(/\s+/g).forEach(function(t){n(this).hasClass(t)||i.push(t)},this),i.length&&G(this,r+(r?" ":"")+i.join(" "))}}):this},removeClass:function(e){return this.each(function(n){if("className"in this){if(e===t)return G(this,"");i=G(this),Y(this,e,n,i).split(/\s+/g).forEach(function(t){i=i.replace(H(t)," ")}),G(this,i.trim())}})},toggleClass:function(e,i){return e?this.each(function(r){var o=n(this),s=Y(this,e,r,G(this));s.split(/\s+/g).forEach(function(e){(i===t?!o.hasClass(e):i)?o.addClass(e):o.removeClass(e)})}):this},scrollTop:function(e){if(this.length){var n="scrollTop"in this[0];return e===t?n?this[0].scrollTop:this[0].pageYOffset:this.each(n?function(){this.scrollTop=e}:function(){this.scrollTo(this.scrollX,e)})}},scrollLeft:function(e){if(this.length){var n="scrollLeft"in this[0];return e===t?n?this[0].scrollLeft:this[0].pageXOffset:this.each(n?function(){this.scrollLeft=e}:function(){this.scrollTo(e,this.scrollY)})}},position:function(){if(this.length){var t=this[0],e=this.offsetParent(),i=this.offset(),r=m.test(e[0].nodeName)?{top:0,left:0}:e.offset();return i.top-=parseFloat(n(t).css("margin-top"))||0,i.left-=parseFloat(n(t).css("margin-left"))||0,r.top+=parseFloat(n(e[0]).css("border-top-width"))||0,r.left+=parseFloat(n(e[0]).css("border-left-width"))||0,{top:i.top-r.top,left:i.left-r.left}}},offsetParent:function(){return this.map(function(){for(var t=this.offsetParent||u.body;t&&!m.test(t.nodeName)&&"static"==n(t).css("position");)t=t.offsetParent;return t})}},n.fn.detach=n.fn.remove,["width","height"].forEach(function(e){var i=e.replace(/./,function(t){return t[0].toUpperCase()});n.fn[e]=function(r){var o,s=this[0];return r===t?k(s)?s["inner"+i]:Z(s)?s.documentElement["scroll"+i]:(o=this.offset())&&o[e]:this.each(function(t){s=n(this),s.css(e,Y(this,r,t,s[e]()))})}}),y.forEach(function(t,e){var i=e%2;n.fn[t]=function(){var t,o,r=n.map(arguments,function(e){return t=D(e),"object"==t||"array"==t||null==e?e:C.fragment(e)}),s=this.length>1;return r.length<1?this:this.each(function(t,a){o=i?a:a.parentNode,a=0==e?a.nextSibling:1==e?a.firstChild:2==e?a:null;var f=n.contains(u.documentElement,o);r.forEach(function(t){if(s)t=t.cloneNode(!0);else if(!o)return n(t).remove();o.insertBefore(t,a),f&&Q(t,function(t){null==t.nodeName||"SCRIPT"!==t.nodeName.toUpperCase()||t.type&&"text/javascript"!==t.type||t.src||window.eval.call(window,t.innerHTML)})})})},n.fn[i?t+"To":"insert"+(e?"Before":"After")]=function(e){return n(e)[t](this),this}}),C.Z.prototype=X.prototype=n.fn,C.uniq=P,C.deserializeValue=K,n.zepto=C,n}();window.Zepto=Zepto,void 0===window.$&&(window.$=Zepto),function(t){function l(t){return t._zid||(t._zid=e++)}function h(t,e,n,i){if(e=p(e),e.ns)var r=d(e.ns);return(s[l(t)]||[]).filter(function(t){return!(!t||e.e&&t.e!=e.e||e.ns&&!r.test(t.ns)||n&&l(t.fn)!==l(n)||i&&t.sel!=i)})}function p(t){var e=(""+t).split(".");return{e:e[0],ns:e.slice(1).sort().join(" ")}}function d(t){return new RegExp("(?:^| )"+t.replace(" "," .* ?")+"(?: |$)")}function m(t,e){return t.del&&!u&&t.e in f||!!e}function g(t){return c[t]||u&&f[t]||t}function v(e,i,r,o,a,u,f){var h=l(e),d=s[h]||(s[h]=[]);i.split(/\s/).forEach(function(i){if("ready"==i)return t(document).ready(r);var s=p(i);s.fn=r,s.sel=a,s.e in c&&(r=function(e){var n=e.relatedTarget;return!n||n!==this&&!t.contains(this,n)?s.fn.apply(this,arguments):void 0}),s.del=u;var l=u||r;s.proxy=function(t){if(t=T(t),!t.isImmediatePropagationStopped()){t.data=o;var i=l.apply(e,t._args==n?[t]:[t].concat(t._args));return i===!1&&(t.preventDefault(),t.stopPropagation()),i}},s.i=d.length,d.push(s),"addEventListener"in e&&e.addEventListener(g(s.e),s.proxy,m(s,f))})}function y(t,e,n,i,r){var o=l(t);(e||"").split(/\s/).forEach(function(e){h(t,e,n,i).forEach(function(e){delete s[o][e.i],"removeEventListener"in t&&t.removeEventListener(g(e.e),e.proxy,m(e,r))})})}function T(e,i){return(i||!e.isDefaultPrevented)&&(i||(i=e),t.each(E,function(t,n){var r=i[t];e[t]=function(){return this[n]=w,r&&r.apply(i,arguments)},e[n]=x}),(i.defaultPrevented!==n?i.defaultPrevented:"returnValue"in i?i.returnValue===!1:i.getPreventDefault&&i.getPreventDefault())&&(e.isDefaultPrevented=w)),e}function j(t){var e,i={originalEvent:t};for(e in t)b.test(e)||t[e]===n||(i[e]=t[e]);return T(i,t)}var n,e=1,i=Array.prototype.slice,r=t.isFunction,o=function(t){return"string"==typeof t},s={},a={},u="onfocusin"in window,f={focus:"focusin",blur:"focusout"},c={mouseenter:"mouseover",mouseleave:"mouseout"};a.click=a.mousedown=a.mouseup=a.mousemove="MouseEvents",t.event={add:v,remove:y},t.proxy=function(e,n){var s=2 in arguments&&i.call(arguments,2);if(r(e)){var a=function(){return e.apply(n,s?s.concat(i.call(arguments)):arguments)};return a._zid=l(e),a}if(o(n))return s?(s.unshift(e[n],e),t.proxy.apply(null,s)):t.proxy(e[n],e);throw new TypeError("expected function")},t.fn.bind=function(t,e,n){return this.on(t,e,n)},t.fn.unbind=function(t,e){return this.off(t,e)},t.fn.one=function(t,e,n,i){return this.on(t,e,n,i,1)};var w=function(){return!0},x=function(){return!1},b=/^([A-Z]|returnValue$|layer[XY]$)/,E={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};t.fn.delegate=function(t,e,n){return this.on(e,t,n)},t.fn.undelegate=function(t,e,n){return this.off(e,t,n)},t.fn.live=function(e,n){return t(document.body).delegate(this.selector,e,n),this},t.fn.die=function(e,n){return t(document.body).undelegate(this.selector,e,n),this},t.fn.on=function(e,s,a,u,f){var c,l,h=this;return e&&!o(e)?(t.each(e,function(t,e){h.on(t,s,a,e,f)}),h):(o(s)||r(u)||u===!1||(u=a,a=s,s=n),(u===n||a===!1)&&(u=a,a=n),u===!1&&(u=x),h.each(function(n,r){f&&(c=function(t){return y(r,t.type,u),u.apply(this,arguments)}),s&&(l=function(e){var n,o=t(e.target).closest(s,r).get(0);return o&&o!==r?(n=t.extend(j(e),{currentTarget:o,liveFired:r}),(c||u).apply(o,[n].concat(i.call(arguments,1)))):void 0}),v(r,e,u,a,s,l||c)}))},t.fn.off=function(e,i,s){var a=this;return e&&!o(e)?(t.each(e,function(t,e){a.off(t,i,e)}),a):(o(i)||r(s)||s===!1||(s=i,i=n),s===!1&&(s=x),a.each(function(){y(this,e,s,i)}))},t.fn.trigger=function(e,n){return e=o(e)||t.isPlainObject(e)?t.Event(e):T(e),e._args=n,this.each(function(){e.type in f&&"function"==typeof this[e.type]?this[e.type]():"dispatchEvent"in this?this.dispatchEvent(e):t(this).triggerHandler(e,n)})},t.fn.triggerHandler=function(e,n){var i,r;return this.each(function(s,a){i=j(o(e)?t.Event(e):e),i._args=n,i.target=a,t.each(h(a,e.type||e),function(t,e){return r=e.proxy(i),i.isImmediatePropagationStopped()?!1:void 0})}),r},"focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function(e){t.fn[e]=function(t){return 0 in arguments?this.bind(e,t):this.trigger(e)}}),t.Event=function(t,e){o(t)||(e=t,t=e.type);var n=document.createEvent(a[t]||"Events"),i=!0;if(e)for(var r in e)"bubbles"==r?i=!!e[r]:n[r]=e[r];return n.initEvent(t,i,!0),T(n)}}(Zepto),function(t){function h(e,n,i){var r=t.Event(n);return t(e).trigger(r,i),!r.isDefaultPrevented()}function p(t,e,i,r){return t.global?h(e||n,i,r):void 0}function d(e){e.global&&0===t.active++&&p(e,null,"ajaxStart")}function m(e){e.global&&!--t.active&&p(e,null,"ajaxStop")}function g(t,e){var n=e.context;return e.beforeSend.call(n,t,e)===!1||p(e,n,"ajaxBeforeSend",[t,e])===!1?!1:void p(e,n,"ajaxSend",[t,e])}function v(t,e,n,i){var r=n.context,o="success";n.success.call(r,t,o,e),i&&i.resolveWith(r,[t,o,e]),p(n,r,"ajaxSuccess",[e,n,t]),w(o,e,n)}function y(t,e,n,i,r){var o=i.context;i.error.call(o,n,e,t),r&&r.rejectWith(o,[n,e,t]),p(i,o,"ajaxError",[n,i,t||e]),w(e,n,i)}function w(t,e,n){var i=n.context;n.complete.call(i,e,t),p(n,i,"ajaxComplete",[e,n]),m(n)}function x(){}function b(t){return t&&(t=t.split(";",2)[0]),t&&(t==f?"html":t==u?"json":s.test(t)?"script":a.test(t)&&"xml")||"text"}function E(t,e){return""==e?t:(t+"&"+e).replace(/[&?]{1,2}/,"?")}function T(e){e.processData&&e.data&&"string"!=t.type(e.data)&&(e.data=t.param(e.data,e.traditional)),!e.data||e.type&&"GET"!=e.type.toUpperCase()||(e.url=E(e.url,e.data),e.data=void 0)}function j(e,n,i,r){return t.isFunction(n)&&(r=i,i=n,n=void 0),t.isFunction(i)||(r=i,i=void 0),{url:e,data:n,success:i,dataType:r}}function C(e,n,i,r){var o,s=t.isArray(n),a=t.isPlainObject(n);t.each(n,function(n,u){o=t.type(u),r&&(n=i?r:r+"["+(a||"object"==o||"array"==o?n:"")+"]"),!r&&s?e.add(u.name,u.value):"array"==o||!i&&"object"==o?C(e,u,i,n):e.add(n,u)})}var i,r,e=0,n=window.document,o=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,s=/^(?:text|application)\/javascript/i,a=/^(?:text|application)\/xml/i,u="application/json",f="text/html",c=/^\s*$/,l=n.createElement("a");l.href=window.location.href,t.active=0,t.ajaxJSONP=function(i,r){if(!("type"in i))return t.ajax(i);var f,h,o=i.jsonpCallback,s=(t.isFunction(o)?o():o)||"jsonp"+ ++e,a=n.createElement("script"),u=window[s],c=function(e){t(a).triggerHandler("error",e||"abort")},l={abort:c};return r&&r.promise(l),t(a).on("load error",function(e,n){clearTimeout(h),t(a).off().remove(),"error"!=e.type&&f?v(f[0],l,i,r):y(null,n||"error",l,i,r),window[s]=u,f&&t.isFunction(u)&&u(f[0]),u=f=void 0}),g(l,i)===!1?(c("abort"),l):(window[s]=function(){f=arguments},a.src=i.url.replace(/\?(.+)=\?/,"?$1="+s),n.head.appendChild(a),i.timeout>0&&(h=setTimeout(function(){c("timeout")},i.timeout)),l)},t.ajaxSettings={type:"GET",beforeSend:x,success:x,error:x,complete:x,context:null,global:!0,xhr:function(){return new window.XMLHttpRequest},accepts:{script:"text/javascript, application/javascript, application/x-javascript",json:u,xml:"application/xml, text/xml",html:f,text:"text/plain"},crossDomain:!1,timeout:0,processData:!0,cache:!0},t.ajax=function(e){var a,u,o=t.extend({},e||{}),s=t.Deferred&&t.Deferred();for(i in t.ajaxSettings)void 0===o[i]&&(o[i]=t.ajaxSettings[i]);d(o),o.crossDomain||(a=n.createElement("a"),a.href=o.url,a.href=a.href,o.crossDomain=l.protocol+"//"+l.host!=a.protocol+"//"+a.host),o.url||(o.url=window.location.toString()),(u=o.url.indexOf("#"))>-1&&(o.url=o.url.slice(0,u)),T(o);var f=o.dataType,h=/\?.+=\?/.test(o.url);if(h&&(f="jsonp"),o.cache!==!1&&(e&&e.cache===!0||"script"!=f&&"jsonp"!=f)||(o.url=E(o.url,"_="+Date.now())),"jsonp"==f)return h||(o.url=E(o.url,o.jsonp?o.jsonp+"=?":o.jsonp===!1?"":"callback=?")),t.ajaxJSONP(o,s);var N,p=o.accepts[f],m={},w=function(t,e){m[t.toLowerCase()]=[t,e]},j=/^([\w-]+:)\/\//.test(o.url)?RegExp.$1:window.location.protocol,S=o.xhr(),C=S.setRequestHeader;if(s&&s.promise(S),o.crossDomain||w("X-Requested-With","XMLHttpRequest"),w("Accept",p||"*/*"),(p=o.mimeType||p)&&(p.indexOf(",")>-1&&(p=p.split(",",2)[0]),S.overrideMimeType&&S.overrideMimeType(p)),(o.contentType||o.contentType!==!1&&o.data&&"GET"!=o.type.toUpperCase())&&w("Content-Type",o.contentType||"application/x-www-form-urlencoded"),o.headers)for(r in o.headers)w(r,o.headers[r]);if(S.setRequestHeader=w,S.onreadystatechange=function(){if(4==S.readyState){S.onreadystatechange=x,clearTimeout(N);var e,n=!1;if(S.status>=200&&S.status<300||304==S.status||0==S.status&&"file:"==j){f=f||b(o.mimeType||S.getResponseHeader("content-type")),e=S.responseText;try{"script"==f?(1,eval)(e):"xml"==f?e=S.responseXML:"json"==f&&(e=c.test(e)?null:t.parseJSON(e))}catch(i){n=i}n?y(n,"parsererror",S,o,s):v(e,S,o,s)}else y(S.statusText||null,S.status?"error":"abort",S,o,s)}},g(S,o)===!1)return S.abort(),y(null,"abort",S,o,s),S;if(o.xhrFields)for(r in o.xhrFields)S[r]=o.xhrFields[r];var P="async"in o?o.async:!0;S.open(o.type,o.url,P,o.username,o.password);for(r in m)C.apply(S,m[r]);return o.timeout>0&&(N=setTimeout(function(){S.onreadystatechange=x,S.abort(),y(null,"timeout",S,o,s)},o.timeout)),S.send(o.data?o.data:null),S},t.get=function(){return t.ajax(j.apply(null,arguments))},t.post=function(){var e=j.apply(null,arguments);return e.type="POST",t.ajax(e)},t.getJSON=function(){var e=j.apply(null,arguments);return e.dataType="json",t.ajax(e)},t.fn.load=function(e,n,i){if(!this.length)return this;var a,r=this,s=e.split(/\s/),u=j(e,n,i),f=u.success;return s.length>1&&(u.url=s[0],a=s[1]),u.success=function(e){r.html(a?t("<div>").html(e.replace(o,"")).find(a):e),f&&f.apply(r,arguments)},t.ajax(u),this};var S=encodeURIComponent;t.param=function(e,n){var i=[];return i.add=function(e,n){t.isFunction(n)&&(n=n()),null==n&&(n=""),this.push(S(e)+"="+S(n))},C(i,e,n),i.join("&").replace(/%20/g,"+")}}(Zepto),function(t){t.Callbacks=function(e){e=t.extend({},e);var n,i,r,o,s,a,u=[],f=!e.once&&[],c=function(t){for(n=e.memory&&t,i=!0,a=o||0,o=0,s=u.length,r=!0;u&&s>a;++a)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}r=!1,u&&(f?f.length&&c(f.shift()):n?u.length=0:l.disable())},l={add:function(){if(u){var i=u.length,a=function(n){t.each(n,function(t,n){"function"==typeof n?e.unique&&l.has(n)||u.push(n):n&&n.length&&"string"!=typeof n&&a(n)})};a(arguments),r?s=u.length:n&&(o=i,c(n))}return this},remove:function(){return u&&t.each(arguments,function(e,n){for(var i;(i=t.inArray(n,u,i))>-1;)u.splice(i,1),r&&(s>=i&&--s,a>=i&&--a)}),this},has:function(e){return!(!u||!(e?t.inArray(e,u)>-1:u.length))},empty:function(){return s=u.length=0,this},disable:function(){return u=f=n=void 0,this},disabled:function(){return!u},lock:function(){return f=void 0,n||l.disable(),this},locked:function(){return!f},fireWith:function(t,e){return!u||i&&!f||(e=e||[],e=[t,e.slice?e.slice():e],r?f.push(e):c(e)),this},fire:function(){return l.fireWith(this,arguments)},fired:function(){return!!i}};return l}}(Zepto),function(t){function n(e){var i=[["resolve","done",t.Callbacks({once:1,memory:1}),"resolved"],["reject","fail",t.Callbacks({once:1,memory:1}),"rejected"],["notify","progress",t.Callbacks({memory:1})]],r="pending",o={state:function(){return r},always:function(){return s.done(arguments).fail(arguments),this},then:function(){var e=arguments;return n(function(n){t.each(i,function(i,r){var a=t.isFunction(e[i])&&e[i];s[r[1]](function(){var e=a&&a.apply(this,arguments);if(e&&t.isFunction(e.promise))e.promise().done(n.resolve).fail(n.reject).progress(n.notify);else{var i=this===o?n.promise():this,s=a?[e]:arguments;n[r[0]+"With"](i,s)}})}),e=null}).promise()},promise:function(e){return null!=e?t.extend(e,o):o}},s={};return t.each(i,function(t,e){var n=e[2],a=e[3];o[e[1]]=n.add,a&&n.add(function(){r=a},i[1^t][2].disable,i[2][2].lock),s[e[0]]=function(){return s[e[0]+"With"](this===s?o:this,arguments),this},s[e[0]+"With"]=n.fireWith}),o.promise(s),e&&e.call(s,s),s}var e=Array.prototype.slice;t.when=function(i){var f,c,l,r=e.call(arguments),o=r.length,s=0,a=1!==o||i&&t.isFunction(i.promise)?o:0,u=1===a?i:n(),h=function(t,n,i){return function(r){n[t]=this,i[t]=arguments.length>1?e.call(arguments):r,i===f?u.notifyWith(n,i):--a||u.resolveWith(n,i)}};if(o>1)for(f=new Array(o),c=new Array(o),l=new Array(o);o>s;++s)r[s]&&t.isFunction(r[s].promise)?r[s].promise().done(h(s,l,r)).fail(u.reject).progress(h(s,c,f)):--a;return a||u.resolveWith(l,r),u.promise()},t.Deferred=n}(Zepto),function(t){function u(t,e,n,i){return Math.abs(t-e)>=Math.abs(n-i)?t-e>0?"Left":"Right":n-i>0?"Up":"Down"}function f(){o=null,e.last&&(e.el.trigger("longTap"),e={})}function c(){o&&clearTimeout(o),o=null}function l(){n&&clearTimeout(n),i&&clearTimeout(i),r&&clearTimeout(r),o&&clearTimeout(o),n=i=r=o=null,e={}}function h(t){return("touch"==t.pointerType||t.pointerType==t.MSPOINTER_TYPE_TOUCH)&&t.isPrimary}function p(t,e){return t.type=="pointer"+e||t.type.toLowerCase()=="mspointer"+e}var n,i,r,o,a,e={},s=750;t(document).ready(function(){var d,m,y,w,g=0,v=0;"MSGesture"in window&&(a=new MSGesture,a.target=document.body),t(document).bind("MSGestureEnd",function(t){var n=t.velocityX>1?"Right":t.velocityX<-1?"Left":t.velocityY>1?"Down":t.velocityY<-1?"Up":null;n&&(e.el.trigger("swipe"),e.el.trigger("swipe"+n))}).on("touchstart MSPointerDown pointerdown",function(i){(!(w=p(i,"down"))||h(i))&&(y=w?i:i.touches[0],i.touches&&1===i.touches.length&&e.x2&&(e.x2=void 0,e.y2=void 0),d=Date.now(),m=d-(e.last||d),e.el=t("tagName"in y.target?y.target:y.target.parentNode),n&&clearTimeout(n),e.x1=y.pageX,e.y1=y.pageY,m>0&&250>=m&&(e.isDoubleTap=!0),e.last=d,o=setTimeout(f,s),a&&w&&a.addPointer(i.pointerId))}).on("touchmove MSPointerMove pointermove",function(t){(!(w=p(t,"move"))||h(t))&&(y=w?t:t.touches[0],c(),e.x2=y.pageX,e.y2=y.pageY,g+=Math.abs(e.x1-e.x2),v+=Math.abs(e.y1-e.y2))}).on("touchend MSPointerUp pointerup",function(o){(!(w=p(o,"up"))||h(o))&&(c(),e.x2&&Math.abs(e.x1-e.x2)>30||e.y2&&Math.abs(e.y1-e.y2)>30?r=setTimeout(function(){e.el.trigger("swipe"),e.el.trigger("swipe"+u(e.x1,e.x2,e.y1,e.y2)),e={}},0):"last"in e&&(30>g&&30>v?i=setTimeout(function(){var i=t.Event("tap");i.cancelTouch=l,e.el.trigger(i),e.isDoubleTap?(e.el&&e.el.trigger("doubleTap"),e={}):n=setTimeout(function(){n=null,e.el&&e.el.trigger("singleTap"),e={}},250)},0):e={}),g=v=0)}).on("touchcancel MSPointerCancel pointercancel",l),t(window).on("scroll",l)}),["swipe","swipeLeft","swipeRight","swipeUp","swipeDown","doubleTap","tap","singleTap","longTap"].forEach(function(e){t.fn[e]=function(t){return this.on(e,t)}})}(Zepto),function(t){function r(e){return e=t(e),!(!e.width()&&!e.height())&&"none"!==e.css("display")}function f(t,e){t=t.replace(/=#\]/g,'="#"]');var n,i,r=s.exec(t);if(r&&r[2]in o&&(n=o[r[2]],i=r[3],t=r[1],i)){var a=Number(i);i=isNaN(a)?i.replace(/^["']|["']$/g,""):a}return e(t,n,i)}var e=t.zepto,n=e.qsa,i=e.matches,o=t.expr[":"]={visible:function(){return r(this)?this:void 0},hidden:function(){return r(this)?void 0:this},selected:function(){return this.selected?this:void 0},checked:function(){return this.checked?this:void 0},parent:function(){return this.parentNode},first:function(t){return 0===t?this:void 0},last:function(t,e){return t===e.length-1?this:void 0},eq:function(t,e,n){return t===n?this:void 0},contains:function(e,n,i){return t(this).text().indexOf(i)>-1?this:void 0},has:function(t,n,i){return e.qsa(this,i).length?this:void 0}},s=new RegExp("(.*):(\\w+)(?:\\(([^)]+)\\))?$\\s*"),a=/^\s*>/,u="Zepto"+ +new Date;e.qsa=function(i,r){return f(r,function(o,s,f){try{var c;!o&&s?o="*":a.test(o)&&(c=t(i).addClass(u),o="."+u+" "+o);var l=n(i,o)}catch(h){throw console.error("error performing selector: %o",r),h}finally{c&&c.removeClass(u)}return s?e.uniq(t.map(l,function(t,e){return s.call(t,e,l,f)})):l})},e.matches=function(t,e){return f(e,function(e,n,r){return!(e&&!i(t,e)||n&&n.call(t,null,r)!==t)})}}(Zepto),function(){try{getComputedStyle(void 0)}catch(t){var e=getComputedStyle;window.getComputedStyle=function(t){try{return e(t)}catch(n){return null}}}}();
+ module.exports = Zepto;
+
+
+/***/ },
+/* 17 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ /* eslint-disable no-var */
+ // Simple JavaScript Templating
+ // Paul Miller (http://paulmillr.com)
+ // http://underscorejs.org
+ // (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+
+ // By default, Underscore uses ERB-style template delimiters, change the
+ // following template settings to use alternative delimiters.
+ var settings = {
+ evaluate: /<%([\s\S]+?)%>/g,
+ interpolate: /<%=([\s\S]+?)%>/g,
+ escape: /<%-([\s\S]+?)%>/g
+ };
+
+ // When customizing `templateSettings`, if you don't want to define an
+ // interpolation, evaluation or escaping regex, we need one that is
+ // guaranteed not to match.
+ var noMatch = /(.)^/;
+
+ // Certain characters need to be escaped so that they can be put into a
+ // string literal.
+ var escapes = {
+ '\'': '\'',
+ '\\': '\\',
+ '\r': 'r',
+ '\n': 'n',
+ '\t': 't',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
+ var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
+
+ // List of HTML entities for escaping.
+ var htmlEntities = {
+ '&': '&amp;',
+ '<': '&lt;',
+ '>': '&gt;',
+ '"': '&quot;',
+ '\'': '&#x27;'
+ };
+
+ var entityRe = new RegExp('[&<>"\']', 'g');
+
+ var escapeExpr = function escapeExpr(string) {
+ if (string === null) {
+ return '';
+ }
+ return ('' + string).replace(entityRe, function (match) {
+ return htmlEntities[match];
+ });
+ };
+
+ var counter = 0;
+
+ // JavaScript micro-templating, similar to John Resig's implementation.
+ // Underscore templating handles arbitrary delimiters, preserves whitespace,
+ // and correctly escapes quotes within interpolated code.
+ var tmpl = function tmpl(text, data) {
+ var render;
+
+ // Combine delimiters into one regular expression via alternation.
+ var matcher = new RegExp([(settings.escape || noMatch).source, (settings.interpolate || noMatch).source, (settings.evaluate || noMatch).source].join('|') + '|$', 'g');
+
+ // Compile the template source, escaping string literals appropriately.
+ var index = 0;
+ var source = '__p+=\'';
+ text.replace(matcher, function (match, escape, interpolate, evaluate, offset) {
+ source += text.slice(index, offset).replace(escaper, function (match) {
+ return '\\' + escapes[match];
+ });
+
+ if (escape) {
+ source += '\'+\n((__t=(' + escape + '))==null?\'\':escapeExpr(__t))+\n\'';
+ }
+ if (interpolate) {
+ source += '\'+\n((__t=(' + interpolate + '))==null?\'\':__t)+\n\'';
+ }
+ if (evaluate) {
+ source += '\';\n' + evaluate + '\n__p+=\'';
+ }
+ index = offset + match.length;
+ return match;
+ });
+ source += '\';\n';
+
+ // If a variable is not specified, place data values in local scope.
+ if (!settings.variable) {
+ source = 'with(obj||{}){\n' + source + '}\n';
+ }
+
+ source = 'var __t,__p=\'\',__j=Array.prototype.join,' + 'print=function(){__p+=__j.call(arguments,\'\');};\n' + source + 'return __p;\n//# sourceURL=/microtemplates/source[' + counter++ + ']';
+
+ try {
+ /*jshint -W054 */
+ // TODO: find a way to avoid eval
+ render = new Function(settings.variable || 'obj', 'escapeExpr', source);
+ } catch (e) {
+ e.source = source;
+ throw e;
+ }
+
+ if (data) {
+ return render(data, escapeExpr);
+ }
+ var template = function template(data) {
+ return render.call(this, data, escapeExpr);
+ };
+
+ // Provide the compiled function source as a convenience for precompilation.
+ template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
+
+ return template;
+ };
+ tmpl.settings = settings;
+
+ module.exports = tmpl;
+
+/***/ },
+/* 18 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _utils = __webpack_require__(2);
+
+ var _clapprZepto = __webpack_require__(16);
+
+ var _clapprZepto2 = _interopRequireDefault(_clapprZepto);
+
+ var _lodash = __webpack_require__(19);
+
+ var _lodash2 = _interopRequireDefault(_lodash);
+
+ var _base_object = __webpack_require__(4);
+
+ var _base_object2 = _interopRequireDefault(_base_object);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var delegateEventSplitter = /^(\S+)\s*(.*)$/;
+
+ /**
+ * A base class to create ui object.
+ * @class UIObject
+ * @constructor
+ * @extends BaseObject
+ * @module base
+ */
+
+ var UIObject = function (_BaseObject) {
+ _inherits(UIObject, _BaseObject);
+
+ _createClass(UIObject, [{
+ key: 'tagName',
+
+ /**
+ * a unique id prefixed with `'c'`, `c1, c232`
+ *
+ * @property cid
+ * @type String
+ */
+ /**
+ * the dom element itself
+ *
+ * @property el
+ * @type HTMLElement
+ */
+ /**
+ * the dom element wrapped by `$`
+ *
+ * @property $el
+ * @type HTMLElement
+ */
+
+ /**
+ * gets the tag name for the ui component
+ * @method tagName
+ * @default div
+ * @return {String} tag's name
+ */
+ get: function get() {
+ return 'div';
+ }
+ /**
+ * a literal object mapping element's events to methods
+ * @property events
+ * @type Object
+ * @example
+ *
+ *```javascript
+ *
+ * class MyButton extends UIObject {
+ * constructor(options) {
+ * super(options)
+ * this.myId = 0
+ * }
+ * get events() { return { 'click': 'myClick' } }
+ * myClick(){ this.myId = 42 }
+ * }
+ *
+ * // when you click on MyButton the method `myClick` will be called
+ *```
+ */
+
+ }, {
+ key: 'events',
+ get: function get() {
+ return {};
+ }
+ /**
+ * a literal object mapping attributes and values to the element
+ * element's attribute name and the value the attribute value
+ * @property attributes
+ * @type Object
+ * @example
+ *
+ *```javascript
+ *
+ * class MyButton extends UIObject {
+ * constructor(options) { super(options) }
+ * get attributes() { return { class: 'my-button'} }
+ * }
+ *
+ * // MyButton.el.className will be 'my-button'
+ * ```
+ */
+
+ }, {
+ key: 'attributes',
+ get: function get() {
+ return {};
+ }
+
+ /**
+ * it builds an ui component by:
+ * * creating an id for the component `cid`
+ * * making sure the element is created `$el`
+ * * delegating all `events` to the element
+ * @method constructor
+ * @param {Object} options the options object
+ */
+
+ }]);
+
+ function UIObject(options) {
+ _classCallCheck(this, UIObject);
+
+ var _this = _possibleConstructorReturn(this, _BaseObject.call(this, options));
+
+ _this.cid = (0, _utils.uniqueId)('c');
+ _this._ensureElement();
+ _this.delegateEvents();
+ return _this;
+ }
+
+ /**
+ * selects within the component.
+ * @method $
+ * @param {String} selector a selector to find within the component.
+ * @return {HTMLElement} an element, if it exists.
+ * @example
+ * ```javascript
+ * fullScreenBarUIComponent.$('.button-full') //will return only `.button-full` within the component
+ * ```
+ */
+
+
+ UIObject.prototype.$ = function $(selector) {
+ return this.$el.find(selector);
+ };
+
+ /**
+ * render the component, usually attach it to a real existent `element`
+ * @method render
+ * @return {UIObject} itself
+ */
+
+
+ UIObject.prototype.render = function render() {
+ return this;
+ };
+
+ /**
+ * removes the ui component from DOM
+ * @method remove
+ * @return {UIObject} itself
+ */
+
+
+ UIObject.prototype.remove = function remove() {
+ this.$el.remove();
+ this.stopListening();
+ this.undelegateEvents();
+ return this;
+ };
+
+ /**
+ * set element to `el` and `$el`
+ * @method setElement
+ * @param {HTMLElement} element
+ * @param {Boolean} delegate whether is delegate or not
+ * @return {UIObject} itself
+ */
+
+
+ UIObject.prototype.setElement = function setElement(element, delegate) {
+ if (this.$el) {
+ this.undelegateEvents();
+ }
+ this.$el = element instanceof _clapprZepto2.default ? element : (0, _clapprZepto2.default)(element);
+ this.el = this.$el[0];
+ if (delegate !== false) {
+ this.delegateEvents();
+ }
+ return this;
+ };
+
+ /**
+ * delegates all the original `events` on `element` to its callbacks
+ * @method delegateEvents
+ * @param {Object} events
+ * @return {UIObject} itself
+ */
+
+
+ UIObject.prototype.delegateEvents = function delegateEvents(events) {
+ if (!(events || (events = (0, _lodash2.default)(this, 'events')))) {
+ return this;
+ }
+ this.undelegateEvents();
+ for (var key in events) {
+ var method = events[key];
+ if (method && method.constructor !== Function) {
+ method = this[events[key]];
+ }
+ if (!method) {
+ continue;
+ }
+
+ var match = key.match(delegateEventSplitter);
+ var eventName = match[1],
+ selector = match[2];
+ //method = _.bind(method, this)
+ eventName += '.delegateEvents' + this.cid;
+ if (selector === '') {
+ this.$el.on(eventName, method.bind(this));
+ } else {
+ this.$el.on(eventName, selector, method.bind(this));
+ }
+ }
+ return this;
+ };
+
+ /**
+ * undelegats all the `events`
+ * @method undelegateEvents
+ * @return {UIObject} itself
+ */
+
+
+ UIObject.prototype.undelegateEvents = function undelegateEvents() {
+ this.$el.off('.delegateEvents' + this.cid);
+ return this;
+ };
+
+ /**
+ * ensures the creation of this ui component
+ * @method _ensureElement
+ * @private
+ */
+
+
+ UIObject.prototype._ensureElement = function _ensureElement() {
+ if (!this.el) {
+ var attrs = _clapprZepto2.default.extend({}, (0, _lodash2.default)(this, 'attributes'));
+ if (this.id) {
+ attrs.id = (0, _lodash2.default)(this, 'id');
+ }
+ if (this.className) {
+ attrs['class'] = (0, _lodash2.default)(this, 'className');
+ }
+ var $el = (0, _clapprZepto2.default)('<' + (0, _lodash2.default)(this, 'tagName') + '>').attr(attrs);
+ this.setElement($el, false);
+ } else {
+ this.setElement((0, _lodash2.default)(this, 'el'), false);
+ }
+ };
+
+ return UIObject;
+ }(_base_object2.default);
+
+ exports.default = UIObject;
+ module.exports = exports['default'];
+
+/***/ },
+/* 19 */
+/***/ function(module, exports) {
+
+ /* WEBPACK VAR INJECTION */(function(global) {/**
+ * lodash (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors <https://jquery.org/>
+ * Released under MIT license <https://lodash.com/license>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+
+ /** Used as the `TypeError` message for "Functions" methods. */
+ var FUNC_ERROR_TEXT = 'Expected a function';
+
+ /** Used to stand-in for `undefined` hash values. */
+ var HASH_UNDEFINED = '__lodash_hash_undefined__';
+
+ /** Used as references for various `Number` constants. */
+ var INFINITY = 1 / 0;
+
+ /** `Object#toString` result references. */
+ var funcTag = '[object Function]',
+ genTag = '[object GeneratorFunction]',
+ symbolTag = '[object Symbol]';
+
+ /** Used to match property names within property paths. */
+ var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
+ reIsPlainProp = /^\w*$/,
+ reLeadingDot = /^\./,
+ rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
+
+ /**
+ * Used to match `RegExp`
+ * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
+ */
+ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
+
+ /** Used to match backslashes in property paths. */
+ var reEscapeChar = /\\(\\)?/g;
+
+ /** Used to detect host constructors (Safari). */
+ var reIsHostCtor = /^\[object .+?Constructor\]$/;
+
+ /** Detect free variable `global` from Node.js. */
+ var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
+
+ /** Detect free variable `self`. */
+ var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
+
+ /** Used as a reference to the global object. */
+ var root = freeGlobal || freeSelf || Function('return this')();
+
+ /**
+ * Gets the value at `key` of `object`.
+ *
+ * @private
+ * @param {Object} [object] The object to query.
+ * @param {string} key The key of the property to get.
+ * @returns {*} Returns the property value.
+ */
+ function getValue(object, key) {
+ return object == null ? undefined : object[key];
+ }
+
+ /**
+ * Checks if `value` is a host object in IE < 9.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
+ */
+ function isHostObject(value) {
+ // Many host objects are `Object` objects that can coerce to strings
+ // despite having improperly defined `toString` methods.
+ var result = false;
+ if (value != null && typeof value.toString != 'function') {
+ try {
+ result = !!(value + '');
+ } catch (e) {}
+ }
+ return result;
+ }
+
+ /** Used for built-in method references. */
+ var arrayProto = Array.prototype,
+ funcProto = Function.prototype,
+ objectProto = Object.prototype;
+
+ /** Used to detect overreaching core-js shims. */
+ var coreJsData = root['__core-js_shared__'];
+
+ /** Used to detect methods masquerading as native. */
+ var maskSrcKey = (function() {
+ var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
+ return uid ? ('Symbol(src)_1.' + uid) : '';
+ }());
+
+ /** Used to resolve the decompiled source of functions. */
+ var funcToString = funcProto.toString;
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+ var objectToString = objectProto.toString;
+
+ /** Used to detect if a method is native. */
+ var reIsNative = RegExp('^' +
+ funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
+ .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+ );
+
+ /** Built-in value references. */
+ var Symbol = root.Symbol,
+ splice = arrayProto.splice;
+
+ /* Built-in method references that are verified to be native. */
+ var Map = getNative(root, 'Map'),
+ nativeCreate = getNative(Object, 'create');
+
+ /** Used to convert symbols to primitives and strings. */
+ var symbolProto = Symbol ? Symbol.prototype : undefined,
+ symbolToString = symbolProto ? symbolProto.toString : undefined;
+
+ /**
+ * Creates a hash object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function Hash(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the hash.
+ *
+ * @private
+ * @name clear
+ * @memberOf Hash
+ */
+ function hashClear() {
+ this.__data__ = nativeCreate ? nativeCreate(null) : {};
+ }
+
+ /**
+ * Removes `key` and its value from the hash.
+ *
+ * @private
+ * @name delete
+ * @memberOf Hash
+ * @param {Object} hash The hash to modify.
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function hashDelete(key) {
+ return this.has(key) && delete this.__data__[key];
+ }
+
+ /**
+ * Gets the hash value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf Hash
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function hashGet(key) {
+ var data = this.__data__;
+ if (nativeCreate) {
+ var result = data[key];
+ return result === HASH_UNDEFINED ? undefined : result;
+ }
+ return hasOwnProperty.call(data, key) ? data[key] : undefined;
+ }
+
+ /**
+ * Checks if a hash value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf Hash
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function hashHas(key) {
+ var data = this.__data__;
+ return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
+ }
+
+ /**
+ * Sets the hash `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf Hash
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the hash instance.
+ */
+ function hashSet(key, value) {
+ var data = this.__data__;
+ data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
+ return this;
+ }
+
+ // Add methods to `Hash`.
+ Hash.prototype.clear = hashClear;
+ Hash.prototype['delete'] = hashDelete;
+ Hash.prototype.get = hashGet;
+ Hash.prototype.has = hashHas;
+ Hash.prototype.set = hashSet;
+
+ /**
+ * Creates an list cache object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function ListCache(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the list cache.
+ *
+ * @private
+ * @name clear
+ * @memberOf ListCache
+ */
+ function listCacheClear() {
+ this.__data__ = [];
+ }
+
+ /**
+ * Removes `key` and its value from the list cache.
+ *
+ * @private
+ * @name delete
+ * @memberOf ListCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function listCacheDelete(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ return false;
+ }
+ var lastIndex = data.length - 1;
+ if (index == lastIndex) {
+ data.pop();
+ } else {
+ splice.call(data, index, 1);
+ }
+ return true;
+ }
+
+ /**
+ * Gets the list cache value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf ListCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function listCacheGet(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ return index < 0 ? undefined : data[index][1];
+ }
+
+ /**
+ * Checks if a list cache value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf ListCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function listCacheHas(key) {
+ return assocIndexOf(this.__data__, key) > -1;
+ }
+
+ /**
+ * Sets the list cache `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf ListCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the list cache instance.
+ */
+ function listCacheSet(key, value) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ data.push([key, value]);
+ } else {
+ data[index][1] = value;
+ }
+ return this;
+ }
+
+ // Add methods to `ListCache`.
+ ListCache.prototype.clear = listCacheClear;
+ ListCache.prototype['delete'] = listCacheDelete;
+ ListCache.prototype.get = listCacheGet;
+ ListCache.prototype.has = listCacheHas;
+ ListCache.prototype.set = listCacheSet;
+
+ /**
+ * Creates a map cache object to store key-value pairs.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function MapCache(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the map.
+ *
+ * @private
+ * @name clear
+ * @memberOf MapCache
+ */
+ function mapCacheClear() {
+ this.__data__ = {
+ 'hash': new Hash,
+ 'map': new (Map || ListCache),
+ 'string': new Hash
+ };
+ }
+
+ /**
+ * Removes `key` and its value from the map.
+ *
+ * @private
+ * @name delete
+ * @memberOf MapCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function mapCacheDelete(key) {
+ return getMapData(this, key)['delete'](key);
+ }
+
+ /**
+ * Gets the map value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf MapCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function mapCacheGet(key) {
+ return getMapData(this, key).get(key);
+ }
+
+ /**
+ * Checks if a map value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf MapCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function mapCacheHas(key) {
+ return getMapData(this, key).has(key);
+ }
+
+ /**
+ * Sets the map `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf MapCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the map cache instance.
+ */
+ function mapCacheSet(key, value) {
+ getMapData(this, key).set(key, value);
+ return this;
+ }
+
+ // Add methods to `MapCache`.
+ MapCache.prototype.clear = mapCacheClear;
+ MapCache.prototype['delete'] = mapCacheDelete;
+ MapCache.prototype.get = mapCacheGet;
+ MapCache.prototype.has = mapCacheHas;
+ MapCache.prototype.set = mapCacheSet;
+
+ /**
+ * Gets the index at which the `key` is found in `array` of key-value pairs.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {*} key The key to search for.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function assocIndexOf(array, key) {
+ var length = array.length;
+ while (length--) {
+ if (eq(array[length][0], key)) {
+ return length;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `_.isNative` without bad shim checks.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function,
+ * else `false`.
+ */
+ function baseIsNative(value) {
+ if (!isObject(value) || isMasked(value)) {
+ return false;
+ }
+ var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;
+ return pattern.test(toSource(value));
+ }
+
+ /**
+ * The base implementation of `_.toString` which doesn't convert nullish
+ * values to empty strings.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {string} Returns the string.
+ */
+ function baseToString(value) {
+ // Exit early for strings to avoid a performance hit in some environments.
+ if (typeof value == 'string') {
+ return value;
+ }
+ if (isSymbol(value)) {
+ return symbolToString ? symbolToString.call(value) : '';
+ }
+ var result = (value + '');
+ return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
+ }
+
+ /**
+ * Casts `value` to a path array if it's not one.
+ *
+ * @private
+ * @param {*} value The value to inspect.
+ * @returns {Array} Returns the cast property path array.
+ */
+ function castPath(value) {
+ return isArray(value) ? value : stringToPath(value);
+ }
+
+ /**
+ * Gets the data for `map`.
+ *
+ * @private
+ * @param {Object} map The map to query.
+ * @param {string} key The reference key.
+ * @returns {*} Returns the map data.
+ */
+ function getMapData(map, key) {
+ var data = map.__data__;
+ return isKeyable(key)
+ ? data[typeof key == 'string' ? 'string' : 'hash']
+ : data.map;
+ }
+
+ /**
+ * Gets the native function at `key` of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the method to get.
+ * @returns {*} Returns the function if it's native, else `undefined`.
+ */
+ function getNative(object, key) {
+ var value = getValue(object, key);
+ return baseIsNative(value) ? value : undefined;
+ }
+
+ /**
+ * Checks if `value` is a property name and not a property path.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {Object} [object] The object to query keys on.
+ * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
+ */
+ function isKey(value, object) {
+ if (isArray(value)) {
+ return false;
+ }
+ var type = typeof value;
+ if (type == 'number' || type == 'symbol' || type == 'boolean' ||
+ value == null || isSymbol(value)) {
+ return true;
+ }
+ return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
+ (object != null && value in Object(object));
+ }
+
+ /**
+ * Checks if `value` is suitable for use as unique object key.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
+ */
+ function isKeyable(value) {
+ var type = typeof value;
+ return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
+ ? (value !== '__proto__')
+ : (value === null);
+ }
+
+ /**
+ * Checks if `func` has its source masked.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` is masked, else `false`.
+ */
+ function isMasked(func) {
+ return !!maskSrcKey && (maskSrcKey in func);
+ }
+
+ /**
+ * Converts `string` to a property path array.
+ *
+ * @private
+ * @param {string} string The string to convert.
+ * @returns {Array} Returns the property path array.
+ */
+ var stringToPath = memoize(function(string) {
+ string = toString(string);
+
+ var result = [];
+ if (reLeadingDot.test(string)) {
+ result.push('');
+ }
+ string.replace(rePropName, function(match, number, quote, string) {
+ result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
+ });
+ return result;
+ });
+
+ /**
+ * Converts `value` to a string key if it's not a string or symbol.
+ *
+ * @private
+ * @param {*} value The value to inspect.
+ * @returns {string|symbol} Returns the key.
+ */
+ function toKey(value) {
+ if (typeof value == 'string' || isSymbol(value)) {
+ return value;
+ }
+ var result = (value + '');
+ return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
+ }
+
+ /**
+ * Converts `func` to its source code.
+ *
+ * @private
+ * @param {Function} func The function to process.
+ * @returns {string} Returns the source code.
+ */
+ function toSource(func) {
+ if (func != null) {
+ try {
+ return funcToString.call(func);
+ } catch (e) {}
+ try {
+ return (func + '');
+ } catch (e) {}
+ }
+ return '';
+ }
+
+ /**
+ * Creates a function that memoizes the result of `func`. If `resolver` is
+ * provided, it determines the cache key for storing the result based on the
+ * arguments provided to the memoized function. By default, the first argument
+ * provided to the memoized function is used as the map cache key. The `func`
+ * is invoked with the `this` binding of the memoized function.
+ *
+ * **Note:** The cache is exposed as the `cache` property on the memoized
+ * function. Its creation may be customized by replacing the `_.memoize.Cache`
+ * constructor with one whose instances implement the
+ * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
+ * method interface of `delete`, `get`, `has`, and `set`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to have its output memoized.
+ * @param {Function} [resolver] The function to resolve the cache key.
+ * @returns {Function} Returns the new memoized function.
+ * @example
+ *
+ * var object = { 'a': 1, 'b': 2 };
+ * var other = { 'c': 3, 'd': 4 };
+ *
+ * var values = _.memoize(_.values);
+ * values(object);
+ * // => [1, 2]
+ *
+ * values(other);
+ * // => [3, 4]
+ *
+ * object.a = 2;
+ * values(object);
+ * // => [1, 2]
+ *
+ * // Modify the result cache.
+ * values.cache.set(object, ['a', 'b']);
+ * values(object);
+ * // => ['a', 'b']
+ *
+ * // Replace `_.memoize.Cache`.
+ * _.memoize.Cache = WeakMap;
+ */
+ function memoize(func, resolver) {
+ if (typeof func != 'function' || (resolver && typeof resolver != 'function')) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var memoized = function() {
+ var args = arguments,
+ key = resolver ? resolver.apply(this, args) : args[0],
+ cache = memoized.cache;
+
+ if (cache.has(key)) {
+ return cache.get(key);
+ }
+ var result = func.apply(this, args);
+ memoized.cache = cache.set(key, result);
+ return result;
+ };
+ memoized.cache = new (memoize.Cache || MapCache);
+ return memoized;
+ }
+
+ // Assign cache to `_.memoize`.
+ memoize.Cache = MapCache;
+
+ /**
+ * Performs a
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * comparison between two values to determine if they are equivalent.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'a': 1 };
+ * var other = { 'a': 1 };
+ *
+ * _.eq(object, object);
+ * // => true
+ *
+ * _.eq(object, other);
+ * // => false
+ *
+ * _.eq('a', 'a');
+ * // => true
+ *
+ * _.eq('a', Object('a'));
+ * // => false
+ *
+ * _.eq(NaN, NaN);
+ * // => true
+ */
+ function eq(value, other) {
+ return value === other || (value !== value && other !== other);
+ }
+
+ /**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * _.isArray(document.body.children);
+ * // => false
+ *
+ * _.isArray('abc');
+ * // => false
+ *
+ * _.isArray(_.noop);
+ * // => false
+ */
+ var isArray = Array.isArray;
+
+ /**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a function, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+ function isFunction(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in Safari 8-9 which returns 'object' for typed array and other constructors.
+ var tag = isObject(value) ? objectToString.call(value) : '';
+ return tag == funcTag || tag == genTag;
+ }
+
+ /**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+ function isObject(value) {
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+ }
+
+ /**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+ function isObjectLike(value) {
+ return !!value && typeof value == 'object';
+ }
+
+ /**
+ * Checks if `value` is classified as a `Symbol` primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
+ * @example
+ *
+ * _.isSymbol(Symbol.iterator);
+ * // => true
+ *
+ * _.isSymbol('abc');
+ * // => false
+ */
+ function isSymbol(value) {
+ return typeof value == 'symbol' ||
+ (isObjectLike(value) && objectToString.call(value) == symbolTag);
+ }
+
+ /**
+ * Converts `value` to a string. An empty string is returned for `null`
+ * and `undefined` values. The sign of `-0` is preserved.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to process.
+ * @returns {string} Returns the string.
+ * @example
+ *
+ * _.toString(null);
+ * // => ''
+ *
+ * _.toString(-0);
+ * // => '-0'
+ *
+ * _.toString([1, 2, 3]);
+ * // => '1,2,3'
+ */
+ function toString(value) {
+ return value == null ? '' : baseToString(value);
+ }
+
+ /**
+ * This method is like `_.get` except that if the resolved value is a
+ * function it's invoked with the `this` binding of its parent object and
+ * its result is returned.
+ *
+ * @static
+ * @since 0.1.0
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path of the property to resolve.
+ * @param {*} [defaultValue] The value returned for `undefined` resolved values.
+ * @returns {*} Returns the resolved value.
+ * @example
+ *
+ * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
+ *
+ * _.result(object, 'a[0].b.c1');
+ * // => 3
+ *
+ * _.result(object, 'a[0].b.c2');
+ * // => 4
+ *
+ * _.result(object, 'a[0].b.c3', 'default');
+ * // => 'default'
+ *
+ * _.result(object, 'a[0].b.c3', _.constant('default'));
+ * // => 'default'
+ */
+ function result(object, path, defaultValue) {
+ path = isKey(path, object) ? [path] : castPath(path);
+
+ var index = -1,
+ length = path.length;
+
+ // Ensure the loop is entered when path is empty.
+ if (!length) {
+ object = undefined;
+ length = 1;
+ }
+ while (++index < length) {
+ var value = object == null ? undefined : object[toKey(path[index])];
+ if (value === undefined) {
+ index = length;
+ value = defaultValue;
+ }
+ object = isFunction(value) ? value.call(object) : value;
+ }
+ return object;
+ }
+
+ module.exports = result;
+
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
+
+/***/ },
+/* 20 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(21);
+
+/***/ },
+/* 21 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _base_object = __webpack_require__(4);
+
+ var _base_object2 = _interopRequireDefault(_base_object);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _container = __webpack_require__(22);
+
+ var _container2 = _interopRequireDefault(_container);
+
+ var _clapprZepto = __webpack_require__(16);
+
+ var _clapprZepto2 = _interopRequireDefault(_clapprZepto);
+
+ var _lodash = __webpack_require__(26);
+
+ var _lodash2 = _interopRequireDefault(_lodash);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ /**
+ * The ContainerFactory is responsible for manage playback bootstrap and create containers.
+ */
+
+ var ContainerFactory = function (_BaseObject) {
+ _inherits(ContainerFactory, _BaseObject);
+
+ _createClass(ContainerFactory, [{
+ key: 'options',
+ get: function get() {
+ return this._options;
+ },
+ set: function set(options) {
+ this._options = options;
+ }
+ }]);
+
+ function ContainerFactory(options, loader, i18n) {
+ _classCallCheck(this, ContainerFactory);
+
+ var _this = _possibleConstructorReturn(this, _BaseObject.call(this, options));
+
+ _this._i18n = i18n;
+ _this.loader = loader;
+ return _this;
+ }
+
+ ContainerFactory.prototype.createContainers = function createContainers() {
+ var _this2 = this;
+
+ return _clapprZepto2.default.Deferred(function (promise) {
+ promise.resolve(_this2.options.sources.map(function (source) {
+ return _this2.createContainer(source);
+ }));
+ });
+ };
+
+ ContainerFactory.prototype.findPlaybackPlugin = function findPlaybackPlugin(source, mimeType) {
+ return this.loader.playbackPlugins.filter(function (p) {
+ return p.canPlay(source, mimeType);
+ })[0];
+ };
+
+ ContainerFactory.prototype.createContainer = function createContainer(source) {
+ var resolvedSource = null,
+ mimeType = this.options.mimeType;
+ if ((0, _lodash2.default)(source)) {
+ resolvedSource = source.source.toString();
+ if (source.mimeType) {
+ mimeType = source.mimeType;
+ }
+ } else {
+ resolvedSource = source.toString();
+ }
+
+ if (resolvedSource.match(/^\/\//)) resolvedSource = window.location.protocol + resolvedSource;
+
+ var options = _clapprZepto2.default.extend({}, this.options, {
+ src: resolvedSource,
+ mimeType: mimeType
+ });
+ var playbackPlugin = this.findPlaybackPlugin(resolvedSource, mimeType);
+ var playback = new playbackPlugin(options, this._i18n);
+
+ options = _clapprZepto2.default.extend({}, options, { playback: playback });
+
+ var container = new _container2.default(options, this._i18n);
+ var defer = _clapprZepto2.default.Deferred();
+ defer.promise(container);
+ this.addContainerPlugins(container);
+ this.listenToOnce(container, _events2.default.CONTAINER_READY, function () {
+ return defer.resolve(container);
+ });
+ return container;
+ };
+
+ ContainerFactory.prototype.addContainerPlugins = function addContainerPlugins(container) {
+ this.loader.containerPlugins.forEach(function (Plugin) {
+ container.addPlugin(new Plugin(container));
+ });
+ };
+
+ return ContainerFactory;
+ }(_base_object2.default);
+
+ exports.default = ContainerFactory;
+ module.exports = exports['default'];
+
+/***/ },
+/* 22 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(23);
+
+/***/ },
+/* 23 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _ui_object = __webpack_require__(18);
+
+ var _ui_object2 = _interopRequireDefault(_ui_object);
+
+ var _styler = __webpack_require__(15);
+
+ var _styler2 = _interopRequireDefault(_styler);
+
+ var _style = __webpack_require__(24);
+
+ var _style2 = _interopRequireDefault(_style);
+
+ var _clapprZepto = __webpack_require__(16);
+
+ var _clapprZepto2 = _interopRequireDefault(_clapprZepto);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ /**
+ * Container is responsible for the video rendering and state
+ */
+
+ /**
+ * An abstraction to represent a container for a given playback
+ * TODO: describe its responsabilities
+ * @class Container
+ * @constructor
+ * @extends UIObject
+ * @module base
+ */
+ var Container = function (_UIObject) {
+ _inherits(Container, _UIObject);
+
+ _createClass(Container, [{
+ key: 'name',
+
+ /**
+ * container's name
+ * @method name
+ * @default Container
+ * @return {String} container's name
+ */
+ get: function get() {
+ return 'Container';
+ }
+ }, {
+ key: 'attributes',
+ get: function get() {
+ return { class: 'container', 'data-container': '' };
+ }
+ }, {
+ key: 'events',
+ get: function get() {
+ return {
+ 'click': 'clicked',
+ 'dblclick': 'dblClicked',
+ 'doubleTap': 'dblClicked',
+ 'contextmenu': 'onContextMenu',
+ 'mouseenter': 'mouseEnter',
+ 'mouseleave': 'mouseLeave'
+ };
+ }
+
+ /**
+ * Determine if the playback has ended.
+ * @property ended
+ * @type Boolean
+ */
+
+ }, {
+ key: 'ended',
+ get: function get() {
+ return this.playback.ended;
+ }
+
+ /**
+ * Determine if the playback is having to buffer in order for
+ * playback to be smooth.
+ * (i.e if a live stream is playing smoothly, this will be false)
+ * @property buffering
+ * @type Boolean
+ */
+
+ }, {
+ key: 'buffering',
+ get: function get() {
+ return this.playback.buffering;
+ }
+
+ /**
+ * The internationalization plugin.
+ * @property i18n
+ * @type {Strings}
+ */
+
+ }, {
+ key: 'i18n',
+ get: function get() {
+ return this._i18n;
+ }
+
+ /**
+ * it builds a container
+ * @method constructor
+ * @param {Object} options the options object
+ * @param {Strings} i18n the internationalization component
+ */
+
+ }]);
+
+ function Container(options, i18n) {
+ _classCallCheck(this, Container);
+
+ var _this = _possibleConstructorReturn(this, _UIObject.call(this, options));
+
+ _this._i18n = i18n;
+ _this.currentTime = 0;
+ _this.volume = 100;
+ _this.playback = options.playback;
+ _this.settings = _clapprZepto2.default.extend({}, _this.playback.settings);
+ _this.isReady = false;
+ _this.mediaControlDisabled = false;
+ _this.plugins = [_this.playback];
+ _this.bindEvents();
+ return _this;
+ }
+
+ /**
+ * binds playback events to the methods of the container.
+ * it listens to playback's events and triggers them as container events.
+ *
+ * | Playback |
+ * |----------|
+ * | progress |
+ * | timeupdate |
+ * | ready |
+ * | buffering |
+ * | bufferfull |
+ * | settingsupdate |
+ * | loadedmetadata |
+ * | highdefinitionupdate |
+ * | bitrate |
+ * | playbackstate |
+ * | dvr |
+ * | mediacontrol_disable |
+ * | mediacontrol_enable |
+ * | ended |
+ * | play |
+ * | pause |
+ * | error |
+ *
+ * ps: the events usually translate from PLABACK_x to CONTAINER_x, you can check all the events at `Event` class.
+ *
+ * @method bindEvents
+ */
+
+
+ Container.prototype.bindEvents = function bindEvents() {
+ this.listenTo(this.playback, _events2.default.PLAYBACK_PROGRESS, this.progress);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_TIMEUPDATE, this.timeUpdated);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_READY, this.ready);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_BUFFERING, this.onBuffering);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_BUFFERFULL, this.bufferfull);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_SETTINGSUPDATE, this.settingsUpdate);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_LOADEDMETADATA, this.loadedMetadata);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_HIGHDEFINITIONUPDATE, this.highDefinitionUpdate);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_BITRATE, this.updateBitrate);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_PLAYBACKSTATE, this.playbackStateChanged);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_DVR, this.playbackDvrStateChanged);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_MEDIACONTROL_DISABLE, this.disableMediaControl);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_MEDIACONTROL_ENABLE, this.enableMediaControl);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_ENDED, this.onEnded);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_PLAY, this.playing);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_PAUSE, this.paused);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_STOP, this.stopped);
+ this.listenTo(this.playback, _events2.default.PLAYBACK_ERROR, this.error);
+ };
+
+ Container.prototype.playbackStateChanged = function playbackStateChanged(state) {
+ this.trigger(_events2.default.CONTAINER_PLAYBACKSTATE, state);
+ };
+
+ Container.prototype.playbackDvrStateChanged = function playbackDvrStateChanged(dvrInUse) {
+ this.settings = this.playback.settings;
+ this.dvrInUse = dvrInUse;
+ this.trigger(_events2.default.CONTAINER_PLAYBACKDVRSTATECHANGED, dvrInUse);
+ };
+
+ Container.prototype.updateBitrate = function updateBitrate(newBitrate) {
+ this.trigger(_events2.default.CONTAINER_BITRATE, newBitrate);
+ };
+
+ Container.prototype.statsReport = function statsReport(metrics) {
+ this.trigger(_events2.default.CONTAINER_STATS_REPORT, metrics);
+ };
+
+ Container.prototype.getPlaybackType = function getPlaybackType() {
+ return this.playback.getPlaybackType();
+ };
+
+ /**
+ * returns `true` if DVR is enable otherwise `false`.
+ * @method isDvrEnabled
+ * @return {Boolean}
+ */
+
+
+ Container.prototype.isDvrEnabled = function isDvrEnabled() {
+ return !!this.playback.dvrEnabled;
+ };
+
+ /**
+ * returns `true` if DVR is in use otherwise `false`.
+ * @method isDvrInUse
+ * @return {Boolean}
+ */
+
+
+ Container.prototype.isDvrInUse = function isDvrInUse() {
+ return !!this.dvrInUse;
+ };
+
+ /**
+ * destroys the container
+ * @method destroy
+ */
+
+
+ Container.prototype.destroy = function destroy() {
+ this.trigger(_events2.default.CONTAINER_DESTROYED, this, this.name);
+ this.stopListening();
+ this.plugins.forEach(function (plugin) {
+ return plugin.destroy();
+ });
+ this.$el.remove();
+ };
+
+ Container.prototype.setStyle = function setStyle(style) {
+ this.$el.css(style);
+ };
+
+ Container.prototype.animate = function animate(style, duration) {
+ return this.$el.animate(style, duration).promise();
+ };
+
+ Container.prototype.ready = function ready() {
+ this.isReady = true;
+ this.trigger(_events2.default.CONTAINER_READY, this.name);
+ };
+
+ Container.prototype.isPlaying = function isPlaying() {
+ return this.playback.isPlaying();
+ };
+
+ Container.prototype.getStartTimeOffset = function getStartTimeOffset() {
+ return this.playback.getStartTimeOffset();
+ };
+
+ Container.prototype.getCurrentTime = function getCurrentTime() {
+ return this.currentTime;
+ };
+
+ Container.prototype.getDuration = function getDuration() {
+ return this.playback.getDuration();
+ };
+
+ Container.prototype.error = function error(errorObj) {
+ if (!this.isReady) {
+ this.ready();
+ }
+ this.trigger(_events2.default.CONTAINER_ERROR, { error: errorObj, container: this }, this.name);
+ };
+
+ Container.prototype.loadedMetadata = function loadedMetadata(metadata) {
+ this.trigger(_events2.default.CONTAINER_LOADEDMETADATA, metadata);
+ };
+
+ Container.prototype.timeUpdated = function timeUpdated(timeProgress) {
+ this.currentTime = timeProgress.current;
+ this.trigger(_events2.default.CONTAINER_TIMEUPDATE, timeProgress, this.name);
+ };
+
+ Container.prototype.progress = function progress() {
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ this.trigger.apply(this, [_events2.default.CONTAINER_PROGRESS].concat(args, [this.name]));
+ };
+
+ Container.prototype.playing = function playing() {
+ this.trigger(_events2.default.CONTAINER_PLAY, this.name);
+ };
+
+ Container.prototype.paused = function paused() {
+ this.trigger(_events2.default.CONTAINER_PAUSE, this.name);
+ };
+
+ /**
+ * plays the playback
+ * @method play
+ */
+
+
+ Container.prototype.play = function play() {
+ this.playback.play();
+ };
+
+ /**
+ * stops the playback
+ * @method stop
+ */
+
+
+ Container.prototype.stop = function stop() {
+ this.playback.stop();
+ this.currentTime = 0;
+ };
+
+ /**
+ * pauses the playback
+ * @method pause
+ */
+
+
+ Container.prototype.pause = function pause() {
+ this.playback.pause();
+ };
+
+ Container.prototype.onEnded = function onEnded() {
+ this.trigger(_events2.default.CONTAINER_ENDED, this, this.name);
+ this.currentTime = 0;
+ };
+
+ Container.prototype.stopped = function stopped() {
+ this.trigger(_events2.default.CONTAINER_STOP);
+ };
+
+ Container.prototype.clicked = function clicked() {
+ if (!this.options.chromeless || this.options.allowUserInteraction) {
+ this.trigger(_events2.default.CONTAINER_CLICK, this, this.name);
+ }
+ };
+
+ Container.prototype.dblClicked = function dblClicked() {
+ if (!this.options.chromeless || this.options.allowUserInteraction) {
+ this.trigger(_events2.default.CONTAINER_DBLCLICK, this, this.name);
+ }
+ };
+
+ Container.prototype.onContextMenu = function onContextMenu() {
+ if (!this.options.chromeless || this.options.allowUserInteraction) {
+ this.trigger(_events2.default.CONTAINER_CONTEXTMENU, this, this.name);
+ }
+ };
+
+ Container.prototype.seek = function seek(time) {
+ this.trigger(_events2.default.CONTAINER_SEEK, time, this.name);
+ this.playback.seek(time);
+ };
+
+ Container.prototype.seekPercentage = function seekPercentage(percentage) {
+ var duration = this.getDuration();
+ if (percentage >= 0 && percentage <= 100) {
+ var time = duration * (percentage / 100);
+ this.seek(time);
+ }
+ };
+
+ Container.prototype.setVolume = function setVolume(value) {
+ this.volume = parseInt(value, 10);
+ this.trigger(_events2.default.CONTAINER_VOLUME, value, this.name);
+ this.playback.volume(value);
+ };
+
+ Container.prototype.fullscreen = function fullscreen() {
+ this.trigger(_events2.default.CONTAINER_FULLSCREEN, this.name);
+ };
+
+ Container.prototype.onBuffering = function onBuffering() {
+ this.trigger(_events2.default.CONTAINER_STATE_BUFFERING, this.name);
+ };
+
+ Container.prototype.bufferfull = function bufferfull() {
+ this.trigger(_events2.default.CONTAINER_STATE_BUFFERFULL, this.name);
+ };
+
+ /**
+ * adds plugin to the container
+ * @method addPlugin
+ * @param {Object} plugin
+ */
+
+
+ Container.prototype.addPlugin = function addPlugin(plugin) {
+ this.plugins.push(plugin);
+ };
+
+ /**
+ * checks if a plugin, given its name, exist
+ * @method hasPlugin
+ * @param {String} name
+ * @return {Boolean}
+ */
+
+
+ Container.prototype.hasPlugin = function hasPlugin(name) {
+ return !!this.getPlugin(name);
+ };
+
+ /**
+ * get the plugin given its name
+ * @method getPlugin
+ * @param {String} name
+ */
+
+
+ Container.prototype.getPlugin = function getPlugin(name) {
+ return this.plugins.filter(function (plugin) {
+ return plugin.name === name;
+ })[0];
+ };
+
+ Container.prototype.mouseEnter = function mouseEnter() {
+ if (!this.options.chromeless || this.options.allowUserInteraction) {
+ this.trigger(_events2.default.CONTAINER_MOUSE_ENTER);
+ }
+ };
+
+ Container.prototype.mouseLeave = function mouseLeave() {
+ if (!this.options.chromeless || this.options.allowUserInteraction) {
+ this.trigger(_events2.default.CONTAINER_MOUSE_LEAVE);
+ }
+ };
+
+ Container.prototype.settingsUpdate = function settingsUpdate() {
+ this.settings = this.playback.settings;
+ this.trigger(_events2.default.CONTAINER_SETTINGSUPDATE);
+ };
+
+ Container.prototype.highDefinitionUpdate = function highDefinitionUpdate(isHD) {
+ this.trigger(_events2.default.CONTAINER_HIGHDEFINITIONUPDATE, isHD);
+ };
+
+ Container.prototype.isHighDefinitionInUse = function isHighDefinitionInUse() {
+ return this.playback.isHighDefinitionInUse();
+ };
+
+ Container.prototype.disableMediaControl = function disableMediaControl() {
+ if (!this.mediaControlDisabled) {
+ this.mediaControlDisabled = true;
+ this.trigger(_events2.default.CONTAINER_MEDIACONTROL_DISABLE);
+ }
+ };
+
+ Container.prototype.enableMediaControl = function enableMediaControl() {
+ if (this.mediaControlDisabled) {
+ this.mediaControlDisabled = false;
+ this.trigger(_events2.default.CONTAINER_MEDIACONTROL_ENABLE);
+ }
+ };
+
+ Container.prototype.updateStyle = function updateStyle() {
+ if (!this.options.chromeless || this.options.allowUserInteraction) {
+ this.$el.removeClass('chromeless');
+ } else {
+ this.$el.addClass('chromeless');
+ }
+ };
+
+ /**
+ * enables to configure the container after its creation
+ * @method configure
+ * @param {Object} options all the options to change in form of a javascript object
+ */
+
+
+ Container.prototype.configure = function configure(options) {
+ this._options = _clapprZepto2.default.extend(this._options, options);
+ this.updateStyle();
+ this.trigger(_events2.default.CONTAINER_OPTIONS_CHANGE);
+ };
+
+ Container.prototype.render = function render() {
+ var s = _styler2.default.getStyleFor(_style2.default);
+ this.$el.append(s);
+ this.$el.append(this.playback.render().el);
+ this.updateStyle();
+ return this;
+ };
+
+ return Container;
+ }(_ui_object2.default);
+
+ exports.default = Container;
+ module.exports = exports['default'];
+
+/***/ },
+/* 24 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(25)();
+ // imports
+
+
+ // module
+ exports.push([module.id, ".container[data-container] {\n position: absolute;\n background-color: black;\n height: 100%;\n width: 100%; }\n .container[data-container] .chromeless {\n cursor: default; }\n\n[data-player]:not(.nocursor) .container[data-container]:not(.chromeless).pointer-enabled {\n cursor: pointer; }\n", ""]);
+
+ // exports
+
+
+/***/ },
+/* 25 */
+/***/ function(module, exports) {
+
+ /*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+ */
+ // css base code, injected by the css-loader
+ module.exports = function() {
+ var list = [];
+
+ // return the list of modules as css string
+ list.toString = function toString() {
+ var result = [];
+ for(var i = 0; i < this.length; i++) {
+ var item = this[i];
+ if(item[2]) {
+ result.push("@media " + item[2] + "{" + item[1] + "}");
+ } else {
+ result.push(item[1]);
+ }
+ }
+ return result.join("");
+ };
+
+ // import a list of modules into the list
+ list.i = function(modules, mediaQuery) {
+ if(typeof modules === "string")
+ modules = [[null, modules, ""]];
+ var alreadyImportedModules = {};
+ for(var i = 0; i < this.length; i++) {
+ var id = this[i][0];
+ if(typeof id === "number")
+ alreadyImportedModules[id] = true;
+ }
+ for(i = 0; i < modules.length; i++) {
+ var item = modules[i];
+ // skip already imported module
+ // this implementation is not 100% perfect for weird media query combinations
+ // when a module is imported multiple times with different media queries.
+ // I hope this will never occur (Hey this way we have smaller bundles)
+ if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) {
+ if(mediaQuery && !item[2]) {
+ item[2] = mediaQuery;
+ } else if(mediaQuery) {
+ item[2] = "(" + item[2] + ") and (" + mediaQuery + ")";
+ }
+ list.push(item);
+ }
+ }
+ };
+ return list;
+ };
+
+
+/***/ },
+/* 26 */
+/***/ function(module, exports) {
+
+ /**
+ * lodash (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors <https://jquery.org/>
+ * Released under MIT license <https://lodash.com/license>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+
+ /** `Object#toString` result references. */
+ var objectTag = '[object Object]';
+
+ /**
+ * Checks if `value` is a host object in IE < 9.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
+ */
+ function isHostObject(value) {
+ // Many host objects are `Object` objects that can coerce to strings
+ // despite having improperly defined `toString` methods.
+ var result = false;
+ if (value != null && typeof value.toString != 'function') {
+ try {
+ result = !!(value + '');
+ } catch (e) {}
+ }
+ return result;
+ }
+
+ /**
+ * Creates a unary function that invokes `func` with its argument transformed.
+ *
+ * @private
+ * @param {Function} func The function to wrap.
+ * @param {Function} transform The argument transform.
+ * @returns {Function} Returns the new function.
+ */
+ function overArg(func, transform) {
+ return function(arg) {
+ return func(transform(arg));
+ };
+ }
+
+ /** Used for built-in method references. */
+ var funcProto = Function.prototype,
+ objectProto = Object.prototype;
+
+ /** Used to resolve the decompiled source of functions. */
+ var funcToString = funcProto.toString;
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /** Used to infer the `Object` constructor. */
+ var objectCtorString = funcToString.call(Object);
+
+ /**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+ var objectToString = objectProto.toString;
+
+ /** Built-in value references. */
+ var getPrototype = overArg(Object.getPrototypeOf, Object);
+
+ /**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+ function isObjectLike(value) {
+ return !!value && typeof value == 'object';
+ }
+
+ /**
+ * Checks if `value` is a plain object, that is, an object created by the
+ * `Object` constructor or one with a `[[Prototype]]` of `null`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.8.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * }
+ *
+ * _.isPlainObject(new Foo);
+ * // => false
+ *
+ * _.isPlainObject([1, 2, 3]);
+ * // => false
+ *
+ * _.isPlainObject({ 'x': 0, 'y': 0 });
+ * // => true
+ *
+ * _.isPlainObject(Object.create(null));
+ * // => true
+ */
+ function isPlainObject(value) {
+ if (!isObjectLike(value) ||
+ objectToString.call(value) != objectTag || isHostObject(value)) {
+ return false;
+ }
+ var proto = getPrototype(value);
+ if (proto === null) {
+ return true;
+ }
+ var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
+ return (typeof Ctor == 'function' &&
+ Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString);
+ }
+
+ module.exports = isPlainObject;
+
+
+/***/ },
+/* 27 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(28);
+
+/***/ },
+/* 28 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /* WEBPACK VAR INJECTION */(function(process) {'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _utils = __webpack_require__(2);
+
+ var _vendor = __webpack_require__(8);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _styler = __webpack_require__(15);
+
+ var _styler2 = _interopRequireDefault(_styler);
+
+ var _ui_object = __webpack_require__(18);
+
+ var _ui_object2 = _interopRequireDefault(_ui_object);
+
+ var _browser = __webpack_require__(3);
+
+ var _browser2 = _interopRequireDefault(_browser);
+
+ var _mediator = __webpack_require__(30);
+
+ var _mediator2 = _interopRequireDefault(_mediator);
+
+ var _template = __webpack_require__(17);
+
+ var _template2 = _interopRequireDefault(_template);
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ var _clapprZepto = __webpack_require__(16);
+
+ var _clapprZepto2 = _interopRequireDefault(_clapprZepto);
+
+ var _lodash = __webpack_require__(32);
+
+ var _lodash2 = _interopRequireDefault(_lodash);
+
+ var _mediaControl = __webpack_require__(34);
+
+ var _mediaControl2 = _interopRequireDefault(_mediaControl);
+
+ var _mediaControl3 = __webpack_require__(36);
+
+ var _mediaControl4 = _interopRequireDefault(_mediaControl3);
+
+ var _play = __webpack_require__(37);
+
+ var _play2 = _interopRequireDefault(_play);
+
+ var _pause = __webpack_require__(38);
+
+ var _pause2 = _interopRequireDefault(_pause);
+
+ var _stop = __webpack_require__(39);
+
+ var _stop2 = _interopRequireDefault(_stop);
+
+ var _volume = __webpack_require__(40);
+
+ var _volume2 = _interopRequireDefault(_volume);
+
+ var _mute = __webpack_require__(41);
+
+ var _mute2 = _interopRequireDefault(_mute);
+
+ var _expand = __webpack_require__(42);
+
+ var _expand2 = _interopRequireDefault(_expand);
+
+ var _shrink = __webpack_require__(43);
+
+ var _shrink2 = _interopRequireDefault(_shrink);
+
+ var _hd = __webpack_require__(44);
+
+ var _hd2 = _interopRequireDefault(_hd);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ /**
+ * The MediaControl is responsible for displaying the Player controls.
+ */
+
+ var MediaControl = function (_UIObject) {
+ _inherits(MediaControl, _UIObject);
+
+ _createClass(MediaControl, [{
+ key: 'name',
+ get: function get() {
+ return 'MediaControl';
+ }
+ }, {
+ key: 'disabled',
+ get: function get() {
+ return this.userDisabled || this.container && this.container.getPlaybackType() === _playback2.default.NO_OP;
+ }
+ }, {
+ key: 'attributes',
+ get: function get() {
+ return {
+ 'class': 'media-control',
+ 'data-media-control': ''
+ };
+ }
+ }, {
+ key: 'events',
+ get: function get() {
+ return {
+ 'click [data-play]': 'play',
+ 'click [data-pause]': 'pause',
+ 'click [data-playpause]': 'togglePlayPause',
+ 'click [data-stop]': 'stop',
+ 'click [data-playstop]': 'togglePlayStop',
+ 'click [data-fullscreen]': 'toggleFullscreen',
+ 'click .bar-container[data-seekbar]': 'seek',
+ 'click .bar-container[data-volume]': 'onVolumeClick',
+ 'click .drawer-icon[data-volume]': 'toggleMute',
+ 'mouseenter .drawer-container[data-volume]': 'showVolumeBar',
+ 'mouseleave .drawer-container[data-volume]': 'hideVolumeBar',
+ 'mousedown .bar-container[data-volume]': 'startVolumeDrag',
+ 'mousemove .bar-container[data-volume]': 'mousemoveOnVolumeBar',
+ 'mousedown .bar-scrubber[data-seekbar]': 'startSeekDrag',
+ 'mousemove .bar-container[data-seekbar]': 'mousemoveOnSeekBar',
+ 'mouseleave .bar-container[data-seekbar]': 'mouseleaveOnSeekBar',
+ 'mouseenter .media-control-layer[data-controls]': 'setUserKeepVisible',
+ 'mouseleave .media-control-layer[data-controls]': 'resetUserKeepVisible'
+ };
+ }
+ }, {
+ key: 'template',
+ get: function get() {
+ return (0, _template2.default)(_mediaControl4.default);
+ }
+ }, {
+ key: 'stylesheet',
+ get: function get() {
+ return _styler2.default.getStyleFor(_mediaControl2.default, { baseUrl: this.options.baseUrl });
+ }
+ }, {
+ key: 'volume',
+ get: function get() {
+ return this.container && this.container.isReady ? this.container.volume : this.intendedVolume;
+ }
+ }, {
+ key: 'muted',
+ get: function get() {
+ return this.volume === 0;
+ }
+ }]);
+
+ function MediaControl(options) {
+ _classCallCheck(this, MediaControl);
+
+ var _this = _possibleConstructorReturn(this, _UIObject.call(this, options));
+
+ _this.persistConfig = _this.options.persistConfig;
+ _this.container = options.container;
+ _this.currentPositionValue = null;
+ _this.currentDurationValue = null;
+ var initialVolume = _this.persistConfig ? _utils.Config.restore('volume') : 100;
+ _this.setVolume(_this.options.mute ? 0 : initialVolume);
+ _this.keepVisible = false;
+ _this.fullScreenOnVideoTagSupported = null; // unknown
+ _this.addEventListeners();
+ _this.settings = {
+ left: ['play', 'stop', 'pause'],
+ right: ['volume'],
+ default: ['position', 'seekbar', 'duration']
+ };
+
+ if (_this.container) {
+ if (!_clapprZepto2.default.isEmptyObject(_this.container.settings)) {
+ _this.settings = _clapprZepto2.default.extend({}, _this.container.settings);
+ }
+ } else {
+ _this.settings = {};
+ }
+
+ _this.userDisabled = false;
+ if (_this.container && _this.container.mediaControlDisabled || _this.options.chromeless) {
+ _this.disable();
+ }
+ _this.stopDragHandler = function (event) {
+ return _this.stopDrag(event);
+ };
+ _this.updateDragHandler = function (event) {
+ return _this.updateDrag(event);
+ };
+ (0, _clapprZepto2.default)(document).bind('mouseup', _this.stopDragHandler);
+ (0, _clapprZepto2.default)(document).bind('mousemove', _this.updateDragHandler);
+ return _this;
+ }
+
+ MediaControl.prototype.addEventListeners = function addEventListeners() {
+ if (this.container) {
+ _mediator2.default.on(this.options.playerId + ':' + _events2.default.PLAYER_RESIZE, this.playerResize, this);
+ this.listenTo(this.container, _events2.default.CONTAINER_PLAY, this.changeTogglePlay);
+ this.listenTo(this.container, _events2.default.CONTAINER_PAUSE, this.changeTogglePlay);
+ this.listenTo(this.container, _events2.default.CONTAINER_DBLCLICK, this.toggleFullscreen);
+ this.listenTo(this.container, _events2.default.CONTAINER_TIMEUPDATE, this.onTimeUpdate);
+ this.listenTo(this.container, _events2.default.CONTAINER_PROGRESS, this.updateProgressBar);
+ this.listenTo(this.container, _events2.default.CONTAINER_SETTINGSUPDATE, this.settingsUpdate);
+ this.listenTo(this.container, _events2.default.CONTAINER_PLAYBACKDVRSTATECHANGED, this.settingsUpdate);
+ this.listenTo(this.container, _events2.default.CONTAINER_HIGHDEFINITIONUPDATE, this.highDefinitionUpdate);
+ this.listenTo(this.container, _events2.default.CONTAINER_MEDIACONTROL_DISABLE, this.disable);
+ this.listenTo(this.container, _events2.default.CONTAINER_MEDIACONTROL_ENABLE, this.enable);
+ this.listenTo(this.container, _events2.default.CONTAINER_ENDED, this.ended);
+ this.listenTo(this.container, _events2.default.CONTAINER_VOLUME, this.onVolumeChanged);
+ if (this.container.playback.el.nodeName.toLowerCase() === 'video') {
+ // wait until the metadata has loaded and then check if fullscreen on video tag is supported
+ this.listenToOnce(this.container, _events2.default.CONTAINER_LOADEDMETADATA, this.onLoadedMetadataOnVideoTag);
+ }
+ }
+ };
+
+ MediaControl.prototype.disable = function disable() {
+ this.userDisabled = true;
+ this.hide();
+ this.$el.hide();
+ };
+
+ MediaControl.prototype.enable = function enable() {
+ if (this.options.chromeless) return;
+ this.userDisabled = false;
+ this.show();
+ };
+
+ MediaControl.prototype.play = function play() {
+ this.container.play();
+ };
+
+ MediaControl.prototype.pause = function pause() {
+ this.container.pause();
+ };
+
+ MediaControl.prototype.stop = function stop() {
+ this.container.stop();
+ };
+
+ MediaControl.prototype.onVolumeChanged = function onVolumeChanged() {
+ this.updateVolumeUI();
+ };
+
+ MediaControl.prototype.onLoadedMetadataOnVideoTag = function onLoadedMetadataOnVideoTag() {
+ var video = this.container.playback.el;
+ // video.webkitSupportsFullscreen is deprecated but iOS appears to only use this
+ // see https://github.com/clappr/clappr/issues/1127
+ if (!_utils.Fullscreen.fullscreenEnabled() && video.webkitSupportsFullscreen) {
+ this.fullScreenOnVideoTagSupported = true;
+ this.settingsUpdate();
+ }
+ };
+
+ MediaControl.prototype.updateVolumeUI = function updateVolumeUI() {
+ if (!this.rendered) {
+ // this will be called after a render
+ return;
+ }
+ // update volume bar scrubber/fill on bar mode
+ this.$volumeBarContainer.find('.bar-fill-2').css({});
+ var containerWidth = this.$volumeBarContainer.width();
+ var barWidth = this.$volumeBarBackground.width();
+ var offset = (containerWidth - barWidth) / 2.0;
+ var pos = barWidth * this.volume / 100.0 + offset;
+ this.$volumeBarFill.css({ width: this.volume + '%' });
+ this.$volumeBarScrubber.css({ left: pos });
+
+ // update volume bar segments on segmented bar mode
+ this.$volumeBarContainer.find('.segmented-bar-element').removeClass('fill');
+ var item = Math.ceil(this.volume / 10.0);
+ this.$volumeBarContainer.find('.segmented-bar-element').slice(0, item).addClass('fill');
+ this.$volumeIcon.html('');
+ this.$volumeIcon.removeClass('muted');
+ if (!this.muted) {
+ this.$volumeIcon.append(_volume2.default);
+ } else {
+ this.$volumeIcon.append(_mute2.default);
+ this.$volumeIcon.addClass('muted');
+ }
+ this.applyButtonStyle(this.$volumeIcon);
+ };
+
+ MediaControl.prototype.changeTogglePlay = function changeTogglePlay() {
+ this.$playPauseToggle.html('');
+ this.$playStopToggle.html('');
+ if (this.container && this.container.isPlaying()) {
+ this.$playPauseToggle.append(_pause2.default);
+ this.$playStopToggle.append(_stop2.default);
+ this.trigger(_events2.default.MEDIACONTROL_PLAYING);
+ } else {
+ this.$playPauseToggle.append(_play2.default);
+ this.$playStopToggle.append(_play2.default);
+ this.trigger(_events2.default.MEDIACONTROL_NOTPLAYING);
+ if (_browser2.default.isMobile) {
+ this.show();
+ }
+ }
+ this.applyButtonStyle(this.$playPauseToggle);
+ this.applyButtonStyle(this.$playStopToggle);
+ };
+
+ MediaControl.prototype.mousemoveOnSeekBar = function mousemoveOnSeekBar(event) {
+ if (this.settings.seekEnabled) {
+ var offsetX = event.pageX - this.$seekBarContainer.offset().left - this.$seekBarHover.width() / 2;
+ this.$seekBarHover.css({ left: offsetX });
+ }
+ this.trigger(_events2.default.MEDIACONTROL_MOUSEMOVE_SEEKBAR, event);
+ };
+
+ MediaControl.prototype.mouseleaveOnSeekBar = function mouseleaveOnSeekBar(event) {
+ this.trigger(_events2.default.MEDIACONTROL_MOUSELEAVE_SEEKBAR, event);
+ };
+
+ MediaControl.prototype.onVolumeClick = function onVolumeClick(event) {
+ this.setVolume(this.getVolumeFromUIEvent(event));
+ };
+
+ MediaControl.prototype.mousemoveOnVolumeBar = function mousemoveOnVolumeBar(event) {
+ if (this.draggingVolumeBar) {
+ this.setVolume(this.getVolumeFromUIEvent(event));
+ }
+ };
+
+ MediaControl.prototype.playerResize = function playerResize(size) {
+ this.$fullscreenToggle.html('');
+ if (_utils.Fullscreen.isFullscreen()) {
+ this.$fullscreenToggle.append(_shrink2.default);
+ } else {
+ this.$fullscreenToggle.append(_expand2.default);
+ }
+ this.applyButtonStyle(this.$fullscreenToggle);
+ this.$el.removeClass('w320');
+ if (size.width <= 320 || this.options.hideVolumeBar) {
+ this.$el.addClass('w320');
+ }
+ };
+
+ MediaControl.prototype.togglePlayPause = function togglePlayPause() {
+ if (this.container.isPlaying()) {
+ this.container.pause();
+ } else {
+ this.container.play();
+ }
+ return false;
+ };
+
+ MediaControl.prototype.togglePlayStop = function togglePlayStop() {
+ if (this.container.isPlaying()) {
+ this.container.stop();
+ } else {
+ this.container.play();
+ }
+ };
+
+ MediaControl.prototype.startSeekDrag = function startSeekDrag(event) {
+ if (!this.settings.seekEnabled) return;
+ this.draggingSeekBar = true;
+ this.$el.addClass('dragging');
+ this.$seekBarLoaded.addClass('media-control-notransition');
+ this.$seekBarPosition.addClass('media-control-notransition');
+ this.$seekBarScrubber.addClass('media-control-notransition');
+ if (event) {
+ event.preventDefault();
+ }
+ };
+
+ MediaControl.prototype.startVolumeDrag = function startVolumeDrag(event) {
+ this.draggingVolumeBar = true;
+ this.$el.addClass('dragging');
+ if (event) {
+ event.preventDefault();
+ }
+ };
+
+ MediaControl.prototype.stopDrag = function stopDrag(event) {
+ if (this.draggingSeekBar) {
+ this.seek(event);
+ }
+ this.$el.removeClass('dragging');
+ this.$seekBarLoaded.removeClass('media-control-notransition');
+ this.$seekBarPosition.removeClass('media-control-notransition');
+ this.$seekBarScrubber.removeClass('media-control-notransition dragging');
+ this.draggingSeekBar = false;
+ this.draggingVolumeBar = false;
+ };
+
+ MediaControl.prototype.updateDrag = function updateDrag(event) {
+ if (this.draggingSeekBar) {
+ event.preventDefault();
+ var offsetX = event.pageX - this.$seekBarContainer.offset().left;
+ var pos = offsetX / this.$seekBarContainer.width() * 100;
+ pos = Math.min(100, Math.max(pos, 0));
+ this.setSeekPercentage(pos);
+ } else if (this.draggingVolumeBar) {
+ event.preventDefault();
+ this.setVolume(this.getVolumeFromUIEvent(event));
+ }
+ };
+
+ MediaControl.prototype.getVolumeFromUIEvent = function getVolumeFromUIEvent(event) {
+ var offsetY = event.pageX - this.$volumeBarContainer.offset().left;
+ var volumeFromUI = offsetY / this.$volumeBarContainer.width() * 100;
+ return volumeFromUI;
+ };
+
+ MediaControl.prototype.toggleMute = function toggleMute() {
+ this.setVolume(this.muted ? 100 : 0);
+ };
+
+ MediaControl.prototype.setVolume = function setVolume(value) {
+ var _this2 = this;
+
+ value = Math.min(100, Math.max(value, 0));
+ // this will hold the intended volume
+ // it may not actually get set to this straight away
+ // if the container is not ready etc
+ this.intendedVolume = value;
+ this.persistConfig && _utils.Config.persist('volume', value);
+ var setWhenContainerReady = function setWhenContainerReady() {
+ if (_this2.container.isReady) {
+ _this2.container.setVolume(value);
+ } else {
+ _this2.listenToOnce(_this2.container, _events2.default.CONTAINER_READY, function () {
+ _this2.container.setVolume(value);
+ });
+ }
+ };
+
+ if (!this.container) {
+ this.listenToOnce(this, _events2.default.MEDIACONTROL_CONTAINERCHANGED, function () {
+ setWhenContainerReady();
+ });
+ } else {
+ setWhenContainerReady();
+ }
+ };
+
+ MediaControl.prototype.toggleFullscreen = function toggleFullscreen() {
+ this.trigger(_events2.default.MEDIACONTROL_FULLSCREEN, this.name);
+ this.container.fullscreen();
+ this.resetUserKeepVisible();
+ };
+
+ MediaControl.prototype.setContainer = function setContainer(container) {
+ if (this.container) {
+ this.stopListening(this.container);
+ this.fullScreenOnVideoTagSupported = null;
+ }
+ _mediator2.default.off(this.options.playerId + ':' + _events2.default.PLAYER_RESIZE, this.playerResize, this);
+ this.container = container;
+ // set the new container to match the volume of the last one
+ this.setVolume(this.intendedVolume);
+ this.changeTogglePlay();
+ this.addEventListeners();
+ this.settingsUpdate();
+ this.container.trigger(_events2.default.CONTAINER_PLAYBACKDVRSTATECHANGED, this.container.isDvrInUse());
+ if (this.container.mediaControlDisabled) {
+ this.disable();
+ }
+ this.trigger(_events2.default.MEDIACONTROL_CONTAINERCHANGED);
+ };
+
+ MediaControl.prototype.showVolumeBar = function showVolumeBar() {
+ if (this.hideVolumeId) {
+ clearTimeout(this.hideVolumeId);
+ }
+ this.$volumeBarContainer.removeClass('volume-bar-hide');
+ };
+
+ MediaControl.prototype.hideVolumeBar = function hideVolumeBar() {
+ var _this3 = this;
+
+ var timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 400;
+
+ if (!this.$volumeBarContainer) return;
+ if (this.draggingVolumeBar) {
+ this.hideVolumeId = setTimeout(function () {
+ return _this3.hideVolumeBar();
+ }, timeout);
+ } else {
+ if (this.hideVolumeId) {
+ clearTimeout(this.hideVolumeId);
+ }
+ this.hideVolumeId = setTimeout(function () {
+ return _this3.$volumeBarContainer.addClass('volume-bar-hide');
+ }, timeout);
+ }
+ };
+
+ MediaControl.prototype.ended = function ended() {
+ this.changeTogglePlay();
+ };
+
+ MediaControl.prototype.updateProgressBar = function updateProgressBar(progress) {
+ var loadedStart = progress.start / progress.total * 100;
+ var loadedEnd = progress.current / progress.total * 100;
+ this.$seekBarLoaded.css({ left: loadedStart + '%', width: loadedEnd - loadedStart + '%' });
+ };
+
+ MediaControl.prototype.onTimeUpdate = function onTimeUpdate(timeProgress) {
+ if (this.draggingSeekBar) return;
+ // TODO why should current time ever be negative?
+ var position = timeProgress.current < 0 ? timeProgress.total : timeProgress.current;
+
+ this.currentPositionValue = position;
+ this.currentDurationValue = timeProgress.total;
+ this.renderSeekBar();
+ };
+
+ MediaControl.prototype.renderSeekBar = function renderSeekBar() {
+ if (this.currentPositionValue === null || this.currentDurationValue === null) {
+ // this will be triggered as soon as these beocome available
+ return;
+ }
+
+ // default to 100%
+ this.currentSeekBarPercentage = 100;
+ if (this.container.getPlaybackType() !== _playback2.default.LIVE || this.container.isDvrInUse()) {
+ this.currentSeekBarPercentage = this.currentPositionValue / this.currentDurationValue * 100;
+ }
+ this.setSeekPercentage(this.currentSeekBarPercentage);
+
+ var newPosition = (0, _utils.formatTime)(this.currentPositionValue);
+ var newDuration = (0, _utils.formatTime)(this.currentDurationValue);
+ if (newPosition !== this.displayedPosition) {
+ this.$position.text(newPosition);
+ this.displayedPosition = newPosition;
+ }
+ if (newDuration !== this.displayedDuration) {
+ this.$duration.text(newDuration);
+ this.displayedDuration = newDuration;
+ }
+ };
+
+ MediaControl.prototype.seek = function seek(event) {
+ if (!this.settings.seekEnabled) return;
+ var offsetX = event.pageX - this.$seekBarContainer.offset().left;
+ var pos = offsetX / this.$seekBarContainer.width() * 100;
+ pos = Math.min(100, Math.max(pos, 0));
+ this.container.seekPercentage(pos);
+ this.setSeekPercentage(pos);
+ return false;
+ };
+
+ MediaControl.prototype.setKeepVisible = function setKeepVisible() {
+ this.keepVisible = true;
+ };
+
+ MediaControl.prototype.resetKeepVisible = function resetKeepVisible() {
+ this.keepVisible = false;
+ };
+
+ MediaControl.prototype.setUserKeepVisible = function setUserKeepVisible() {
+ this.userKeepVisible = true;
+ };
+
+ MediaControl.prototype.resetUserKeepVisible = function resetUserKeepVisible() {
+ this.userKeepVisible = false;
+ };
+
+ MediaControl.prototype.isVisible = function isVisible() {
+ return !this.$el.hasClass('media-control-hide');
+ };
+
+ MediaControl.prototype.show = function show(event) {
+ var _this4 = this;
+
+ if (this.disabled) {
+ return;
+ }
+ var timeout = 2000;
+ if (!event || event.clientX !== this.lastMouseX && event.clientY !== this.lastMouseY || navigator.userAgent.match(/firefox/i)) {
+ clearTimeout(this.hideId);
+ this.$el.show();
+ this.trigger(_events2.default.MEDIACONTROL_SHOW, this.name);
+ this.$el.removeClass('media-control-hide');
+ this.hideId = setTimeout(function () {
+ return _this4.hide();
+ }, timeout);
+ if (event) {
+ this.lastMouseX = event.clientX;
+ this.lastMouseY = event.clientY;
+ }
+ }
+ };
+
+ MediaControl.prototype.hide = function hide() {
+ var _this5 = this;
+
+ var delay = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
+
+ if (!this.isVisible() || _browser2.default.isMobile && !this.container.isPlaying()) {
+ return;
+ }
+ var timeout = delay || 2000;
+ clearTimeout(this.hideId);
+ if (!this.disabled && this.options.hideMediaControl === false) {
+ return;
+ }
+ if (!this.disabled && (delay || this.userKeepVisible || this.keepVisible || this.draggingSeekBar || this.draggingVolumeBar)) {
+ this.hideId = setTimeout(function () {
+ return _this5.hide();
+ }, timeout);
+ } else {
+ this.trigger(_events2.default.MEDIACONTROL_HIDE, this.name);
+ this.$el.addClass('media-control-hide');
+ this.hideVolumeBar(0);
+ }
+ };
+
+ MediaControl.prototype.settingsUpdate = function settingsUpdate() {
+ var newSettings = this.getSettings();
+ if (newSettings && !this.fullScreenOnVideoTagSupported && !_utils.Fullscreen.fullscreenEnabled()) {
+ // remove fullscreen from settings if it is present
+ newSettings.default && (0, _utils.removeArrayItem)(newSettings.default, 'fullscreen');
+ newSettings.left && (0, _utils.removeArrayItem)(newSettings.left, 'fullscreen');
+ newSettings.right && (0, _utils.removeArrayItem)(newSettings.right, 'fullscreen');
+ }
+ var settingsChanged = JSON.stringify(this.settings) !== JSON.stringify(newSettings);
+ if (settingsChanged) {
+ this.settings = newSettings;
+ this.render();
+ }
+ };
+
+ MediaControl.prototype.getSettings = function getSettings() {
+ return (0, _lodash2.default)({}, this.container.settings);
+ };
+
+ MediaControl.prototype.highDefinitionUpdate = function highDefinitionUpdate(isHD) {
+ var method = isHD ? 'addClass' : 'removeClass';
+ this.$hdIndicator[method]('enabled');
+ };
+
+ MediaControl.prototype.createCachedElements = function createCachedElements() {
+ var $layer = this.$el.find('.media-control-layer');
+ this.$duration = $layer.find('.media-control-indicator[data-duration]');
+ this.$fullscreenToggle = $layer.find('button.media-control-button[data-fullscreen]');
+ this.$playPauseToggle = $layer.find('button.media-control-button[data-playpause]');
+ this.$playStopToggle = $layer.find('button.media-control-button[data-playstop]');
+ this.$position = $layer.find('.media-control-indicator[data-position]');
+ this.$seekBarContainer = $layer.find('.bar-container[data-seekbar]');
+ this.$seekBarHover = $layer.find('.bar-hover[data-seekbar]');
+ this.$seekBarLoaded = $layer.find('.bar-fill-1[data-seekbar]');
+ this.$seekBarPosition = $layer.find('.bar-fill-2[data-seekbar]');
+ this.$seekBarScrubber = $layer.find('.bar-scrubber[data-seekbar]');
+ this.$volumeBarContainer = $layer.find('.bar-container[data-volume]');
+ this.$volumeContainer = $layer.find('.drawer-container[data-volume]');
+ this.$volumeIcon = $layer.find('.drawer-icon[data-volume]');
+ this.$volumeBarBackground = this.$el.find('.bar-background[data-volume]');
+ this.$volumeBarFill = this.$el.find('.bar-fill-1[data-volume]');
+ this.$volumeBarScrubber = this.$el.find('.bar-scrubber[data-volume]');
+ this.$hdIndicator = this.$el.find('button.media-control-button[data-hd-indicator]');
+ this.resetIndicators();
+ this.initializeIcons();
+ };
+
+ MediaControl.prototype.resetIndicators = function resetIndicators() {
+ this.displayedPosition = this.$position.text();
+ this.displayedDuration = this.$duration.text();
+ };
+
+ MediaControl.prototype.initializeIcons = function initializeIcons() {
+ var $layer = this.$el.find('.media-control-layer');
+ $layer.find('button.media-control-button[data-play]').append(_play2.default);
+ $layer.find('button.media-control-button[data-pause]').append(_pause2.default);
+ $layer.find('button.media-control-button[data-stop]').append(_stop2.default);
+ this.$playPauseToggle.append(_play2.default);
+ this.$playStopToggle.append(_play2.default);
+ this.$volumeIcon.append(_volume2.default);
+ this.$fullscreenToggle.append(_expand2.default);
+ this.$hdIndicator.append(_hd2.default);
+ };
+
+ MediaControl.prototype.setSeekPercentage = function setSeekPercentage(value) {
+ value = Math.max(Math.min(value, 100.0), 0);
+ if (this.displayedSeekBarPercentage === value) {
+ // not changed since last update
+ return;
+ }
+ this.displayedSeekBarPercentage = value;
+
+ this.$seekBarPosition.removeClass('media-control-notransition');
+ this.$seekBarScrubber.removeClass('media-control-notransition');
+ this.$seekBarPosition.css({ width: value + '%' });
+ this.$seekBarScrubber.css({ left: value + '%' });
+ };
+
+ MediaControl.prototype.seekRelative = function seekRelative(delta) {
+ if (!this.settings.seekEnabled) return;
+ var currentTime = this.container.getCurrentTime();
+ var duration = this.container.getDuration();
+ var position = Math.min(Math.max(currentTime + delta, 0), duration);
+ position = Math.min(position * 100 / duration, 100);
+ this.container.seekPercentage(position);
+ };
+
+ MediaControl.prototype.bindKeyEvents = function bindKeyEvents() {
+ var _this6 = this;
+
+ this.unbindKeyEvents();
+ this.kibo = new _vendor.Kibo(this.options.focusElement);
+ this.kibo.down(['space'], function () {
+ return _this6.togglePlayPause();
+ });
+ this.kibo.down(['left'], function () {
+ return _this6.seekRelative(-15);
+ });
+ this.kibo.down(['right'], function () {
+ return _this6.seekRelative(15);
+ });
+ var keys = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
+ keys.forEach(function (i) {
+ _this6.kibo.down(i.toString(), function () {
+ return _this6.settings.seekEnabled && _this6.container.seekPercentage(i * 10);
+ });
+ });
+ };
+
+ MediaControl.prototype.unbindKeyEvents = function unbindKeyEvents() {
+ if (this.kibo) {
+ this.kibo.off('space');
+ this.kibo.off('left');
+ this.kibo.off('right');
+ this.kibo.off([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);
+ }
+ };
+
+ MediaControl.prototype.parseColors = function parseColors() {
+ if (this.options.mediacontrol) {
+ this.buttonsColor = this.options.mediacontrol.buttons;
+ var seekbarColor = this.options.mediacontrol.seekbar;
+ this.$el.find('.bar-fill-2[data-seekbar]').css('background-color', seekbarColor);
+ this.$el.find('.media-control-icon svg path').css('fill', this.buttonsColor);
+ this.$el.find('.segmented-bar-element[data-volume]').css('boxShadow', 'inset 2px 0 0 ' + this.buttonsColor);
+ }
+ };
+
+ MediaControl.prototype.applyButtonStyle = function applyButtonStyle(element) {
+ if (this.buttonsColor && element) {
+ (0, _clapprZepto2.default)(element).find('svg path').css('fill', this.buttonsColor);
+ }
+ };
+
+ MediaControl.prototype.destroy = function destroy() {
+ this.remove();
+ (0, _clapprZepto2.default)(document).unbind('mouseup', this.stopDragHandler);
+ (0, _clapprZepto2.default)(document).unbind('mousemove', this.updateDragHandler);
+ this.unbindKeyEvents();
+ };
+
+ MediaControl.prototype.render = function render() {
+ var _this7 = this;
+
+ var timeout = 1000;
+ this.$el.html(this.template({ settings: this.settings }));
+ this.$el.append(this.stylesheet);
+ this.createCachedElements();
+ this.$playPauseToggle.addClass('paused');
+ this.$playStopToggle.addClass('stopped');
+
+ this.changeTogglePlay();
+ this.hideId = setTimeout(function () {
+ return _this7.hide();
+ }, timeout);
+ if (this.disabled) {
+ this.hide();
+ }
+
+ if (_browser2.default.isSafari && _browser2.default.isMobile) {
+ this.$volumeContainer.css('display', 'none');
+ }
+
+ this.$seekBarPosition.addClass('media-control-notransition');
+ this.$seekBarScrubber.addClass('media-control-notransition');
+
+ var previousSeekPercentage = 0;
+ if (this.displayedSeekBarPercentage) {
+ previousSeekPercentage = this.displayedSeekBarPercentage;
+ }
+ this.displayedSeekBarPercentage = null;
+ this.setSeekPercentage(previousSeekPercentage);
+
+ process.nextTick(function () {
+ if (!_this7.settings.seekEnabled) {
+ _this7.$seekBarContainer.addClass('seek-disabled');
+ }
+ if (!_this7.options.disableKeyboardShortcuts) {
+ _this7.bindKeyEvents();
+ }
+ _this7.playerResize({ width: _this7.options.width, height: _this7.options.height });
+ _this7.hideVolumeBar(0);
+ });
+
+ this.parseColors();
+ this.highDefinitionUpdate();
+
+ this.rendered = true;
+ this.updateVolumeUI();
+ this.trigger(_events2.default.MEDIACONTROL_RENDERED);
+ return this;
+ };
+
+ return MediaControl;
+ }(_ui_object2.default);
+
+ exports.default = MediaControl;
+
+
+ MediaControl.extend = function (properties) {
+ return (0, _utils.extend)(MediaControl, properties);
+ };
+ module.exports = exports['default'];
+ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(29)))
+
+/***/ },
+/* 29 */
+/***/ function(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.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; };
+
+
+/***/ },
+/* 30 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ /**
+ * The mediator is a singleton for handling global events.
+ */
+
+ var events = new _events2.default();
+
+ var Mediator = function Mediator() {
+ _classCallCheck(this, Mediator);
+ };
+
+ exports.default = Mediator;
+
+
+ Mediator.on = function (name, callback, context) {
+ events.on(name, callback, context);
+ return;
+ };
+
+ Mediator.once = function (name, callback, context) {
+ events.once(name, callback, context);
+ return;
+ };
+
+ Mediator.off = function (name, callback, context) {
+ events.off(name, callback, context);
+ return;
+ };
+
+ Mediator.trigger = function (name) {
+ for (var _len = arguments.length, opts = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ opts[_key - 1] = arguments[_key];
+ }
+
+ events.trigger.apply(events, [name].concat(opts));
+ return;
+ };
+
+ Mediator.stopListening = function (obj, name, callback) {
+ events.stopListening(obj, name, callback);
+ return;
+ };
+ module.exports = exports['default'];
+
+/***/ },
+/* 31 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _utils = __webpack_require__(2);
+
+ var _ui_object = __webpack_require__(18);
+
+ var _ui_object2 = _interopRequireDefault(_ui_object);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ /**
+ * An abstraction to represent a generic playback, it's like an interface to be implemented by subclasses.
+ * @class Playback
+ * @constructor
+ * @extends UIObject
+ * @module base
+ */
+ var Playback = function (_UIObject) {
+ _inherits(Playback, _UIObject);
+
+ _createClass(Playback, [{
+ key: 'isAudioOnly',
+
+ /**
+ * Determine if the playback does not contain video/has video but video should be ignored.
+ * @property isAudioOnly
+ * @type Boolean
+ */
+ get: function get() {
+ return false;
+ }
+
+ /**
+ * Determine if the playback has ended.
+ * @property ended
+ * @type Boolean
+ */
+
+ }, {
+ key: 'ended',
+ get: function get() {
+ return false;
+ }
+
+ /**
+ * The internationalization plugin.
+ * @property i18n
+ * @type {Strings}
+ */
+
+ }, {
+ key: 'i18n',
+ get: function get() {
+ return this._i18n;
+ }
+
+ /**
+ * Determine if the playback is having to buffer in order for
+ * playback to be smooth.
+ * (i.e if a live stream is playing smoothly, this will be false)
+ * @property buffering
+ * @type Boolean
+ */
+
+ }, {
+ key: 'buffering',
+ get: function get() {
+ return false;
+ }
+
+ /**
+ * @method constructor
+ * @param {Object} options the options object
+ * @param {Strings} i18n the internationalization component
+ */
+
+ }]);
+
+ function Playback(options, i18n) {
+ _classCallCheck(this, Playback);
+
+ var _this = _possibleConstructorReturn(this, _UIObject.call(this, options));
+
+ _this.settings = {};
+ _this._i18n = i18n;
+ return _this;
+ }
+
+ /**
+ * plays the playback.
+ * @method play
+ */
+
+
+ Playback.prototype.play = function play() {};
+
+ /**
+ * pauses the playback.
+ * @method pause
+ */
+
+
+ Playback.prototype.pause = function pause() {};
+
+ /**
+ * stops the playback.
+ * @method stop
+ */
+
+
+ Playback.prototype.stop = function stop() {};
+
+ /**
+ * seeks the playback to a given `time` in seconds
+ * @method seek
+ * @param {Number} time should be a number between 0 and the video duration
+ */
+
+
+ Playback.prototype.seek = function seek(time) {}; // eslint-disable-line no-unused-vars
+
+ /**
+ * seeks the playback to a given `percentage` in percentage
+ * @method seekPercentage
+ * @param {Number} time should be a number between 0 and 100
+ */
+
+
+ Playback.prototype.seekPercentage = function seekPercentage(percentage) {}; // eslint-disable-line no-unused-vars
+
+
+ /**
+ * The time that "0" now represents relative to when playback started.
+ * For a stream with a sliding window this will increase as content is
+ * removed from the beginning.
+ * @method getStartTimeOffset
+ * @return {Number} time (in seconds) that time "0" represents.
+ */
+
+
+ Playback.prototype.getStartTimeOffset = function getStartTimeOffset() {
+ return 0;
+ };
+
+ /**
+ * gets the duration in seconds
+ * @method getDuration
+ * @return {Number} duration (in seconds) of the current source
+ */
+
+
+ Playback.prototype.getDuration = function getDuration() {
+ return 0;
+ };
+
+ /**
+ * checks if the playback is playing.
+ * @method isPlaying
+ * @return {Boolean} `true` if the current playback is playing, otherwise `false`
+ */
+
+
+ Playback.prototype.isPlaying = function isPlaying() {
+ return false;
+ };
+
+ /**
+ * checks if the playback is ready.
+ * @property isReady
+ * @type {Boolean} `true` if the current playback is ready, otherwise `false`
+ */
+
+
+ /**
+ * gets the playback type (`'vod', 'live', 'aod'`)
+ * @method getPlaybackType
+ * @return {String} you should write the playback type otherwise it'll assume `'no_op'`
+ * @example
+ * ```javascript
+ * html5VideoPlayback.getPlaybackType() //vod
+ * html5AudioPlayback.getPlaybackType() //aod
+ * html5VideoPlayback.getPlaybackType() //live
+ * flashHlsPlayback.getPlaybackType() //live
+ * ```
+ */
+ Playback.prototype.getPlaybackType = function getPlaybackType() {
+ return Playback.NO_OP;
+ };
+
+ /**
+ * checks if the playback is in HD.
+ * @method isHighDefinitionInUse
+ * @return {Boolean} `true` if the playback is playing in HD, otherwise `false`
+ */
+
+
+ Playback.prototype.isHighDefinitionInUse = function isHighDefinitionInUse() {
+ return false;
+ };
+
+ /**
+ * sets the volume for the playback
+ * @method volume
+ * @param {Number} value a number between 0 (`muted`) to 100 (`max`)
+ */
+
+
+ Playback.prototype.volume = function volume(value) {}; // eslint-disable-line no-unused-vars
+
+ /**
+ * destroys the playback, removing it from DOM
+ * @method destroy
+ */
+
+
+ Playback.prototype.destroy = function destroy() {
+ this.$el.remove();
+ };
+
+ _createClass(Playback, [{
+ key: 'isReady',
+ get: function get() {
+ return false;
+ }
+ }]);
+
+ return Playback;
+ }(_ui_object2.default);
+
+ exports.default = Playback;
+
+
+ Playback.extend = function (properties) {
+ return (0, _utils.extend)(Playback, properties);
+ };
+
+ /**
+ * checks if the playback can play a given `source`
+ * If a mimeType is provided then this will be used instead of inferring the mimetype
+ * from the source extension.
+ * @method canPlay
+ * @static
+ * @param {String} source the given source ex: `http://example.com/play.mp4`
+ * @param {String} [mimeType] the given mime type, ex: `'application/vnd.apple.mpegurl'`
+ * @return {Boolean} `true` if the playback is playable, otherwise `false`
+ */
+ Playback.canPlay = function (source, mimeType) {
+ // eslint-disable-line no-unused-vars
+ return false;
+ };
+
+ /**
+ * a playback type for video on demand
+ *
+ * @property VOD
+ * @static
+ * @type String
+ */
+ Playback.VOD = 'vod';
+ /**
+ * a playback type for audio on demand
+ *
+ * @property AOD
+ * @static
+ * @type String
+ */
+ Playback.AOD = 'aod';
+ /**
+ * a playback type for live video
+ *
+ * @property LIVE
+ * @static
+ * @type String
+ */
+ Playback.LIVE = 'live';
+ /**
+ * a default playback type
+ *
+ * @property NO_OP
+ * @static
+ * @type String
+ */
+ Playback.NO_OP = 'no_op';
+ /**
+ * the plugin type
+ *
+ * @property type
+ * @static
+ * @type String
+ */
+ Playback.type = 'playback';
+ module.exports = exports['default'];
+
+/***/ },
+/* 32 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /* WEBPACK VAR INJECTION */(function(global, module) {/**
+ * lodash (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors <https://jquery.org/>
+ * Released under MIT license <https://lodash.com/license>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+
+ /** Used as the size to enable large array optimizations. */
+ var LARGE_ARRAY_SIZE = 200;
+
+ /** Used to stand-in for `undefined` hash values. */
+ var HASH_UNDEFINED = '__lodash_hash_undefined__';
+
+ /** Used as references for various `Number` constants. */
+ var MAX_SAFE_INTEGER = 9007199254740991;
+
+ /** `Object#toString` result references. */
+ var argsTag = '[object Arguments]',
+ arrayTag = '[object Array]',
+ boolTag = '[object Boolean]',
+ dateTag = '[object Date]',
+ errorTag = '[object Error]',
+ funcTag = '[object Function]',
+ genTag = '[object GeneratorFunction]',
+ mapTag = '[object Map]',
+ numberTag = '[object Number]',
+ objectTag = '[object Object]',
+ promiseTag = '[object Promise]',
+ regexpTag = '[object RegExp]',
+ setTag = '[object Set]',
+ stringTag = '[object String]',
+ symbolTag = '[object Symbol]',
+ weakMapTag = '[object WeakMap]';
+
+ var arrayBufferTag = '[object ArrayBuffer]',
+ dataViewTag = '[object DataView]',
+ float32Tag = '[object Float32Array]',
+ float64Tag = '[object Float64Array]',
+ int8Tag = '[object Int8Array]',
+ int16Tag = '[object Int16Array]',
+ int32Tag = '[object Int32Array]',
+ uint8Tag = '[object Uint8Array]',
+ uint8ClampedTag = '[object Uint8ClampedArray]',
+ uint16Tag = '[object Uint16Array]',
+ uint32Tag = '[object Uint32Array]';
+
+ /**
+ * Used to match `RegExp`
+ * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
+ */
+ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
+
+ /** Used to match `RegExp` flags from their coerced string values. */
+ var reFlags = /\w*$/;
+
+ /** Used to detect host constructors (Safari). */
+ var reIsHostCtor = /^\[object .+?Constructor\]$/;
+
+ /** Used to detect unsigned integer values. */
+ var reIsUint = /^(?:0|[1-9]\d*)$/;
+
+ /** Used to identify `toStringTag` values of typed arrays. */
+ var typedArrayTags = {};
+ typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
+ typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
+ typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
+ typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
+ typedArrayTags[uint32Tag] = true;
+ typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
+ typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
+ typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
+ typedArrayTags[errorTag] = typedArrayTags[funcTag] =
+ typedArrayTags[mapTag] = typedArrayTags[numberTag] =
+ typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
+ typedArrayTags[setTag] = typedArrayTags[stringTag] =
+ typedArrayTags[weakMapTag] = false;
+
+ /** Used to identify `toStringTag` values supported by `_.clone`. */
+ var cloneableTags = {};
+ cloneableTags[argsTag] = cloneableTags[arrayTag] =
+ cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
+ cloneableTags[boolTag] = cloneableTags[dateTag] =
+ cloneableTags[float32Tag] = cloneableTags[float64Tag] =
+ cloneableTags[int8Tag] = cloneableTags[int16Tag] =
+ cloneableTags[int32Tag] = cloneableTags[mapTag] =
+ cloneableTags[numberTag] = cloneableTags[objectTag] =
+ cloneableTags[regexpTag] = cloneableTags[setTag] =
+ cloneableTags[stringTag] = cloneableTags[symbolTag] =
+ cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
+ cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
+ cloneableTags[errorTag] = cloneableTags[funcTag] =
+ cloneableTags[weakMapTag] = false;
+
+ /** Detect free variable `global` from Node.js. */
+ var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
+
+ /** Detect free variable `self`. */
+ var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
+
+ /** Used as a reference to the global object. */
+ var root = freeGlobal || freeSelf || Function('return this')();
+
+ /** Detect free variable `exports`. */
+ var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
+
+ /** Detect free variable `module`. */
+ var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
+
+ /** Detect the popular CommonJS extension `module.exports`. */
+ var moduleExports = freeModule && freeModule.exports === freeExports;
+
+ /** Detect free variable `process` from Node.js. */
+ var freeProcess = moduleExports && freeGlobal.process;
+
+ /** Used to access faster Node.js helpers. */
+ var nodeUtil = (function() {
+ try {
+ return freeProcess && freeProcess.binding('util');
+ } catch (e) {}
+ }());
+
+ /* Node.js helper references. */
+ var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
+
+ /**
+ * Adds the key-value `pair` to `map`.
+ *
+ * @private
+ * @param {Object} map The map to modify.
+ * @param {Array} pair The key-value pair to add.
+ * @returns {Object} Returns `map`.
+ */
+ function addMapEntry(map, pair) {
+ // Don't return `map.set` because it's not chainable in IE 11.
+ map.set(pair[0], pair[1]);
+ return map;
+ }
+
+ /**
+ * Adds `value` to `set`.
+ *
+ * @private
+ * @param {Object} set The set to modify.
+ * @param {*} value The value to add.
+ * @returns {Object} Returns `set`.
+ */
+ function addSetEntry(set, value) {
+ // Don't return `set.add` because it's not chainable in IE 11.
+ set.add(value);
+ return set;
+ }
+
+ /**
+ * A faster alternative to `Function#apply`, this function invokes `func`
+ * with the `this` binding of `thisArg` and the arguments of `args`.
+ *
+ * @private
+ * @param {Function} func The function to invoke.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {Array} args The arguments to invoke `func` with.
+ * @returns {*} Returns the result of `func`.
+ */
+ function apply(func, thisArg, args) {
+ switch (args.length) {
+ case 0: return func.call(thisArg);
+ case 1: return func.call(thisArg, args[0]);
+ case 2: return func.call(thisArg, args[0], args[1]);
+ case 3: return func.call(thisArg, args[0], args[1], args[2]);
+ }
+ return func.apply(thisArg, args);
+ }
+
+ /**
+ * A specialized version of `_.forEach` for arrays without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayEach(array, iteratee) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ while (++index < length) {
+ if (iteratee(array[index], index, array) === false) {
+ break;
+ }
+ }
+ return array;
+ }
+
+ /**
+ * Appends the elements of `values` to `array`.
+ *
+ * @private
+ * @param {Array} array The array to modify.
+ * @param {Array} values The values to append.
+ * @returns {Array} Returns `array`.
+ */
+ function arrayPush(array, values) {
+ var index = -1,
+ length = values.length,
+ offset = array.length;
+
+ while (++index < length) {
+ array[offset + index] = values[index];
+ }
+ return array;
+ }
+
+ /**
+ * A specialized version of `_.reduce` for arrays without support for
+ * iteratee shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {*} [accumulator] The initial value.
+ * @param {boolean} [initAccum] Specify using the first element of `array` as
+ * the initial value.
+ * @returns {*} Returns the accumulated value.
+ */
+ function arrayReduce(array, iteratee, accumulator, initAccum) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ if (initAccum && length) {
+ accumulator = array[++index];
+ }
+ while (++index < length) {
+ accumulator = iteratee(accumulator, array[index], index, array);
+ }
+ return accumulator;
+ }
+
+ /**
+ * The base implementation of `_.times` without support for iteratee shorthands
+ * or max array length checks.
+ *
+ * @private
+ * @param {number} n The number of times to invoke `iteratee`.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the array of results.
+ */
+ function baseTimes(n, iteratee) {
+ var index = -1,
+ result = Array(n);
+
+ while (++index < n) {
+ result[index] = iteratee(index);
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.unary` without support for storing metadata.
+ *
+ * @private
+ * @param {Function} func The function to cap arguments for.
+ * @returns {Function} Returns the new capped function.
+ */
+ function baseUnary(func) {
+ return function(value) {
+ return func(value);
+ };
+ }
+
+ /**
+ * Gets the value at `key` of `object`.
+ *
+ * @private
+ * @param {Object} [object] The object to query.
+ * @param {string} key The key of the property to get.
+ * @returns {*} Returns the property value.
+ */
+ function getValue(object, key) {
+ return object == null ? undefined : object[key];
+ }
+
+ /**
+ * Checks if `value` is a host object in IE < 9.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
+ */
+ function isHostObject(value) {
+ // Many host objects are `Object` objects that can coerce to strings
+ // despite having improperly defined `toString` methods.
+ var result = false;
+ if (value != null && typeof value.toString != 'function') {
+ try {
+ result = !!(value + '');
+ } catch (e) {}
+ }
+ return result;
+ }
+
+ /**
+ * Converts `map` to its key-value pairs.
+ *
+ * @private
+ * @param {Object} map The map to convert.
+ * @returns {Array} Returns the key-value pairs.
+ */
+ function mapToArray(map) {
+ var index = -1,
+ result = Array(map.size);
+
+ map.forEach(function(value, key) {
+ result[++index] = [key, value];
+ });
+ return result;
+ }
+
+ /**
+ * Creates a unary function that invokes `func` with its argument transformed.
+ *
+ * @private
+ * @param {Function} func The function to wrap.
+ * @param {Function} transform The argument transform.
+ * @returns {Function} Returns the new function.
+ */
+ function overArg(func, transform) {
+ return function(arg) {
+ return func(transform(arg));
+ };
+ }
+
+ /**
+ * Converts `set` to an array of its values.
+ *
+ * @private
+ * @param {Object} set The set to convert.
+ * @returns {Array} Returns the values.
+ */
+ function setToArray(set) {
+ var index = -1,
+ result = Array(set.size);
+
+ set.forEach(function(value) {
+ result[++index] = value;
+ });
+ return result;
+ }
+
+ /** Used for built-in method references. */
+ var arrayProto = Array.prototype,
+ funcProto = Function.prototype,
+ objectProto = Object.prototype;
+
+ /** Used to detect overreaching core-js shims. */
+ var coreJsData = root['__core-js_shared__'];
+
+ /** Used to detect methods masquerading as native. */
+ var maskSrcKey = (function() {
+ var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
+ return uid ? ('Symbol(src)_1.' + uid) : '';
+ }());
+
+ /** Used to resolve the decompiled source of functions. */
+ var funcToString = funcProto.toString;
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /** Used to infer the `Object` constructor. */
+ var objectCtorString = funcToString.call(Object);
+
+ /**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+ var objectToString = objectProto.toString;
+
+ /** Used to detect if a method is native. */
+ var reIsNative = RegExp('^' +
+ funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
+ .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+ );
+
+ /** Built-in value references. */
+ var Buffer = moduleExports ? root.Buffer : undefined,
+ Symbol = root.Symbol,
+ Uint8Array = root.Uint8Array,
+ getPrototype = overArg(Object.getPrototypeOf, Object),
+ objectCreate = Object.create,
+ propertyIsEnumerable = objectProto.propertyIsEnumerable,
+ splice = arrayProto.splice;
+
+ /* Built-in method references for those with the same name as other `lodash` methods. */
+ var nativeGetSymbols = Object.getOwnPropertySymbols,
+ nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
+ nativeKeys = overArg(Object.keys, Object),
+ nativeMax = Math.max;
+
+ /* Built-in method references that are verified to be native. */
+ var DataView = getNative(root, 'DataView'),
+ Map = getNative(root, 'Map'),
+ Promise = getNative(root, 'Promise'),
+ Set = getNative(root, 'Set'),
+ WeakMap = getNative(root, 'WeakMap'),
+ nativeCreate = getNative(Object, 'create');
+
+ /** Used to detect maps, sets, and weakmaps. */
+ var dataViewCtorString = toSource(DataView),
+ mapCtorString = toSource(Map),
+ promiseCtorString = toSource(Promise),
+ setCtorString = toSource(Set),
+ weakMapCtorString = toSource(WeakMap);
+
+ /** Used to convert symbols to primitives and strings. */
+ var symbolProto = Symbol ? Symbol.prototype : undefined,
+ symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;
+
+ /**
+ * Creates a hash object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function Hash(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the hash.
+ *
+ * @private
+ * @name clear
+ * @memberOf Hash
+ */
+ function hashClear() {
+ this.__data__ = nativeCreate ? nativeCreate(null) : {};
+ }
+
+ /**
+ * Removes `key` and its value from the hash.
+ *
+ * @private
+ * @name delete
+ * @memberOf Hash
+ * @param {Object} hash The hash to modify.
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function hashDelete(key) {
+ return this.has(key) && delete this.__data__[key];
+ }
+
+ /**
+ * Gets the hash value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf Hash
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function hashGet(key) {
+ var data = this.__data__;
+ if (nativeCreate) {
+ var result = data[key];
+ return result === HASH_UNDEFINED ? undefined : result;
+ }
+ return hasOwnProperty.call(data, key) ? data[key] : undefined;
+ }
+
+ /**
+ * Checks if a hash value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf Hash
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function hashHas(key) {
+ var data = this.__data__;
+ return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
+ }
+
+ /**
+ * Sets the hash `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf Hash
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the hash instance.
+ */
+ function hashSet(key, value) {
+ var data = this.__data__;
+ data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
+ return this;
+ }
+
+ // Add methods to `Hash`.
+ Hash.prototype.clear = hashClear;
+ Hash.prototype['delete'] = hashDelete;
+ Hash.prototype.get = hashGet;
+ Hash.prototype.has = hashHas;
+ Hash.prototype.set = hashSet;
+
+ /**
+ * Creates an list cache object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function ListCache(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the list cache.
+ *
+ * @private
+ * @name clear
+ * @memberOf ListCache
+ */
+ function listCacheClear() {
+ this.__data__ = [];
+ }
+
+ /**
+ * Removes `key` and its value from the list cache.
+ *
+ * @private
+ * @name delete
+ * @memberOf ListCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function listCacheDelete(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ return false;
+ }
+ var lastIndex = data.length - 1;
+ if (index == lastIndex) {
+ data.pop();
+ } else {
+ splice.call(data, index, 1);
+ }
+ return true;
+ }
+
+ /**
+ * Gets the list cache value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf ListCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function listCacheGet(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ return index < 0 ? undefined : data[index][1];
+ }
+
+ /**
+ * Checks if a list cache value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf ListCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function listCacheHas(key) {
+ return assocIndexOf(this.__data__, key) > -1;
+ }
+
+ /**
+ * Sets the list cache `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf ListCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the list cache instance.
+ */
+ function listCacheSet(key, value) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ data.push([key, value]);
+ } else {
+ data[index][1] = value;
+ }
+ return this;
+ }
+
+ // Add methods to `ListCache`.
+ ListCache.prototype.clear = listCacheClear;
+ ListCache.prototype['delete'] = listCacheDelete;
+ ListCache.prototype.get = listCacheGet;
+ ListCache.prototype.has = listCacheHas;
+ ListCache.prototype.set = listCacheSet;
+
+ /**
+ * Creates a map cache object to store key-value pairs.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function MapCache(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the map.
+ *
+ * @private
+ * @name clear
+ * @memberOf MapCache
+ */
+ function mapCacheClear() {
+ this.__data__ = {
+ 'hash': new Hash,
+ 'map': new (Map || ListCache),
+ 'string': new Hash
+ };
+ }
+
+ /**
+ * Removes `key` and its value from the map.
+ *
+ * @private
+ * @name delete
+ * @memberOf MapCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function mapCacheDelete(key) {
+ return getMapData(this, key)['delete'](key);
+ }
+
+ /**
+ * Gets the map value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf MapCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function mapCacheGet(key) {
+ return getMapData(this, key).get(key);
+ }
+
+ /**
+ * Checks if a map value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf MapCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function mapCacheHas(key) {
+ return getMapData(this, key).has(key);
+ }
+
+ /**
+ * Sets the map `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf MapCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the map cache instance.
+ */
+ function mapCacheSet(key, value) {
+ getMapData(this, key).set(key, value);
+ return this;
+ }
+
+ // Add methods to `MapCache`.
+ MapCache.prototype.clear = mapCacheClear;
+ MapCache.prototype['delete'] = mapCacheDelete;
+ MapCache.prototype.get = mapCacheGet;
+ MapCache.prototype.has = mapCacheHas;
+ MapCache.prototype.set = mapCacheSet;
+
+ /**
+ * Creates a stack cache object to store key-value pairs.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function Stack(entries) {
+ this.__data__ = new ListCache(entries);
+ }
+
+ /**
+ * Removes all key-value entries from the stack.
+ *
+ * @private
+ * @name clear
+ * @memberOf Stack
+ */
+ function stackClear() {
+ this.__data__ = new ListCache;
+ }
+
+ /**
+ * Removes `key` and its value from the stack.
+ *
+ * @private
+ * @name delete
+ * @memberOf Stack
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function stackDelete(key) {
+ return this.__data__['delete'](key);
+ }
+
+ /**
+ * Gets the stack value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf Stack
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function stackGet(key) {
+ return this.__data__.get(key);
+ }
+
+ /**
+ * Checks if a stack value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf Stack
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function stackHas(key) {
+ return this.__data__.has(key);
+ }
+
+ /**
+ * Sets the stack `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf Stack
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the stack cache instance.
+ */
+ function stackSet(key, value) {
+ var cache = this.__data__;
+ if (cache instanceof ListCache) {
+ var pairs = cache.__data__;
+ if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
+ pairs.push([key, value]);
+ return this;
+ }
+ cache = this.__data__ = new MapCache(pairs);
+ }
+ cache.set(key, value);
+ return this;
+ }
+
+ // Add methods to `Stack`.
+ Stack.prototype.clear = stackClear;
+ Stack.prototype['delete'] = stackDelete;
+ Stack.prototype.get = stackGet;
+ Stack.prototype.has = stackHas;
+ Stack.prototype.set = stackSet;
+
+ /**
+ * Creates an array of the enumerable property names of the array-like `value`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @param {boolean} inherited Specify returning inherited property names.
+ * @returns {Array} Returns the array of property names.
+ */
+ function arrayLikeKeys(value, inherited) {
+ // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
+ // Safari 9 makes `arguments.length` enumerable in strict mode.
+ var result = (isArray(value) || isArguments(value))
+ ? baseTimes(value.length, String)
+ : [];
+
+ var length = result.length,
+ skipIndexes = !!length;
+
+ for (var key in value) {
+ if ((inherited || hasOwnProperty.call(value, key)) &&
+ !(skipIndexes && (key == 'length' || isIndex(key, length)))) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * This function is like `assignValue` except that it doesn't assign
+ * `undefined` values.
+ *
+ * @private
+ * @param {Object} object The object to modify.
+ * @param {string} key The key of the property to assign.
+ * @param {*} value The value to assign.
+ */
+ function assignMergeValue(object, key, value) {
+ if ((value !== undefined && !eq(object[key], value)) ||
+ (typeof key == 'number' && value === undefined && !(key in object))) {
+ object[key] = value;
+ }
+ }
+
+ /**
+ * Assigns `value` to `key` of `object` if the existing value is not equivalent
+ * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * for equality comparisons.
+ *
+ * @private
+ * @param {Object} object The object to modify.
+ * @param {string} key The key of the property to assign.
+ * @param {*} value The value to assign.
+ */
+ function assignValue(object, key, value) {
+ var objValue = object[key];
+ if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
+ (value === undefined && !(key in object))) {
+ object[key] = value;
+ }
+ }
+
+ /**
+ * Gets the index at which the `key` is found in `array` of key-value pairs.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {*} key The key to search for.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function assocIndexOf(array, key) {
+ var length = array.length;
+ while (length--) {
+ if (eq(array[length][0], key)) {
+ return length;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `_.assign` without support for multiple sources
+ * or `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @returns {Object} Returns `object`.
+ */
+ function baseAssign(object, source) {
+ return object && copyObject(source, keys(source), object);
+ }
+
+ /**
+ * The base implementation of `_.clone` and `_.cloneDeep` which tracks
+ * traversed objects.
+ *
+ * @private
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {boolean} [isFull] Specify a clone including symbols.
+ * @param {Function} [customizer] The function to customize cloning.
+ * @param {string} [key] The key of `value`.
+ * @param {Object} [object] The parent object of `value`.
+ * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
+ * @returns {*} Returns the cloned value.
+ */
+ function baseClone(value, isDeep, isFull, customizer, key, object, stack) {
+ var result;
+ if (customizer) {
+ result = object ? customizer(value, key, object, stack) : customizer(value);
+ }
+ if (result !== undefined) {
+ return result;
+ }
+ if (!isObject(value)) {
+ return value;
+ }
+ var isArr = isArray(value);
+ if (isArr) {
+ result = initCloneArray(value);
+ if (!isDeep) {
+ return copyArray(value, result);
+ }
+ } else {
+ var tag = getTag(value),
+ isFunc = tag == funcTag || tag == genTag;
+
+ if (isBuffer(value)) {
+ return cloneBuffer(value, isDeep);
+ }
+ if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
+ if (isHostObject(value)) {
+ return object ? value : {};
+ }
+ result = initCloneObject(isFunc ? {} : value);
+ if (!isDeep) {
+ return copySymbols(value, baseAssign(result, value));
+ }
+ } else {
+ if (!cloneableTags[tag]) {
+ return object ? value : {};
+ }
+ result = initCloneByTag(value, tag, baseClone, isDeep);
+ }
+ }
+ // Check for circular references and return its corresponding clone.
+ stack || (stack = new Stack);
+ var stacked = stack.get(value);
+ if (stacked) {
+ return stacked;
+ }
+ stack.set(value, result);
+
+ if (!isArr) {
+ var props = isFull ? getAllKeys(value) : keys(value);
+ }
+ arrayEach(props || value, function(subValue, key) {
+ if (props) {
+ key = subValue;
+ subValue = value[key];
+ }
+ // Recursively populate clone (susceptible to call stack limits).
+ assignValue(result, key, baseClone(subValue, isDeep, isFull, customizer, key, value, stack));
+ });
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.create` without support for assigning
+ * properties to the created object.
+ *
+ * @private
+ * @param {Object} prototype The object to inherit from.
+ * @returns {Object} Returns the new object.
+ */
+ function baseCreate(proto) {
+ return isObject(proto) ? objectCreate(proto) : {};
+ }
+
+ /**
+ * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
+ * `keysFunc` and `symbolsFunc` to get the enumerable property names and
+ * symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @param {Function} symbolsFunc The function to get the symbols of `object`.
+ * @returns {Array} Returns the array of property names and symbols.
+ */
+ function baseGetAllKeys(object, keysFunc, symbolsFunc) {
+ var result = keysFunc(object);
+ return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
+ }
+
+ /**
+ * The base implementation of `getTag`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+ function baseGetTag(value) {
+ return objectToString.call(value);
+ }
+
+ /**
+ * The base implementation of `_.isNative` without bad shim checks.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function,
+ * else `false`.
+ */
+ function baseIsNative(value) {
+ if (!isObject(value) || isMasked(value)) {
+ return false;
+ }
+ var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;
+ return pattern.test(toSource(value));
+ }
+
+ /**
+ * The base implementation of `_.isTypedArray` without Node.js optimizations.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
+ */
+ function baseIsTypedArray(value) {
+ return isObjectLike(value) &&
+ isLength(value.length) && !!typedArrayTags[objectToString.call(value)];
+ }
+
+ /**
+ * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+ function baseKeys(object) {
+ if (!isPrototype(object)) {
+ return nativeKeys(object);
+ }
+ var result = [];
+ for (var key in Object(object)) {
+ if (hasOwnProperty.call(object, key) && key != 'constructor') {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+ function baseKeysIn(object) {
+ if (!isObject(object)) {
+ return nativeKeysIn(object);
+ }
+ var isProto = isPrototype(object),
+ result = [];
+
+ for (var key in object) {
+ if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.merge` without support for multiple sources.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {number} srcIndex The index of `source`.
+ * @param {Function} [customizer] The function to customize merged values.
+ * @param {Object} [stack] Tracks traversed source values and their merged
+ * counterparts.
+ */
+ function baseMerge(object, source, srcIndex, customizer, stack) {
+ if (object === source) {
+ return;
+ }
+ if (!(isArray(source) || isTypedArray(source))) {
+ var props = baseKeysIn(source);
+ }
+ arrayEach(props || source, function(srcValue, key) {
+ if (props) {
+ key = srcValue;
+ srcValue = source[key];
+ }
+ if (isObject(srcValue)) {
+ stack || (stack = new Stack);
+ baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
+ }
+ else {
+ var newValue = customizer
+ ? customizer(object[key], srcValue, (key + ''), object, source, stack)
+ : undefined;
+
+ if (newValue === undefined) {
+ newValue = srcValue;
+ }
+ assignMergeValue(object, key, newValue);
+ }
+ });
+ }
+
+ /**
+ * A specialized version of `baseMerge` for arrays and objects which performs
+ * deep merges and tracks traversed objects enabling objects with circular
+ * references to be merged.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {string} key The key of the value to merge.
+ * @param {number} srcIndex The index of `source`.
+ * @param {Function} mergeFunc The function to merge values.
+ * @param {Function} [customizer] The function to customize assigned values.
+ * @param {Object} [stack] Tracks traversed source values and their merged
+ * counterparts.
+ */
+ function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
+ var objValue = object[key],
+ srcValue = source[key],
+ stacked = stack.get(srcValue);
+
+ if (stacked) {
+ assignMergeValue(object, key, stacked);
+ return;
+ }
+ var newValue = customizer
+ ? customizer(objValue, srcValue, (key + ''), object, source, stack)
+ : undefined;
+
+ var isCommon = newValue === undefined;
+
+ if (isCommon) {
+ newValue = srcValue;
+ if (isArray(srcValue) || isTypedArray(srcValue)) {
+ if (isArray(objValue)) {
+ newValue = objValue;
+ }
+ else if (isArrayLikeObject(objValue)) {
+ newValue = copyArray(objValue);
+ }
+ else {
+ isCommon = false;
+ newValue = baseClone(srcValue, true);
+ }
+ }
+ else if (isPlainObject(srcValue) || isArguments(srcValue)) {
+ if (isArguments(objValue)) {
+ newValue = toPlainObject(objValue);
+ }
+ else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) {
+ isCommon = false;
+ newValue = baseClone(srcValue, true);
+ }
+ else {
+ newValue = objValue;
+ }
+ }
+ else {
+ isCommon = false;
+ }
+ }
+ if (isCommon) {
+ // Recursively merge objects and arrays (susceptible to call stack limits).
+ stack.set(srcValue, newValue);
+ mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
+ stack['delete'](srcValue);
+ }
+ assignMergeValue(object, key, newValue);
+ }
+
+ /**
+ * The base implementation of `_.rest` which doesn't validate or coerce arguments.
+ *
+ * @private
+ * @param {Function} func The function to apply a rest parameter to.
+ * @param {number} [start=func.length-1] The start position of the rest parameter.
+ * @returns {Function} Returns the new function.
+ */
+ function baseRest(func, start) {
+ start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
+ return function() {
+ var args = arguments,
+ index = -1,
+ length = nativeMax(args.length - start, 0),
+ array = Array(length);
+
+ while (++index < length) {
+ array[index] = args[start + index];
+ }
+ index = -1;
+ var otherArgs = Array(start + 1);
+ while (++index < start) {
+ otherArgs[index] = args[index];
+ }
+ otherArgs[start] = array;
+ return apply(func, this, otherArgs);
+ };
+ }
+
+ /**
+ * Creates a clone of `buffer`.
+ *
+ * @private
+ * @param {Buffer} buffer The buffer to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Buffer} Returns the cloned buffer.
+ */
+ function cloneBuffer(buffer, isDeep) {
+ if (isDeep) {
+ return buffer.slice();
+ }
+ var result = new buffer.constructor(buffer.length);
+ buffer.copy(result);
+ return result;
+ }
+
+ /**
+ * Creates a clone of `arrayBuffer`.
+ *
+ * @private
+ * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
+ * @returns {ArrayBuffer} Returns the cloned array buffer.
+ */
+ function cloneArrayBuffer(arrayBuffer) {
+ var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
+ new Uint8Array(result).set(new Uint8Array(arrayBuffer));
+ return result;
+ }
+
+ /**
+ * Creates a clone of `dataView`.
+ *
+ * @private
+ * @param {Object} dataView The data view to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the cloned data view.
+ */
+ function cloneDataView(dataView, isDeep) {
+ var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
+ return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
+ }
+
+ /**
+ * Creates a clone of `map`.
+ *
+ * @private
+ * @param {Object} map The map to clone.
+ * @param {Function} cloneFunc The function to clone values.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the cloned map.
+ */
+ function cloneMap(map, isDeep, cloneFunc) {
+ var array = isDeep ? cloneFunc(mapToArray(map), true) : mapToArray(map);
+ return arrayReduce(array, addMapEntry, new map.constructor);
+ }
+
+ /**
+ * Creates a clone of `regexp`.
+ *
+ * @private
+ * @param {Object} regexp The regexp to clone.
+ * @returns {Object} Returns the cloned regexp.
+ */
+ function cloneRegExp(regexp) {
+ var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
+ result.lastIndex = regexp.lastIndex;
+ return result;
+ }
+
+ /**
+ * Creates a clone of `set`.
+ *
+ * @private
+ * @param {Object} set The set to clone.
+ * @param {Function} cloneFunc The function to clone values.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the cloned set.
+ */
+ function cloneSet(set, isDeep, cloneFunc) {
+ var array = isDeep ? cloneFunc(setToArray(set), true) : setToArray(set);
+ return arrayReduce(array, addSetEntry, new set.constructor);
+ }
+
+ /**
+ * Creates a clone of the `symbol` object.
+ *
+ * @private
+ * @param {Object} symbol The symbol object to clone.
+ * @returns {Object} Returns the cloned symbol object.
+ */
+ function cloneSymbol(symbol) {
+ return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
+ }
+
+ /**
+ * Creates a clone of `typedArray`.
+ *
+ * @private
+ * @param {Object} typedArray The typed array to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the cloned typed array.
+ */
+ function cloneTypedArray(typedArray, isDeep) {
+ var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
+ return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
+ }
+
+ /**
+ * Copies the values of `source` to `array`.
+ *
+ * @private
+ * @param {Array} source The array to copy values from.
+ * @param {Array} [array=[]] The array to copy values to.
+ * @returns {Array} Returns `array`.
+ */
+ function copyArray(source, array) {
+ var index = -1,
+ length = source.length;
+
+ array || (array = Array(length));
+ while (++index < length) {
+ array[index] = source[index];
+ }
+ return array;
+ }
+
+ /**
+ * Copies properties of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy properties from.
+ * @param {Array} props The property identifiers to copy.
+ * @param {Object} [object={}] The object to copy properties to.
+ * @param {Function} [customizer] The function to customize copied values.
+ * @returns {Object} Returns `object`.
+ */
+ function copyObject(source, props, object, customizer) {
+ object || (object = {});
+
+ var index = -1,
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+
+ var newValue = customizer
+ ? customizer(object[key], source[key], key, object, source)
+ : undefined;
+
+ assignValue(object, key, newValue === undefined ? source[key] : newValue);
+ }
+ return object;
+ }
+
+ /**
+ * Copies own symbol properties of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy symbols from.
+ * @param {Object} [object={}] The object to copy symbols to.
+ * @returns {Object} Returns `object`.
+ */
+ function copySymbols(source, object) {
+ return copyObject(source, getSymbols(source), object);
+ }
+
+ /**
+ * Creates a function like `_.assign`.
+ *
+ * @private
+ * @param {Function} assigner The function to assign values.
+ * @returns {Function} Returns the new assigner function.
+ */
+ function createAssigner(assigner) {
+ return baseRest(function(object, sources) {
+ var index = -1,
+ length = sources.length,
+ customizer = length > 1 ? sources[length - 1] : undefined,
+ guard = length > 2 ? sources[2] : undefined;
+
+ customizer = (assigner.length > 3 && typeof customizer == 'function')
+ ? (length--, customizer)
+ : undefined;
+
+ if (guard && isIterateeCall(sources[0], sources[1], guard)) {
+ customizer = length < 3 ? undefined : customizer;
+ length = 1;
+ }
+ object = Object(object);
+ while (++index < length) {
+ var source = sources[index];
+ if (source) {
+ assigner(object, source, index, customizer);
+ }
+ }
+ return object;
+ });
+ }
+
+ /**
+ * Creates an array of own enumerable property names and symbols of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names and symbols.
+ */
+ function getAllKeys(object) {
+ return baseGetAllKeys(object, keys, getSymbols);
+ }
+
+ /**
+ * Gets the data for `map`.
+ *
+ * @private
+ * @param {Object} map The map to query.
+ * @param {string} key The reference key.
+ * @returns {*} Returns the map data.
+ */
+ function getMapData(map, key) {
+ var data = map.__data__;
+ return isKeyable(key)
+ ? data[typeof key == 'string' ? 'string' : 'hash']
+ : data.map;
+ }
+
+ /**
+ * Gets the native function at `key` of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the method to get.
+ * @returns {*} Returns the function if it's native, else `undefined`.
+ */
+ function getNative(object, key) {
+ var value = getValue(object, key);
+ return baseIsNative(value) ? value : undefined;
+ }
+
+ /**
+ * Creates an array of the own enumerable symbol properties of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of symbols.
+ */
+ var getSymbols = nativeGetSymbols ? overArg(nativeGetSymbols, Object) : stubArray;
+
+ /**
+ * Gets the `toStringTag` of `value`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+ var getTag = baseGetTag;
+
+ // Fallback for data views, maps, sets, and weak maps in IE 11,
+ // for data views in Edge < 14, and promises in Node.js.
+ if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
+ (Map && getTag(new Map) != mapTag) ||
+ (Promise && getTag(Promise.resolve()) != promiseTag) ||
+ (Set && getTag(new Set) != setTag) ||
+ (WeakMap && getTag(new WeakMap) != weakMapTag)) {
+ getTag = function(value) {
+ var result = objectToString.call(value),
+ Ctor = result == objectTag ? value.constructor : undefined,
+ ctorString = Ctor ? toSource(Ctor) : undefined;
+
+ if (ctorString) {
+ switch (ctorString) {
+ case dataViewCtorString: return dataViewTag;
+ case mapCtorString: return mapTag;
+ case promiseCtorString: return promiseTag;
+ case setCtorString: return setTag;
+ case weakMapCtorString: return weakMapTag;
+ }
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Initializes an array clone.
+ *
+ * @private
+ * @param {Array} array The array to clone.
+ * @returns {Array} Returns the initialized clone.
+ */
+ function initCloneArray(array) {
+ var length = array.length,
+ result = array.constructor(length);
+
+ // Add properties assigned by `RegExp#exec`.
+ if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
+ result.index = array.index;
+ result.input = array.input;
+ }
+ return result;
+ }
+
+ /**
+ * Initializes an object clone.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneObject(object) {
+ return (typeof object.constructor == 'function' && !isPrototype(object))
+ ? baseCreate(getPrototype(object))
+ : {};
+ }
+
+ /**
+ * Initializes an object clone based on its `toStringTag`.
+ *
+ * **Note:** This function only supports cloning values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @param {string} tag The `toStringTag` of the object to clone.
+ * @param {Function} cloneFunc The function to clone values.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+ function initCloneByTag(object, tag, cloneFunc, isDeep) {
+ var Ctor = object.constructor;
+ switch (tag) {
+ case arrayBufferTag:
+ return cloneArrayBuffer(object);
+
+ case boolTag:
+ case dateTag:
+ return new Ctor(+object);
+
+ case dataViewTag:
+ return cloneDataView(object, isDeep);
+
+ case float32Tag: case float64Tag:
+ case int8Tag: case int16Tag: case int32Tag:
+ case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
+ return cloneTypedArray(object, isDeep);
+
+ case mapTag:
+ return cloneMap(object, isDeep, cloneFunc);
+
+ case numberTag:
+ case stringTag:
+ return new Ctor(object);
+
+ case regexpTag:
+ return cloneRegExp(object);
+
+ case setTag:
+ return cloneSet(object, isDeep, cloneFunc);
+
+ case symbolTag:
+ return cloneSymbol(object);
+ }
+ }
+
+ /**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+ function isIndex(value, length) {
+ length = length == null ? MAX_SAFE_INTEGER : length;
+ return !!length &&
+ (typeof value == 'number' || reIsUint.test(value)) &&
+ (value > -1 && value % 1 == 0 && value < length);
+ }
+
+ /**
+ * Checks if the given arguments are from an iteratee call.
+ *
+ * @private
+ * @param {*} value The potential iteratee value argument.
+ * @param {*} index The potential iteratee index or key argument.
+ * @param {*} object The potential iteratee object argument.
+ * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
+ * else `false`.
+ */
+ function isIterateeCall(value, index, object) {
+ if (!isObject(object)) {
+ return false;
+ }
+ var type = typeof index;
+ if (type == 'number'
+ ? (isArrayLike(object) && isIndex(index, object.length))
+ : (type == 'string' && index in object)
+ ) {
+ return eq(object[index], value);
+ }
+ return false;
+ }
+
+ /**
+ * Checks if `value` is suitable for use as unique object key.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
+ */
+ function isKeyable(value) {
+ var type = typeof value;
+ return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
+ ? (value !== '__proto__')
+ : (value === null);
+ }
+
+ /**
+ * Checks if `func` has its source masked.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` is masked, else `false`.
+ */
+ function isMasked(func) {
+ return !!maskSrcKey && (maskSrcKey in func);
+ }
+
+ /**
+ * Checks if `value` is likely a prototype object.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
+ */
+ function isPrototype(value) {
+ var Ctor = value && value.constructor,
+ proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
+
+ return value === proto;
+ }
+
+ /**
+ * This function is like
+ * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
+ * except that it includes inherited enumerable properties.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+ function nativeKeysIn(object) {
+ var result = [];
+ if (object != null) {
+ for (var key in Object(object)) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Converts `func` to its source code.
+ *
+ * @private
+ * @param {Function} func The function to process.
+ * @returns {string} Returns the source code.
+ */
+ function toSource(func) {
+ if (func != null) {
+ try {
+ return funcToString.call(func);
+ } catch (e) {}
+ try {
+ return (func + '');
+ } catch (e) {}
+ }
+ return '';
+ }
+
+ /**
+ * Performs a
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * comparison between two values to determine if they are equivalent.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'a': 1 };
+ * var other = { 'a': 1 };
+ *
+ * _.eq(object, object);
+ * // => true
+ *
+ * _.eq(object, other);
+ * // => false
+ *
+ * _.eq('a', 'a');
+ * // => true
+ *
+ * _.eq('a', Object('a'));
+ * // => false
+ *
+ * _.eq(NaN, NaN);
+ * // => true
+ */
+ function eq(value, other) {
+ return value === other || (value !== value && other !== other);
+ }
+
+ /**
+ * Checks if `value` is likely an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an `arguments` object,
+ * else `false`.
+ * @example
+ *
+ * _.isArguments(function() { return arguments; }());
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+ function isArguments(value) {
+ // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
+ return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&
+ (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);
+ }
+
+ /**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * _.isArray(document.body.children);
+ * // => false
+ *
+ * _.isArray('abc');
+ * // => false
+ *
+ * _.isArray(_.noop);
+ * // => false
+ */
+ var isArray = Array.isArray;
+
+ /**
+ * Checks if `value` is array-like. A value is considered array-like if it's
+ * not a function and has a `value.length` that's an integer greater than or
+ * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+ * @example
+ *
+ * _.isArrayLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLike(document.body.children);
+ * // => true
+ *
+ * _.isArrayLike('abc');
+ * // => true
+ *
+ * _.isArrayLike(_.noop);
+ * // => false
+ */
+ function isArrayLike(value) {
+ return value != null && isLength(value.length) && !isFunction(value);
+ }
+
+ /**
+ * This method is like `_.isArrayLike` except that it also checks if `value`
+ * is an object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array-like object,
+ * else `false`.
+ * @example
+ *
+ * _.isArrayLikeObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLikeObject(document.body.children);
+ * // => true
+ *
+ * _.isArrayLikeObject('abc');
+ * // => false
+ *
+ * _.isArrayLikeObject(_.noop);
+ * // => false
+ */
+ function isArrayLikeObject(value) {
+ return isObjectLike(value) && isArrayLike(value);
+ }
+
+ /**
+ * Checks if `value` is a buffer.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.3.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
+ * @example
+ *
+ * _.isBuffer(new Buffer(2));
+ * // => true
+ *
+ * _.isBuffer(new Uint8Array(2));
+ * // => false
+ */
+ var isBuffer = nativeIsBuffer || stubFalse;
+
+ /**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a function, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+ function isFunction(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in Safari 8-9 which returns 'object' for typed array and other constructors.
+ var tag = isObject(value) ? objectToString.call(value) : '';
+ return tag == funcTag || tag == genTag;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This method is loosely based on
+ * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ * @example
+ *
+ * _.isLength(3);
+ * // => true
+ *
+ * _.isLength(Number.MIN_VALUE);
+ * // => false
+ *
+ * _.isLength(Infinity);
+ * // => false
+ *
+ * _.isLength('3');
+ * // => false
+ */
+ function isLength(value) {
+ return typeof value == 'number' &&
+ value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+ }
+
+ /**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+ function isObject(value) {
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+ }
+
+ /**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+ function isObjectLike(value) {
+ return !!value && typeof value == 'object';
+ }
+
+ /**
+ * Checks if `value` is a plain object, that is, an object created by the
+ * `Object` constructor or one with a `[[Prototype]]` of `null`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.8.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * }
+ *
+ * _.isPlainObject(new Foo);
+ * // => false
+ *
+ * _.isPlainObject([1, 2, 3]);
+ * // => false
+ *
+ * _.isPlainObject({ 'x': 0, 'y': 0 });
+ * // => true
+ *
+ * _.isPlainObject(Object.create(null));
+ * // => true
+ */
+ function isPlainObject(value) {
+ if (!isObjectLike(value) ||
+ objectToString.call(value) != objectTag || isHostObject(value)) {
+ return false;
+ }
+ var proto = getPrototype(value);
+ if (proto === null) {
+ return true;
+ }
+ var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
+ return (typeof Ctor == 'function' &&
+ Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString);
+ }
+
+ /**
+ * Checks if `value` is classified as a typed array.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
+ * @example
+ *
+ * _.isTypedArray(new Uint8Array);
+ * // => true
+ *
+ * _.isTypedArray([]);
+ * // => false
+ */
+ var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;
+
+ /**
+ * Converts `value` to a plain object flattening inherited enumerable string
+ * keyed properties of `value` to own properties of the plain object.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {Object} Returns the converted plain object.
+ * @example
+ *
+ * function Foo() {
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.assign({ 'a': 1 }, new Foo);
+ * // => { 'a': 1, 'b': 2 }
+ *
+ * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
+ * // => { 'a': 1, 'b': 2, 'c': 3 }
+ */
+ function toPlainObject(value) {
+ return copyObject(value, keysIn(value));
+ }
+
+ /**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @since 0.1.0
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+ function keys(object) {
+ return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
+ }
+
+ /**
+ * Creates an array of the own and inherited enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keysIn(new Foo);
+ * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
+ */
+ function keysIn(object) {
+ return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
+ }
+
+ /**
+ * This method is like `_.assign` except that it recursively merges own and
+ * inherited enumerable string keyed properties of source objects into the
+ * destination object. Source properties that resolve to `undefined` are
+ * skipped if a destination value exists. Array and plain object properties
+ * are merged recursively. Other objects and value types are overridden by
+ * assignment. Source objects are applied from left to right. Subsequent
+ * sources overwrite property assignments of previous sources.
+ *
+ * **Note:** This method mutates `object`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.5.0
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * var object = {
+ * 'a': [{ 'b': 2 }, { 'd': 4 }]
+ * };
+ *
+ * var other = {
+ * 'a': [{ 'c': 3 }, { 'e': 5 }]
+ * };
+ *
+ * _.merge(object, other);
+ * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
+ */
+ var merge = createAssigner(function(object, source, srcIndex) {
+ baseMerge(object, source, srcIndex);
+ });
+
+ /**
+ * This method returns a new empty array.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.13.0
+ * @category Util
+ * @returns {Array} Returns the new empty array.
+ * @example
+ *
+ * var arrays = _.times(2, _.stubArray);
+ *
+ * console.log(arrays);
+ * // => [[], []]
+ *
+ * console.log(arrays[0] === arrays[1]);
+ * // => false
+ */
+ function stubArray() {
+ return [];
+ }
+
+ /**
+ * This method returns `false`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.13.0
+ * @category Util
+ * @returns {boolean} Returns `false`.
+ * @example
+ *
+ * _.times(2, _.stubFalse);
+ * // => [false, false]
+ */
+ function stubFalse() {
+ return false;
+ }
+
+ module.exports = merge;
+
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(33)(module)))
+
+/***/ },
+/* 33 */
+/***/ function(module, exports) {
+
+ module.exports = function(module) {
+ if(!module.webpackPolyfill) {
+ module.deprecate = function() {};
+ module.paths = [];
+ // module.parent = undefined by default
+ module.children = [];
+ module.webpackPolyfill = 1;
+ }
+ return module;
+ }
+
+
+/***/ },
+/* 34 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(25)();
+ // imports
+
+
+ // module
+ exports.push([module.id, ".media-control-notransition {\n -webkit-transition: none !important;\n -moz-transition: none !important;\n transition: none !important; }\n\n.media-control[data-media-control] {\n position: absolute;\n width: 100%;\n height: 100%;\n z-index: 9999;\n pointer-events: none; }\n .media-control[data-media-control].dragging {\n pointer-events: auto;\n cursor: -webkit-grabbing !important;\n cursor: grabbing !important;\n cursor: url(" + __webpack_require__(35) + "), move; }\n .media-control[data-media-control].dragging * {\n cursor: -webkit-grabbing !important;\n cursor: grabbing !important;\n cursor: url(" + __webpack_require__(35) + "), move; }\n .media-control[data-media-control] .media-control-background[data-background] {\n position: absolute;\n height: 40%;\n width: 100%;\n bottom: 0;\n background: -webkit-linear-gradient(transparent, rgba(0, 0, 0, 0.9));\n background: linear-gradient(transparent, rgba(0, 0, 0, 0.9));\n -webkit-transition: opacity 0.6s ease-out;\n -moz-transition: opacity 0.6s ease-out;\n transition: opacity 0.6s ease-out; }\n .media-control[data-media-control] .media-control-icon {\n line-height: 0;\n letter-spacing: 0;\n speak: none;\n color: #fff;\n opacity: 0.5;\n vertical-align: middle;\n text-align: left;\n -webkit-transition: all 0.1s ease;\n -moz-transition: all 0.1s ease;\n transition: all 0.1s ease; }\n .media-control[data-media-control] .media-control-icon:hover {\n color: white;\n opacity: 0.75;\n text-shadow: rgba(255, 255, 255, 0.8) 0 0 5px; }\n .media-control[data-media-control].media-control-hide .media-control-background[data-background] {\n opacity: 0; }\n .media-control[data-media-control].media-control-hide .media-control-layer[data-controls] {\n bottom: -50px; }\n .media-control[data-media-control].media-control-hide .media-control-layer[data-controls] .bar-container[data-seekbar] .bar-scrubber[data-seekbar] {\n opacity: 0; }\n .media-control[data-media-control] .media-control-layer[data-controls] {\n position: absolute;\n bottom: 7px;\n width: 100%;\n height: 32px;\n font-size: 0;\n vertical-align: middle;\n pointer-events: auto;\n -webkit-transition: bottom 0.4s ease-out;\n -moz-transition: bottom 0.4s ease-out;\n transition: bottom 0.4s ease-out; }\n .media-control[data-media-control] .media-control-layer[data-controls] .media-control-left-panel[data-media-control] {\n position: absolute;\n top: 0;\n left: 4px;\n height: 100%; }\n .media-control[data-media-control] .media-control-layer[data-controls] .media-control-center-panel[data-media-control] {\n height: 100%;\n text-align: center;\n line-height: 32px; }\n .media-control[data-media-control] .media-control-layer[data-controls] .media-control-right-panel[data-media-control] {\n position: absolute;\n top: 0;\n right: 4px;\n height: 100%; }\n .media-control[data-media-control] .media-control-layer[data-controls] button.media-control-button {\n background-color: transparent;\n border: 0;\n margin: 0 6px;\n padding: 0;\n cursor: pointer;\n display: inline-block;\n width: 32px;\n height: 100%; }\n .media-control[data-media-control] .media-control-layer[data-controls] button.media-control-button svg {\n width: 100%;\n height: 22px; }\n .media-control[data-media-control] .media-control-layer[data-controls] button.media-control-button svg path {\n fill: white; }\n .media-control[data-media-control] .media-control-layer[data-controls] button.media-control-button:focus {\n outline: none; }\n .media-control[data-media-control] .media-control-layer[data-controls] button.media-control-button[data-play] {\n float: left;\n height: 100%; }\n .media-control[data-media-control] .media-control-layer[data-controls] button.media-control-button[data-pause] {\n float: left;\n height: 100%; }\n .media-control[data-media-control] .media-control-layer[data-controls] button.media-control-button[data-stop] {\n float: left;\n height: 100%; }\n .media-control[data-media-control] .media-control-layer[data-controls] button.media-control-button[data-fullscreen] {\n float: right;\n background-color: transparent;\n border: 0;\n height: 100%; }\n .media-control[data-media-control] .media-control-layer[data-controls] button.media-control-button[data-hd-indicator] {\n cursor: default;\n float: right;\n background-color: transparent;\n border: 0;\n height: 100%;\n display: none; }\n .media-control[data-media-control] .media-control-layer[data-controls] button.media-control-button[data-hd-indicator].enabled {\n opacity: 1.0;\n display: block; }\n .media-control[data-media-control] .media-control-layer[data-controls] button.media-control-button[data-hd-indicator].enabled:hover {\n opacity: 1.0;\n text-shadow: none; }\n .media-control[data-media-control] .media-control-layer[data-controls] button.media-control-button[data-playpause] {\n float: left; }\n .media-control[data-media-control] .media-control-layer[data-controls] button.media-control-button[data-playstop] {\n float: left; }\n .media-control[data-media-control] .media-control-layer[data-controls] .media-control-indicator[data-position], .media-control[data-media-control] .media-control-layer[data-controls] .media-control-indicator[data-duration] {\n display: inline-block;\n font-size: 10px;\n color: white;\n cursor: default;\n line-height: 32px;\n position: relative; }\n .media-control[data-media-control] .media-control-layer[data-controls] .media-control-indicator[data-position] {\n margin: 0 6px 0 7px; }\n .media-control[data-media-control] .media-control-layer[data-controls] .media-control-indicator[data-duration] {\n color: rgba(255, 255, 255, 0.5);\n margin-right: 6px; }\n .media-control[data-media-control] .media-control-layer[data-controls] .media-control-indicator[data-duration]:before {\n content: \"|\";\n margin-right: 7px; }\n .media-control[data-media-control] .media-control-layer[data-controls] .bar-container[data-seekbar] {\n position: absolute;\n top: -20px;\n left: 0;\n display: inline-block;\n vertical-align: middle;\n width: 100%;\n height: 25px;\n cursor: pointer; }\n .media-control[data-media-control] .media-control-layer[data-controls] .bar-container[data-seekbar] .bar-background[data-seekbar] {\n width: 100%;\n height: 1px;\n position: relative;\n top: 12px;\n background-color: #666666; }\n .media-control[data-media-control] .media-control-layer[data-controls] .bar-container[data-seekbar] .bar-background[data-seekbar] .bar-fill-1[data-seekbar] {\n position: absolute;\n top: 0;\n left: 0;\n width: 0;\n height: 100%;\n background-color: #c2c2c2;\n -webkit-transition: all 0.1s ease-out;\n -moz-transition: all 0.1s ease-out;\n transition: all 0.1s ease-out; }\n .media-control[data-media-control] .media-control-layer[data-controls] .bar-container[data-seekbar] .bar-background[data-seekbar] .bar-fill-2[data-seekbar] {\n position: absolute;\n top: 0;\n left: 0;\n width: 0;\n height: 100%;\n background-color: #005aff;\n -webkit-transition: all 0.1s ease-out;\n -moz-transition: all 0.1s ease-out;\n transition: all 0.1s ease-out; }\n .media-control[data-media-control] .media-control-layer[data-controls] .bar-container[data-seekbar] .bar-background[data-seekbar] .bar-hover[data-seekbar] {\n opacity: 0;\n position: absolute;\n top: -3px;\n width: 5px;\n height: 7px;\n background-color: rgba(255, 255, 255, 0.5);\n -webkit-transition: opacity 0.1s ease;\n -moz-transition: opacity 0.1s ease;\n transition: opacity 0.1s ease; }\n .media-control[data-media-control] .media-control-layer[data-controls] .bar-container[data-seekbar]:hover .bar-background[data-seekbar] .bar-hover[data-seekbar] {\n opacity: 1; }\n .media-control[data-media-control] .media-control-layer[data-controls] .bar-container[data-seekbar].seek-disabled {\n cursor: default; }\n .media-control[data-media-control] .media-control-layer[data-controls] .bar-container[data-seekbar].seek-disabled:hover .bar-background[data-seekbar] .bar-hover[data-seekbar] {\n opacity: 0; }\n .media-control[data-media-control] .media-control-layer[data-controls] .bar-container[data-seekbar] .bar-scrubber[data-seekbar] {\n position: absolute;\n -webkit-transform: translateX(-50%);\n -moz-transform: translateX(-50%);\n -ms-transform: translateX(-50%);\n -o-transform: translateX(-50%);\n transform: translateX(-50%);\n top: 2px;\n left: 0;\n width: 20px;\n height: 20px;\n opacity: 1;\n -webkit-transition: all 0.1s ease-out;\n -moz-transition: all 0.1s ease-out;\n transition: all 0.1s ease-out; }\n .media-control[data-media-control] .media-control-layer[data-controls] .bar-container[data-seekbar] .bar-scrubber[data-seekbar] .bar-scrubber-icon[data-seekbar] {\n position: absolute;\n left: 6px;\n top: 6px;\n width: 8px;\n height: 8px;\n border-radius: 10px;\n box-shadow: 0 0 0 6px rgba(255, 255, 255, 0.2);\n background-color: white; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] {\n float: right;\n display: inline-block;\n height: 32px;\n cursor: pointer;\n margin: 0 6px;\n box-sizing: border-box; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .drawer-icon-container[data-volume] {\n float: left;\n bottom: 0; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .drawer-icon-container[data-volume] .drawer-icon[data-volume] {\n background-color: transparent;\n border: 0;\n box-sizing: content-box;\n width: 32px;\n height: 32px;\n opacity: 0.5; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .drawer-icon-container[data-volume] .drawer-icon[data-volume]:hover {\n opacity: 0.75; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .drawer-icon-container[data-volume] .drawer-icon[data-volume] svg {\n height: 24px;\n position: relative;\n top: 3px; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .drawer-icon-container[data-volume] .drawer-icon[data-volume] svg path {\n fill: white; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .drawer-icon-container[data-volume] .drawer-icon[data-volume].muted svg {\n margin-left: 2px; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .bar-container[data-volume] {\n float: left;\n position: relative;\n overflow: hidden;\n top: 6px;\n width: 42px;\n height: 18px;\n padding: 3px 0;\n -webkit-transition: width 0.2s ease-out;\n -moz-transition: width 0.2s ease-out;\n transition: width 0.2s ease-out; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .bar-container[data-volume] .bar-background[data-volume] {\n height: 1px;\n position: relative;\n top: 7px;\n margin: 0 3px;\n background-color: #666666; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .bar-container[data-volume] .bar-background[data-volume] .bar-fill-1[data-volume] {\n position: absolute;\n top: 0;\n left: 0;\n width: 0;\n height: 100%;\n background-color: #c2c2c2;\n -webkit-transition: all 0.1s ease-out;\n -moz-transition: all 0.1s ease-out;\n transition: all 0.1s ease-out; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .bar-container[data-volume] .bar-background[data-volume] .bar-fill-2[data-volume] {\n position: absolute;\n top: 0;\n left: 0;\n width: 0;\n height: 100%;\n background-color: #005aff;\n -webkit-transition: all 0.1s ease-out;\n -moz-transition: all 0.1s ease-out;\n transition: all 0.1s ease-out; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .bar-container[data-volume] .bar-background[data-volume] .bar-hover[data-volume] {\n opacity: 0;\n position: absolute;\n top: -3px;\n width: 5px;\n height: 7px;\n background-color: rgba(255, 255, 255, 0.5);\n -webkit-transition: opacity 0.1s ease;\n -moz-transition: opacity 0.1s ease;\n transition: opacity 0.1s ease; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .bar-container[data-volume] .bar-scrubber[data-volume] {\n position: absolute;\n -webkit-transform: translateX(-50%);\n -moz-transform: translateX(-50%);\n -ms-transform: translateX(-50%);\n -o-transform: translateX(-50%);\n transform: translateX(-50%);\n top: 0px;\n left: 0;\n width: 20px;\n height: 20px;\n opacity: 1;\n -webkit-transition: all 0.1s ease-out;\n -moz-transition: all 0.1s ease-out;\n transition: all 0.1s ease-out; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .bar-container[data-volume] .bar-scrubber[data-volume] .bar-scrubber-icon[data-volume] {\n position: absolute;\n left: 6px;\n top: 6px;\n width: 8px;\n height: 8px;\n border-radius: 10px;\n box-shadow: 0 0 0 6px rgba(255, 255, 255, 0.2);\n background-color: white; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .bar-container[data-volume] .segmented-bar-element[data-volume] {\n float: left;\n width: 4px;\n padding-left: 2px;\n height: 12px;\n opacity: 0.5;\n box-shadow: inset 2px 0 0 white;\n -webkit-transition: -webkit-transform 0.2s ease-out;\n -moz-transition: -moz-transform 0.2s ease-out;\n transition: transform 0.2s ease-out; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .bar-container[data-volume] .segmented-bar-element[data-volume].fill {\n box-shadow: inset 2px 0 0 #fff;\n opacity: 1; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .bar-container[data-volume] .segmented-bar-element[data-volume]:nth-of-type(1) {\n padding-left: 0; }\n .media-control[data-media-control] .media-control-layer[data-controls] .drawer-container[data-volume] .bar-container[data-volume] .segmented-bar-element[data-volume]:hover {\n -webkit-transform: scaleY(1.5);\n -moz-transform: scaleY(1.5);\n -ms-transform: scaleY(1.5);\n -o-transform: scaleY(1.5);\n transform: scaleY(1.5); }\n .media-control[data-media-control].w320 .media-control-layer[data-controls] .drawer-container[data-volume] .bar-container[data-volume].volume-bar-hide {\n width: 0;\n height: 12px;\n top: 9px;\n padding: 0; }\n", ""]);
+
+ // exports
+
+
+/***/ },
+/* 35 */
+/***/ function(module, exports, __webpack_require__) {
+
+ module.exports = __webpack_require__.p + "a8c874b93b3d848f39a71260c57e3863.cur";
+
+/***/ },
+/* 36 */
+/***/ function(module, exports) {
+
+ module.exports = "<div class=\"media-control-background\" data-background></div>\n<div class=\"media-control-layer\" data-controls>\n <% var renderBar = function(name) { %>\n <div class=\"bar-container\" data-<%= name %>>\n <div class=\"bar-background\" data-<%= name %>>\n <div class=\"bar-fill-1\" data-<%= name %>></div>\n <div class=\"bar-fill-2\" data-<%= name %>></div>\n <div class=\"bar-hover\" data-<%= name %>></div>\n </div>\n <div class=\"bar-scrubber\" data-<%= name %>>\n <div class=\"bar-scrubber-icon\" data-<%= name %>></div>\n </div>\n </div>\n <% }; %>\n <% var renderSegmentedBar = function(name, segments) {\n segments = segments || 10; %>\n <div class=\"bar-container\" data-<%= name %>>\n <% for (var i = 0; i < segments; i++) { %>\n <div class=\"segmented-bar-element\" data-<%= name %>></div>\n <% } %>\n </div>\n <% }; %>\n <% var renderDrawer = function(name, renderContent) { %>\n <div class=\"drawer-container\" data-<%= name %>>\n <div class=\"drawer-icon-container\" data-<%= name %>>\n <div class=\"drawer-icon media-control-icon\" data-<%= name %>></div>\n <span class=\"drawer-text\" data-<%= name %>></span>\n </div>\n <% renderContent(name); %>\n </div>\n <% }; %>\n <% var renderIndicator = function(name) { %>\n <div class=\"media-control-indicator\" data-<%= name %>></div>\n <% }; %>\n <% var renderButton = function(name) { %>\n <button type=\"button\" class=\"media-control-button media-control-icon\" data-<%= name %>></button>\n <% }; %>\n <% var templates = {\n bar: renderBar,\n segmentedBar: renderSegmentedBar,\n };\n var render = function(settingsList) {\n settingsList.forEach(function(setting) {\n if(setting === \"seekbar\") {\n renderBar(setting);\n } else if (setting === \"volume\") {\n renderDrawer(setting, settings.volumeBarTemplate ? templates[settings.volumeBarTemplate] : function(name) { return renderSegmentedBar(name); });\n } else if (setting === \"duration\" || setting === \"position\") {\n renderIndicator(setting);\n } else {\n renderButton(setting);\n }\n });\n }; %>\n <% if (settings.default && settings.default.length) { %>\n <div class=\"media-control-center-panel\" data-media-control>\n <% render(settings.default); %>\n </div>\n <% } %>\n <% if (settings.left && settings.left.length) { %>\n <div class=\"media-control-left-panel\" data-media-control>\n <% render(settings.left); %>\n </div>\n <% } %>\n <% if (settings.right && settings.right.length) { %>\n <div class=\"media-control-right-panel\" data-media-control>\n <% render(settings.right); %>\n </div>\n <% } %>\n</div>\n";
+
+/***/ },
+/* 37 */
+/***/ function(module, exports) {
+
+ module.exports = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\"><path fill=\"#010101\" d=\"M1.425.35L14.575 8l-13.15 7.65V.35z\"></path></svg>"
+
+/***/ },
+/* 38 */
+/***/ function(module, exports) {
+
+ module.exports = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" fill=\"#010101\" d=\"M1.712 14.76H6.43V1.24H1.71v13.52zm7.86-13.52v13.52h4.716V1.24H9.573z\"></path></svg>"
+
+/***/ },
+/* 39 */
+/***/ function(module, exports) {
+
+ module.exports = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" fill=\"#010101\" d=\"M1.712 1.24h12.6v13.52h-12.6z\"></path></svg>"
+
+/***/ },
+/* 40 */
+/***/ function(module, exports) {
+
+ module.exports = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" fill=\"#010101\" d=\"M11.5 11h-.002v1.502L7.798 10H4.5V6h3.297l3.7-2.502V4.5h.003V11zM11 4.49L7.953 6.5H5v3h2.953L11 11.51V4.49z\"></path></svg>"
+
+/***/ },
+/* 41 */
+/***/ function(module, exports) {
+
+ module.exports = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" fill=\"#010101\" d=\"M9.75 11.51L6.7 9.5H3.75v-3H6.7L9.75 4.49v.664l.497.498V3.498L6.547 6H3.248v4h3.296l3.7 2.502v-2.154l-.497.5v.662zm3-5.165L12.404 6l-1.655 1.653L9.093 6l-.346.345L10.402 8 8.747 9.654l.346.347 1.655-1.653L12.403 10l.348-.346L11.097 8l1.655-1.655z\"></path></svg>"
+
+/***/ },
+/* 42 */
+/***/ function(module, exports) {
+
+ module.exports = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\"><path fill=\"#010101\" d=\"M7.156 8L4 11.156V8.5H3V13h4.5v-1H4.844L8 8.844 7.156 8zM8.5 3v1h2.657L8 7.157 8.846 8 12 4.844V7.5h1V3H8.5z\"></path></svg>"
+
+/***/ },
+/* 43 */
+/***/ function(module, exports) {
+
+ module.exports = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\"><path fill=\"#010101\" d=\"M13.5 3.344l-.844-.844L9.5 5.656V3h-1v4.5H13v-1h-2.656L13.5 3.344zM3 9.5h2.656L2.5 12.656l.844.844L6.5 10.344V13h1V8.5H3v1z\"></path></svg>"
+
+/***/ },
+/* 44 */
+/***/ function(module, exports) {
+
+ module.exports = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\"><path fill=\"#010101\" d=\"M5.375 7.062H2.637V4.26H.502v7.488h2.135V8.9h2.738v2.848h2.133V4.26H5.375v2.802zm5.97-2.81h-2.84v7.496h2.798c2.65 0 4.195-1.607 4.195-3.77v-.022c0-2.162-1.523-3.704-4.154-3.704zm2.06 3.758c0 1.21-.81 1.896-2.03 1.896h-.83V6.093h.83c1.22 0 2.03.696 2.03 1.896v.02z\"></path></svg>"
+
+/***/ },
+/* 45 */
+/***/ function(module, exports) {
+
+ "use strict";
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var PlayerInfo = function PlayerInfo() {
+ _classCallCheck(this, PlayerInfo);
+
+ this.options = {};
+ this.playbackPlugins = [];
+ this.currentSize = { width: 0, height: 0 };
+ };
+
+ PlayerInfo._players = {};
+
+ PlayerInfo.getInstance = function (playerId) {
+ return PlayerInfo._players[playerId] || (PlayerInfo._players[playerId] = new PlayerInfo());
+ };
+
+ exports.default = PlayerInfo;
+ module.exports = exports["default"];
+
+/***/ },
+/* 46 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(25)();
+ // imports
+
+
+ // module
+ exports.push([module.id, "@font-face {\n font-family: \"Roboto\";\n font-style: normal;\n font-weight: 400;\n src: local(\"Roboto\"), local(\"Roboto-Regular\"), url(" + __webpack_require__(47) + ") format(\"truetype\"); }\n\n[data-player] {\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -khtml-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n -o-user-select: none;\n user-select: none;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n -webkit-transform: translate3d(0, 0, 0);\n -moz-transform: translate3d(0, 0, 0);\n -ms-transform: translate3d(0, 0, 0);\n -o-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n position: relative;\n margin: 0;\n padding: 0;\n border: 0;\n font-style: normal;\n font-weight: normal;\n text-align: center;\n overflow: hidden;\n font-size: 100%;\n font-family: \"Roboto\", \"Open Sans\", Arial, sans-serif;\n text-shadow: 0 0 0;\n box-sizing: border-box; }\n [data-player] div, [data-player] span, [data-player] applet, [data-player] object, [data-player] iframe,\n [data-player] h1, [data-player] h2, [data-player] h3, [data-player] h4, [data-player] h5, [data-player] h6, [data-player] p, [data-player] blockquote, [data-player] pre,\n [data-player] a, [data-player] abbr, [data-player] acronym, [data-player] address, [data-player] big, [data-player] cite, [data-player] code,\n [data-player] del, [data-player] dfn, [data-player] em, [data-player] img, [data-player] ins, [data-player] kbd, [data-player] q, [data-player] s, [data-player] samp,\n [data-player] small, [data-player] strike, [data-player] strong, [data-player] sub, [data-player] sup, [data-player] tt, [data-player] var,\n [data-player] b, [data-player] u, [data-player] i, [data-player] center,\n [data-player] dl, [data-player] dt, [data-player] dd, [data-player] ol, [data-player] ul, [data-player] li,\n [data-player] fieldset, [data-player] form, [data-player] label, [data-player] legend,\n [data-player] table, [data-player] caption, [data-player] tbody, [data-player] tfoot, [data-player] thead, [data-player] tr, [data-player] th, [data-player] td,\n [data-player] article, [data-player] aside, [data-player] canvas, [data-player] details, [data-player] embed,\n [data-player] figure, [data-player] figcaption, [data-player] footer, [data-player] header, [data-player] hgroup,\n [data-player] menu, [data-player] nav, [data-player] output, [data-player] ruby, [data-player] section, [data-player] summary,\n [data-player] time, [data-player] mark, [data-player] audio, [data-player] video {\n margin: 0;\n padding: 0;\n border: 0;\n font: inherit;\n font-size: 100%;\n vertical-align: baseline; }\n [data-player] table {\n border-collapse: collapse;\n border-spacing: 0; }\n [data-player] caption, [data-player] th, [data-player] td {\n text-align: left;\n font-weight: normal;\n vertical-align: middle; }\n [data-player] q, [data-player] blockquote {\n quotes: none; }\n [data-player] q:before, [data-player] q:after, [data-player] blockquote:before, [data-player] blockquote:after {\n content: \"\";\n content: none; }\n [data-player] a img {\n border: none; }\n [data-player]:focus {\n outline: 0; }\n [data-player] * {\n max-width: none;\n box-sizing: inherit;\n float: none; }\n [data-player] div {\n display: block; }\n [data-player].fullscreen {\n width: 100% !important;\n height: 100% !important;\n top: 0;\n left: 0; }\n [data-player].nocursor {\n cursor: none; }\n\n.clappr-style {\n display: none !important; }\n", ""]);
+
+ // exports
+
+
+/***/ },
+/* 47 */
+/***/ function(module, exports, __webpack_require__) {
+
+ module.exports = __webpack_require__.p + "38861cba61c66739c1452c3a71e39852.ttf";
+
+/***/ },
+/* 48 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(49);
+
+/***/ },
+/* 49 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _base_object = __webpack_require__(4);
+
+ var _base_object2 = _interopRequireDefault(_base_object);
+
+ var _player_info = __webpack_require__(45);
+
+ var _player_info2 = _interopRequireDefault(_player_info);
+
+ var _lodash = __webpack_require__(50);
+
+ var _lodash2 = _interopRequireDefault(_lodash);
+
+ var _html5_video = __webpack_require__(51);
+
+ var _html5_video2 = _interopRequireDefault(_html5_video);
+
+ var _flash = __webpack_require__(54);
+
+ var _flash2 = _interopRequireDefault(_flash);
+
+ var _html5_audio = __webpack_require__(61);
+
+ var _html5_audio2 = _interopRequireDefault(_html5_audio);
+
+ var _flashls = __webpack_require__(63);
+
+ var _flashls2 = _interopRequireDefault(_flashls);
+
+ var _hls = __webpack_require__(67);
+
+ var _hls2 = _interopRequireDefault(_hls);
+
+ var _html_img = __webpack_require__(71);
+
+ var _html_img2 = _interopRequireDefault(_html_img);
+
+ var _no_op = __webpack_require__(74);
+
+ var _no_op2 = _interopRequireDefault(_no_op);
+
+ var _spinner_three_bounce = __webpack_require__(78);
+
+ var _spinner_three_bounce2 = _interopRequireDefault(_spinner_three_bounce);
+
+ var _stats = __webpack_require__(83);
+
+ var _stats2 = _interopRequireDefault(_stats);
+
+ var _watermark = __webpack_require__(86);
+
+ var _watermark2 = _interopRequireDefault(_watermark);
+
+ var _poster = __webpack_require__(90);
+
+ var _poster2 = _interopRequireDefault(_poster);
+
+ var _google_analytics = __webpack_require__(94);
+
+ var _google_analytics2 = _interopRequireDefault(_google_analytics);
+
+ var _click_to_pause = __webpack_require__(96);
+
+ var _click_to_pause2 = _interopRequireDefault(_click_to_pause);
+
+ var _dvr_controls = __webpack_require__(98);
+
+ var _dvr_controls2 = _interopRequireDefault(_dvr_controls);
+
+ var _favicon = __webpack_require__(103);
+
+ var _favicon2 = _interopRequireDefault(_favicon);
+
+ var _seek_time = __webpack_require__(106);
+
+ var _seek_time2 = _interopRequireDefault(_seek_time);
+
+ var _sources = __webpack_require__(110);
+
+ var _sources2 = _interopRequireDefault(_sources);
+
+ var _end_video = __webpack_require__(111);
+
+ var _end_video2 = _interopRequireDefault(_end_video);
+
+ var _strings = __webpack_require__(112);
+
+ var _strings2 = _interopRequireDefault(_strings);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ /* Playback Plugins */
+
+
+ /* Container Plugins */
+
+
+ /* Core Plugins */
+
+
+ /**
+ * It keeps a list of the default plugins (playback, container, core) and it merges external plugins with its internals.
+ * @class Loader
+ * @constructor
+ * @extends BaseObject
+ * @module components
+ */
+ var Loader = function (_BaseObject) {
+ _inherits(Loader, _BaseObject);
+
+ /**
+ * builds the loader
+ * @method constructor
+ * @param {Object} externalPlugins the external plugins
+ * @param {Number} playerId you can embed multiple instances of clappr, therefore this is the unique id of each one.
+ */
+ function Loader(externalPlugins, playerId) {
+ _classCallCheck(this, Loader);
+
+ var _this = _possibleConstructorReturn(this, _BaseObject.call(this));
+
+ _this.playerId = playerId;
+ _this.playbackPlugins = [_hls2.default, _html5_video2.default, _html5_audio2.default, _flash2.default, _flashls2.default, _html_img2.default, _no_op2.default];
+ _this.containerPlugins = [_spinner_three_bounce2.default, _watermark2.default, _poster2.default, _stats2.default, _google_analytics2.default, _click_to_pause2.default];
+ _this.corePlugins = [_dvr_controls2.default, _favicon2.default, _seek_time2.default, _sources2.default, _end_video2.default, _strings2.default];
+ if (externalPlugins) {
+ if (!Array.isArray(externalPlugins)) {
+ _this.validateExternalPluginsType(externalPlugins);
+ }
+ _this.addExternalPlugins(externalPlugins);
+ }
+ return _this;
+ }
+
+ /**
+ * groups by type the external plugins that were passed through `options.plugins` it they're on a flat array
+ * @method addExternalPlugins
+ * @private
+ * @param {Object} an config object or an array of plugins
+ * @return {Object} plugins the config object with the plugins separated by type
+ */
+
+
+ Loader.prototype.groupPluginsByType = function groupPluginsByType(plugins) {
+ if (Array.isArray(plugins)) {
+ plugins = plugins.reduce(function (memo, plugin) {
+ memo[plugin.type] || (memo[plugin.type] = []);
+ memo[plugin.type].push(plugin);
+ return memo;
+ }, {});
+ }
+ return plugins;
+ };
+
+ /**
+ * adds all the external plugins that were passed through `options.plugins`
+ * @method addExternalPlugins
+ * @private
+ * @param {Object} plugins the config object with all plugins
+ */
+
+
+ Loader.prototype.addExternalPlugins = function addExternalPlugins(plugins) {
+ plugins = this.groupPluginsByType(plugins);
+ var pluginName = function pluginName(plugin) {
+ return plugin.prototype.name;
+ };
+ if (plugins.playback) {
+ this.playbackPlugins = (0, _lodash2.default)(plugins.playback.concat(this.playbackPlugins), pluginName);
+ }
+ if (plugins.container) {
+ this.containerPlugins = (0, _lodash2.default)(plugins.container.concat(this.containerPlugins), pluginName);
+ }
+ if (plugins.core) {
+ this.corePlugins = (0, _lodash2.default)(plugins.core.concat(this.corePlugins), pluginName);
+ }
+ _player_info2.default.getInstance(this.playerId).playbackPlugins = this.playbackPlugins;
+ };
+
+ /**
+ * validate if the external plugins that were passed through `options.plugins` are associated to the correct type
+ * @method validateExternalPluginsType
+ * @private
+ * @param {Object} plugins the config object with all plugins
+ */
+
+
+ Loader.prototype.validateExternalPluginsType = function validateExternalPluginsType(plugins) {
+ var plugintypes = ['playback', 'container', 'core'];
+ plugintypes.forEach(function (type) {
+ (plugins[type] || []).forEach(function (el) {
+ var errorMessage = 'external ' + el.type + ' plugin on ' + type + ' array';
+ if (el.type !== type) {
+ throw new ReferenceError(errorMessage);
+ }
+ });
+ });
+ };
+
+ return Loader;
+ }(_base_object2.default);
+
+ exports.default = Loader;
+ module.exports = exports['default'];
+
+/***/ },
+/* 50 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /* WEBPACK VAR INJECTION */(function(global, module) {/**
+ * lodash (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors <https://jquery.org/>
+ * Released under MIT license <https://lodash.com/license>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+
+ /** Used as the size to enable large array optimizations. */
+ var LARGE_ARRAY_SIZE = 200;
+
+ /** Used as the `TypeError` message for "Functions" methods. */
+ var FUNC_ERROR_TEXT = 'Expected a function';
+
+ /** Used to stand-in for `undefined` hash values. */
+ var HASH_UNDEFINED = '__lodash_hash_undefined__';
+
+ /** Used to compose bitmasks for comparison styles. */
+ var UNORDERED_COMPARE_FLAG = 1,
+ PARTIAL_COMPARE_FLAG = 2;
+
+ /** Used as references for various `Number` constants. */
+ var INFINITY = 1 / 0,
+ MAX_SAFE_INTEGER = 9007199254740991;
+
+ /** `Object#toString` result references. */
+ var argsTag = '[object Arguments]',
+ arrayTag = '[object Array]',
+ boolTag = '[object Boolean]',
+ dateTag = '[object Date]',
+ errorTag = '[object Error]',
+ funcTag = '[object Function]',
+ genTag = '[object GeneratorFunction]',
+ mapTag = '[object Map]',
+ numberTag = '[object Number]',
+ objectTag = '[object Object]',
+ promiseTag = '[object Promise]',
+ regexpTag = '[object RegExp]',
+ setTag = '[object Set]',
+ stringTag = '[object String]',
+ symbolTag = '[object Symbol]',
+ weakMapTag = '[object WeakMap]';
+
+ var arrayBufferTag = '[object ArrayBuffer]',
+ dataViewTag = '[object DataView]',
+ float32Tag = '[object Float32Array]',
+ float64Tag = '[object Float64Array]',
+ int8Tag = '[object Int8Array]',
+ int16Tag = '[object Int16Array]',
+ int32Tag = '[object Int32Array]',
+ uint8Tag = '[object Uint8Array]',
+ uint8ClampedTag = '[object Uint8ClampedArray]',
+ uint16Tag = '[object Uint16Array]',
+ uint32Tag = '[object Uint32Array]';
+
+ /** Used to match property names within property paths. */
+ var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
+ reIsPlainProp = /^\w*$/,
+ reLeadingDot = /^\./,
+ rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
+
+ /**
+ * Used to match `RegExp`
+ * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
+ */
+ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
+
+ /** Used to match backslashes in property paths. */
+ var reEscapeChar = /\\(\\)?/g;
+
+ /** Used to detect host constructors (Safari). */
+ var reIsHostCtor = /^\[object .+?Constructor\]$/;
+
+ /** Used to detect unsigned integer values. */
+ var reIsUint = /^(?:0|[1-9]\d*)$/;
+
+ /** Used to identify `toStringTag` values of typed arrays. */
+ var typedArrayTags = {};
+ typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
+ typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
+ typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
+ typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
+ typedArrayTags[uint32Tag] = true;
+ typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
+ typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
+ typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
+ typedArrayTags[errorTag] = typedArrayTags[funcTag] =
+ typedArrayTags[mapTag] = typedArrayTags[numberTag] =
+ typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
+ typedArrayTags[setTag] = typedArrayTags[stringTag] =
+ typedArrayTags[weakMapTag] = false;
+
+ /** Detect free variable `global` from Node.js. */
+ var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
+
+ /** Detect free variable `self`. */
+ var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
+
+ /** Used as a reference to the global object. */
+ var root = freeGlobal || freeSelf || Function('return this')();
+
+ /** Detect free variable `exports`. */
+ var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
+
+ /** Detect free variable `module`. */
+ var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
+
+ /** Detect the popular CommonJS extension `module.exports`. */
+ var moduleExports = freeModule && freeModule.exports === freeExports;
+
+ /** Detect free variable `process` from Node.js. */
+ var freeProcess = moduleExports && freeGlobal.process;
+
+ /** Used to access faster Node.js helpers. */
+ var nodeUtil = (function() {
+ try {
+ return freeProcess && freeProcess.binding('util');
+ } catch (e) {}
+ }());
+
+ /* Node.js helper references. */
+ var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
+
+ /**
+ * A specialized version of `_.includes` for arrays without support for
+ * specifying an index to search from.
+ *
+ * @private
+ * @param {Array} [array] The array to inspect.
+ * @param {*} target The value to search for.
+ * @returns {boolean} Returns `true` if `target` is found, else `false`.
+ */
+ function arrayIncludes(array, value) {
+ var length = array ? array.length : 0;
+ return !!length && baseIndexOf(array, value, 0) > -1;
+ }
+
+ /**
+ * This function is like `arrayIncludes` except that it accepts a comparator.
+ *
+ * @private
+ * @param {Array} [array] The array to inspect.
+ * @param {*} target The value to search for.
+ * @param {Function} comparator The comparator invoked per element.
+ * @returns {boolean} Returns `true` if `target` is found, else `false`.
+ */
+ function arrayIncludesWith(array, value, comparator) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ while (++index < length) {
+ if (comparator(value, array[index])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A specialized version of `_.some` for arrays without support for iteratee
+ * shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function arraySome(array, predicate) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * The base implementation of `_.findIndex` and `_.findLastIndex` without
+ * support for iteratee shorthands.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} predicate The function invoked per iteration.
+ * @param {number} fromIndex The index to search from.
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function baseFindIndex(array, predicate, fromIndex, fromRight) {
+ var length = array.length,
+ index = fromIndex + (fromRight ? 1 : -1);
+
+ while ((fromRight ? index-- : ++index < length)) {
+ if (predicate(array[index], index, array)) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {*} value The value to search for.
+ * @param {number} fromIndex The index to search from.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function baseIndexOf(array, value, fromIndex) {
+ if (value !== value) {
+ return baseFindIndex(array, baseIsNaN, fromIndex);
+ }
+ var index = fromIndex - 1,
+ length = array.length;
+
+ while (++index < length) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `_.isNaN` without support for number objects.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
+ */
+ function baseIsNaN(value) {
+ return value !== value;
+ }
+
+ /**
+ * The base implementation of `_.property` without support for deep paths.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new accessor function.
+ */
+ function baseProperty(key) {
+ return function(object) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * The base implementation of `_.times` without support for iteratee shorthands
+ * or max array length checks.
+ *
+ * @private
+ * @param {number} n The number of times to invoke `iteratee`.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the array of results.
+ */
+ function baseTimes(n, iteratee) {
+ var index = -1,
+ result = Array(n);
+
+ while (++index < n) {
+ result[index] = iteratee(index);
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.unary` without support for storing metadata.
+ *
+ * @private
+ * @param {Function} func The function to cap arguments for.
+ * @returns {Function} Returns the new capped function.
+ */
+ function baseUnary(func) {
+ return function(value) {
+ return func(value);
+ };
+ }
+
+ /**
+ * Checks if a cache value for `key` exists.
+ *
+ * @private
+ * @param {Object} cache The cache to query.
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function cacheHas(cache, key) {
+ return cache.has(key);
+ }
+
+ /**
+ * Gets the value at `key` of `object`.
+ *
+ * @private
+ * @param {Object} [object] The object to query.
+ * @param {string} key The key of the property to get.
+ * @returns {*} Returns the property value.
+ */
+ function getValue(object, key) {
+ return object == null ? undefined : object[key];
+ }
+
+ /**
+ * Checks if `value` is a host object in IE < 9.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
+ */
+ function isHostObject(value) {
+ // Many host objects are `Object` objects that can coerce to strings
+ // despite having improperly defined `toString` methods.
+ var result = false;
+ if (value != null && typeof value.toString != 'function') {
+ try {
+ result = !!(value + '');
+ } catch (e) {}
+ }
+ return result;
+ }
+
+ /**
+ * Converts `map` to its key-value pairs.
+ *
+ * @private
+ * @param {Object} map The map to convert.
+ * @returns {Array} Returns the key-value pairs.
+ */
+ function mapToArray(map) {
+ var index = -1,
+ result = Array(map.size);
+
+ map.forEach(function(value, key) {
+ result[++index] = [key, value];
+ });
+ return result;
+ }
+
+ /**
+ * Creates a unary function that invokes `func` with its argument transformed.
+ *
+ * @private
+ * @param {Function} func The function to wrap.
+ * @param {Function} transform The argument transform.
+ * @returns {Function} Returns the new function.
+ */
+ function overArg(func, transform) {
+ return function(arg) {
+ return func(transform(arg));
+ };
+ }
+
+ /**
+ * Converts `set` to an array of its values.
+ *
+ * @private
+ * @param {Object} set The set to convert.
+ * @returns {Array} Returns the values.
+ */
+ function setToArray(set) {
+ var index = -1,
+ result = Array(set.size);
+
+ set.forEach(function(value) {
+ result[++index] = value;
+ });
+ return result;
+ }
+
+ /** Used for built-in method references. */
+ var arrayProto = Array.prototype,
+ funcProto = Function.prototype,
+ objectProto = Object.prototype;
+
+ /** Used to detect overreaching core-js shims. */
+ var coreJsData = root['__core-js_shared__'];
+
+ /** Used to detect methods masquerading as native. */
+ var maskSrcKey = (function() {
+ var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
+ return uid ? ('Symbol(src)_1.' + uid) : '';
+ }());
+
+ /** Used to resolve the decompiled source of functions. */
+ var funcToString = funcProto.toString;
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+ var objectToString = objectProto.toString;
+
+ /** Used to detect if a method is native. */
+ var reIsNative = RegExp('^' +
+ funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
+ .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+ );
+
+ /** Built-in value references. */
+ var Symbol = root.Symbol,
+ Uint8Array = root.Uint8Array,
+ propertyIsEnumerable = objectProto.propertyIsEnumerable,
+ splice = arrayProto.splice;
+
+ /* Built-in method references for those with the same name as other `lodash` methods. */
+ var nativeKeys = overArg(Object.keys, Object);
+
+ /* Built-in method references that are verified to be native. */
+ var DataView = getNative(root, 'DataView'),
+ Map = getNative(root, 'Map'),
+ Promise = getNative(root, 'Promise'),
+ Set = getNative(root, 'Set'),
+ WeakMap = getNative(root, 'WeakMap'),
+ nativeCreate = getNative(Object, 'create');
+
+ /** Used to detect maps, sets, and weakmaps. */
+ var dataViewCtorString = toSource(DataView),
+ mapCtorString = toSource(Map),
+ promiseCtorString = toSource(Promise),
+ setCtorString = toSource(Set),
+ weakMapCtorString = toSource(WeakMap);
+
+ /** Used to convert symbols to primitives and strings. */
+ var symbolProto = Symbol ? Symbol.prototype : undefined,
+ symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
+ symbolToString = symbolProto ? symbolProto.toString : undefined;
+
+ /**
+ * Creates a hash object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function Hash(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the hash.
+ *
+ * @private
+ * @name clear
+ * @memberOf Hash
+ */
+ function hashClear() {
+ this.__data__ = nativeCreate ? nativeCreate(null) : {};
+ }
+
+ /**
+ * Removes `key` and its value from the hash.
+ *
+ * @private
+ * @name delete
+ * @memberOf Hash
+ * @param {Object} hash The hash to modify.
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function hashDelete(key) {
+ return this.has(key) && delete this.__data__[key];
+ }
+
+ /**
+ * Gets the hash value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf Hash
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function hashGet(key) {
+ var data = this.__data__;
+ if (nativeCreate) {
+ var result = data[key];
+ return result === HASH_UNDEFINED ? undefined : result;
+ }
+ return hasOwnProperty.call(data, key) ? data[key] : undefined;
+ }
+
+ /**
+ * Checks if a hash value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf Hash
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function hashHas(key) {
+ var data = this.__data__;
+ return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
+ }
+
+ /**
+ * Sets the hash `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf Hash
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the hash instance.
+ */
+ function hashSet(key, value) {
+ var data = this.__data__;
+ data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
+ return this;
+ }
+
+ // Add methods to `Hash`.
+ Hash.prototype.clear = hashClear;
+ Hash.prototype['delete'] = hashDelete;
+ Hash.prototype.get = hashGet;
+ Hash.prototype.has = hashHas;
+ Hash.prototype.set = hashSet;
+
+ /**
+ * Creates an list cache object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function ListCache(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the list cache.
+ *
+ * @private
+ * @name clear
+ * @memberOf ListCache
+ */
+ function listCacheClear() {
+ this.__data__ = [];
+ }
+
+ /**
+ * Removes `key` and its value from the list cache.
+ *
+ * @private
+ * @name delete
+ * @memberOf ListCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function listCacheDelete(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ return false;
+ }
+ var lastIndex = data.length - 1;
+ if (index == lastIndex) {
+ data.pop();
+ } else {
+ splice.call(data, index, 1);
+ }
+ return true;
+ }
+
+ /**
+ * Gets the list cache value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf ListCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function listCacheGet(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ return index < 0 ? undefined : data[index][1];
+ }
+
+ /**
+ * Checks if a list cache value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf ListCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function listCacheHas(key) {
+ return assocIndexOf(this.__data__, key) > -1;
+ }
+
+ /**
+ * Sets the list cache `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf ListCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the list cache instance.
+ */
+ function listCacheSet(key, value) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ data.push([key, value]);
+ } else {
+ data[index][1] = value;
+ }
+ return this;
+ }
+
+ // Add methods to `ListCache`.
+ ListCache.prototype.clear = listCacheClear;
+ ListCache.prototype['delete'] = listCacheDelete;
+ ListCache.prototype.get = listCacheGet;
+ ListCache.prototype.has = listCacheHas;
+ ListCache.prototype.set = listCacheSet;
+
+ /**
+ * Creates a map cache object to store key-value pairs.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function MapCache(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the map.
+ *
+ * @private
+ * @name clear
+ * @memberOf MapCache
+ */
+ function mapCacheClear() {
+ this.__data__ = {
+ 'hash': new Hash,
+ 'map': new (Map || ListCache),
+ 'string': new Hash
+ };
+ }
+
+ /**
+ * Removes `key` and its value from the map.
+ *
+ * @private
+ * @name delete
+ * @memberOf MapCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function mapCacheDelete(key) {
+ return getMapData(this, key)['delete'](key);
+ }
+
+ /**
+ * Gets the map value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf MapCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function mapCacheGet(key) {
+ return getMapData(this, key).get(key);
+ }
+
+ /**
+ * Checks if a map value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf MapCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function mapCacheHas(key) {
+ return getMapData(this, key).has(key);
+ }
+
+ /**
+ * Sets the map `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf MapCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the map cache instance.
+ */
+ function mapCacheSet(key, value) {
+ getMapData(this, key).set(key, value);
+ return this;
+ }
+
+ // Add methods to `MapCache`.
+ MapCache.prototype.clear = mapCacheClear;
+ MapCache.prototype['delete'] = mapCacheDelete;
+ MapCache.prototype.get = mapCacheGet;
+ MapCache.prototype.has = mapCacheHas;
+ MapCache.prototype.set = mapCacheSet;
+
+ /**
+ *
+ * Creates an array cache object to store unique values.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [values] The values to cache.
+ */
+ function SetCache(values) {
+ var index = -1,
+ length = values ? values.length : 0;
+
+ this.__data__ = new MapCache;
+ while (++index < length) {
+ this.add(values[index]);
+ }
+ }
+
+ /**
+ * Adds `value` to the array cache.
+ *
+ * @private
+ * @name add
+ * @memberOf SetCache
+ * @alias push
+ * @param {*} value The value to cache.
+ * @returns {Object} Returns the cache instance.
+ */
+ function setCacheAdd(value) {
+ this.__data__.set(value, HASH_UNDEFINED);
+ return this;
+ }
+
+ /**
+ * Checks if `value` is in the array cache.
+ *
+ * @private
+ * @name has
+ * @memberOf SetCache
+ * @param {*} value The value to search for.
+ * @returns {number} Returns `true` if `value` is found, else `false`.
+ */
+ function setCacheHas(value) {
+ return this.__data__.has(value);
+ }
+
+ // Add methods to `SetCache`.
+ SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
+ SetCache.prototype.has = setCacheHas;
+
+ /**
+ * Creates a stack cache object to store key-value pairs.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function Stack(entries) {
+ this.__data__ = new ListCache(entries);
+ }
+
+ /**
+ * Removes all key-value entries from the stack.
+ *
+ * @private
+ * @name clear
+ * @memberOf Stack
+ */
+ function stackClear() {
+ this.__data__ = new ListCache;
+ }
+
+ /**
+ * Removes `key` and its value from the stack.
+ *
+ * @private
+ * @name delete
+ * @memberOf Stack
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function stackDelete(key) {
+ return this.__data__['delete'](key);
+ }
+
+ /**
+ * Gets the stack value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf Stack
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function stackGet(key) {
+ return this.__data__.get(key);
+ }
+
+ /**
+ * Checks if a stack value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf Stack
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function stackHas(key) {
+ return this.__data__.has(key);
+ }
+
+ /**
+ * Sets the stack `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf Stack
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the stack cache instance.
+ */
+ function stackSet(key, value) {
+ var cache = this.__data__;
+ if (cache instanceof ListCache) {
+ var pairs = cache.__data__;
+ if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
+ pairs.push([key, value]);
+ return this;
+ }
+ cache = this.__data__ = new MapCache(pairs);
+ }
+ cache.set(key, value);
+ return this;
+ }
+
+ // Add methods to `Stack`.
+ Stack.prototype.clear = stackClear;
+ Stack.prototype['delete'] = stackDelete;
+ Stack.prototype.get = stackGet;
+ Stack.prototype.has = stackHas;
+ Stack.prototype.set = stackSet;
+
+ /**
+ * Creates an array of the enumerable property names of the array-like `value`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @param {boolean} inherited Specify returning inherited property names.
+ * @returns {Array} Returns the array of property names.
+ */
+ function arrayLikeKeys(value, inherited) {
+ // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
+ // Safari 9 makes `arguments.length` enumerable in strict mode.
+ var result = (isArray(value) || isArguments(value))
+ ? baseTimes(value.length, String)
+ : [];
+
+ var length = result.length,
+ skipIndexes = !!length;
+
+ for (var key in value) {
+ if ((inherited || hasOwnProperty.call(value, key)) &&
+ !(skipIndexes && (key == 'length' || isIndex(key, length)))) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the index at which the `key` is found in `array` of key-value pairs.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {*} key The key to search for.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function assocIndexOf(array, key) {
+ var length = array.length;
+ while (length--) {
+ if (eq(array[length][0], key)) {
+ return length;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `_.get` without support for default values.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path of the property to get.
+ * @returns {*} Returns the resolved value.
+ */
+ function baseGet(object, path) {
+ path = isKey(path, object) ? [path] : castPath(path);
+
+ var index = 0,
+ length = path.length;
+
+ while (object != null && index < length) {
+ object = object[toKey(path[index++])];
+ }
+ return (index && index == length) ? object : undefined;
+ }
+
+ /**
+ * The base implementation of `getTag`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+ function baseGetTag(value) {
+ return objectToString.call(value);
+ }
+
+ /**
+ * The base implementation of `_.hasIn` without support for deep paths.
+ *
+ * @private
+ * @param {Object} [object] The object to query.
+ * @param {Array|string} key The key to check.
+ * @returns {boolean} Returns `true` if `key` exists, else `false`.
+ */
+ function baseHasIn(object, key) {
+ return object != null && key in Object(object);
+ }
+
+ /**
+ * The base implementation of `_.isEqual` which supports partial comparisons
+ * and tracks traversed objects.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparisons.
+ * @param {boolean} [bitmask] The bitmask of comparison flags.
+ * The bitmask may be composed of the following flags:
+ * 1 - Unordered comparison
+ * 2 - Partial comparison
+ * @param {Object} [stack] Tracks traversed `value` and `other` objects.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ */
+ function baseIsEqual(value, other, customizer, bitmask, stack) {
+ if (value === other) {
+ return true;
+ }
+ if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) {
+ return value !== value && other !== other;
+ }
+ return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stack);
+ }
+
+ /**
+ * A specialized version of `baseIsEqual` for arrays and objects which performs
+ * deep comparisons and tracks traversed objects enabling objects with circular
+ * references to be compared.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparisons.
+ * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual`
+ * for more details.
+ * @param {Object} [stack] Tracks traversed `object` and `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stack) {
+ var objIsArr = isArray(object),
+ othIsArr = isArray(other),
+ objTag = arrayTag,
+ othTag = arrayTag;
+
+ if (!objIsArr) {
+ objTag = getTag(object);
+ objTag = objTag == argsTag ? objectTag : objTag;
+ }
+ if (!othIsArr) {
+ othTag = getTag(other);
+ othTag = othTag == argsTag ? objectTag : othTag;
+ }
+ var objIsObj = objTag == objectTag && !isHostObject(object),
+ othIsObj = othTag == objectTag && !isHostObject(other),
+ isSameTag = objTag == othTag;
+
+ if (isSameTag && !objIsObj) {
+ stack || (stack = new Stack);
+ return (objIsArr || isTypedArray(object))
+ ? equalArrays(object, other, equalFunc, customizer, bitmask, stack)
+ : equalByTag(object, other, objTag, equalFunc, customizer, bitmask, stack);
+ }
+ if (!(bitmask & PARTIAL_COMPARE_FLAG)) {
+ var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
+ othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
+
+ if (objIsWrapped || othIsWrapped) {
+ var objUnwrapped = objIsWrapped ? object.value() : object,
+ othUnwrapped = othIsWrapped ? other.value() : other;
+
+ stack || (stack = new Stack);
+ return equalFunc(objUnwrapped, othUnwrapped, customizer, bitmask, stack);
+ }
+ }
+ if (!isSameTag) {
+ return false;
+ }
+ stack || (stack = new Stack);
+ return equalObjects(object, other, equalFunc, customizer, bitmask, stack);
+ }
+
+ /**
+ * The base implementation of `_.isMatch` without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @param {Object} source The object of property values to match.
+ * @param {Array} matchData The property names, values, and compare flags to match.
+ * @param {Function} [customizer] The function to customize comparisons.
+ * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+ */
+ function baseIsMatch(object, source, matchData, customizer) {
+ var index = matchData.length,
+ length = index,
+ noCustomizer = !customizer;
+
+ if (object == null) {
+ return !length;
+ }
+ object = Object(object);
+ while (index--) {
+ var data = matchData[index];
+ if ((noCustomizer && data[2])
+ ? data[1] !== object[data[0]]
+ : !(data[0] in object)
+ ) {
+ return false;
+ }
+ }
+ while (++index < length) {
+ data = matchData[index];
+ var key = data[0],
+ objValue = object[key],
+ srcValue = data[1];
+
+ if (noCustomizer && data[2]) {
+ if (objValue === undefined && !(key in object)) {
+ return false;
+ }
+ } else {
+ var stack = new Stack;
+ if (customizer) {
+ var result = customizer(objValue, srcValue, key, object, source, stack);
+ }
+ if (!(result === undefined
+ ? baseIsEqual(srcValue, objValue, customizer, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG, stack)
+ : result
+ )) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * The base implementation of `_.isNative` without bad shim checks.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function,
+ * else `false`.
+ */
+ function baseIsNative(value) {
+ if (!isObject(value) || isMasked(value)) {
+ return false;
+ }
+ var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;
+ return pattern.test(toSource(value));
+ }
+
+ /**
+ * The base implementation of `_.isTypedArray` without Node.js optimizations.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
+ */
+ function baseIsTypedArray(value) {
+ return isObjectLike(value) &&
+ isLength(value.length) && !!typedArrayTags[objectToString.call(value)];
+ }
+
+ /**
+ * The base implementation of `_.iteratee`.
+ *
+ * @private
+ * @param {*} [value=_.identity] The value to convert to an iteratee.
+ * @returns {Function} Returns the iteratee.
+ */
+ function baseIteratee(value) {
+ // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
+ // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
+ if (typeof value == 'function') {
+ return value;
+ }
+ if (value == null) {
+ return identity;
+ }
+ if (typeof value == 'object') {
+ return isArray(value)
+ ? baseMatchesProperty(value[0], value[1])
+ : baseMatches(value);
+ }
+ return property(value);
+ }
+
+ /**
+ * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+ function baseKeys(object) {
+ if (!isPrototype(object)) {
+ return nativeKeys(object);
+ }
+ var result = [];
+ for (var key in Object(object)) {
+ if (hasOwnProperty.call(object, key) && key != 'constructor') {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.matches` which doesn't clone `source`.
+ *
+ * @private
+ * @param {Object} source The object of property values to match.
+ * @returns {Function} Returns the new spec function.
+ */
+ function baseMatches(source) {
+ var matchData = getMatchData(source);
+ if (matchData.length == 1 && matchData[0][2]) {
+ return matchesStrictComparable(matchData[0][0], matchData[0][1]);
+ }
+ return function(object) {
+ return object === source || baseIsMatch(object, source, matchData);
+ };
+ }
+
+ /**
+ * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
+ *
+ * @private
+ * @param {string} path The path of the property to get.
+ * @param {*} srcValue The value to match.
+ * @returns {Function} Returns the new spec function.
+ */
+ function baseMatchesProperty(path, srcValue) {
+ if (isKey(path) && isStrictComparable(srcValue)) {
+ return matchesStrictComparable(toKey(path), srcValue);
+ }
+ return function(object) {
+ var objValue = get(object, path);
+ return (objValue === undefined && objValue === srcValue)
+ ? hasIn(object, path)
+ : baseIsEqual(srcValue, objValue, undefined, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG);
+ };
+ }
+
+ /**
+ * A specialized version of `baseProperty` which supports deep paths.
+ *
+ * @private
+ * @param {Array|string} path The path of the property to get.
+ * @returns {Function} Returns the new accessor function.
+ */
+ function basePropertyDeep(path) {
+ return function(object) {
+ return baseGet(object, path);
+ };
+ }
+
+ /**
+ * The base implementation of `_.toString` which doesn't convert nullish
+ * values to empty strings.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {string} Returns the string.
+ */
+ function baseToString(value) {
+ // Exit early for strings to avoid a performance hit in some environments.
+ if (typeof value == 'string') {
+ return value;
+ }
+ if (isSymbol(value)) {
+ return symbolToString ? symbolToString.call(value) : '';
+ }
+ var result = (value + '');
+ return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
+ }
+
+ /**
+ * The base implementation of `_.uniqBy` without support for iteratee shorthands.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee] The iteratee invoked per element.
+ * @param {Function} [comparator] The comparator invoked per element.
+ * @returns {Array} Returns the new duplicate free array.
+ */
+ function baseUniq(array, iteratee, comparator) {
+ var index = -1,
+ includes = arrayIncludes,
+ length = array.length,
+ isCommon = true,
+ result = [],
+ seen = result;
+
+ if (comparator) {
+ isCommon = false;
+ includes = arrayIncludesWith;
+ }
+ else if (length >= LARGE_ARRAY_SIZE) {
+ var set = iteratee ? null : createSet(array);
+ if (set) {
+ return setToArray(set);
+ }
+ isCommon = false;
+ includes = cacheHas;
+ seen = new SetCache;
+ }
+ else {
+ seen = iteratee ? [] : result;
+ }
+ outer:
+ while (++index < length) {
+ var value = array[index],
+ computed = iteratee ? iteratee(value) : value;
+
+ value = (comparator || value !== 0) ? value : 0;
+ if (isCommon && computed === computed) {
+ var seenIndex = seen.length;
+ while (seenIndex--) {
+ if (seen[seenIndex] === computed) {
+ continue outer;
+ }
+ }
+ if (iteratee) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ else if (!includes(seen, computed, comparator)) {
+ if (seen !== result) {
+ seen.push(computed);
+ }
+ result.push(value);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Casts `value` to a path array if it's not one.
+ *
+ * @private
+ * @param {*} value The value to inspect.
+ * @returns {Array} Returns the cast property path array.
+ */
+ function castPath(value) {
+ return isArray(value) ? value : stringToPath(value);
+ }
+
+ /**
+ * Creates a set object of `values`.
+ *
+ * @private
+ * @param {Array} values The values to add to the set.
+ * @returns {Object} Returns the new set.
+ */
+ var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {
+ return new Set(values);
+ };
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for arrays with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Array} array The array to compare.
+ * @param {Array} other The other array to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} customizer The function to customize comparisons.
+ * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
+ * for more details.
+ * @param {Object} stack Tracks traversed `array` and `other` objects.
+ * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
+ */
+ function equalArrays(array, other, equalFunc, customizer, bitmask, stack) {
+ var isPartial = bitmask & PARTIAL_COMPARE_FLAG,
+ arrLength = array.length,
+ othLength = other.length;
+
+ if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
+ return false;
+ }
+ // Assume cyclic values are equal.
+ var stacked = stack.get(array);
+ if (stacked && stack.get(other)) {
+ return stacked == other;
+ }
+ var index = -1,
+ result = true,
+ seen = (bitmask & UNORDERED_COMPARE_FLAG) ? new SetCache : undefined;
+
+ stack.set(array, other);
+ stack.set(other, array);
+
+ // Ignore non-index properties.
+ while (++index < arrLength) {
+ var arrValue = array[index],
+ othValue = other[index];
+
+ if (customizer) {
+ var compared = isPartial
+ ? customizer(othValue, arrValue, index, other, array, stack)
+ : customizer(arrValue, othValue, index, array, other, stack);
+ }
+ if (compared !== undefined) {
+ if (compared) {
+ continue;
+ }
+ result = false;
+ break;
+ }
+ // Recursively compare arrays (susceptible to call stack limits).
+ if (seen) {
+ if (!arraySome(other, function(othValue, othIndex) {
+ if (!seen.has(othIndex) &&
+ (arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack))) {
+ return seen.add(othIndex);
+ }
+ })) {
+ result = false;
+ break;
+ }
+ } else if (!(
+ arrValue === othValue ||
+ equalFunc(arrValue, othValue, customizer, bitmask, stack)
+ )) {
+ result = false;
+ break;
+ }
+ }
+ stack['delete'](array);
+ stack['delete'](other);
+ return result;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for comparing objects of
+ * the same `toStringTag`.
+ *
+ * **Note:** This function only supports comparing values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {string} tag The `toStringTag` of the objects to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} customizer The function to customize comparisons.
+ * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
+ * for more details.
+ * @param {Object} stack Tracks traversed `object` and `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalByTag(object, other, tag, equalFunc, customizer, bitmask, stack) {
+ switch (tag) {
+ case dataViewTag:
+ if ((object.byteLength != other.byteLength) ||
+ (object.byteOffset != other.byteOffset)) {
+ return false;
+ }
+ object = object.buffer;
+ other = other.buffer;
+
+ case arrayBufferTag:
+ if ((object.byteLength != other.byteLength) ||
+ !equalFunc(new Uint8Array(object), new Uint8Array(other))) {
+ return false;
+ }
+ return true;
+
+ case boolTag:
+ case dateTag:
+ case numberTag:
+ // Coerce booleans to `1` or `0` and dates to milliseconds.
+ // Invalid dates are coerced to `NaN`.
+ return eq(+object, +other);
+
+ case errorTag:
+ return object.name == other.name && object.message == other.message;
+
+ case regexpTag:
+ case stringTag:
+ // Coerce regexes to strings and treat strings, primitives and objects,
+ // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
+ // for more details.
+ return object == (other + '');
+
+ case mapTag:
+ var convert = mapToArray;
+
+ case setTag:
+ var isPartial = bitmask & PARTIAL_COMPARE_FLAG;
+ convert || (convert = setToArray);
+
+ if (object.size != other.size && !isPartial) {
+ return false;
+ }
+ // Assume cyclic values are equal.
+ var stacked = stack.get(object);
+ if (stacked) {
+ return stacked == other;
+ }
+ bitmask |= UNORDERED_COMPARE_FLAG;
+
+ // Recursively compare objects (susceptible to call stack limits).
+ stack.set(object, other);
+ var result = equalArrays(convert(object), convert(other), equalFunc, customizer, bitmask, stack);
+ stack['delete'](object);
+ return result;
+
+ case symbolTag:
+ if (symbolValueOf) {
+ return symbolValueOf.call(object) == symbolValueOf.call(other);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for objects with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} customizer The function to customize comparisons.
+ * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
+ * for more details.
+ * @param {Object} stack Tracks traversed `object` and `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalObjects(object, other, equalFunc, customizer, bitmask, stack) {
+ var isPartial = bitmask & PARTIAL_COMPARE_FLAG,
+ objProps = keys(object),
+ objLength = objProps.length,
+ othProps = keys(other),
+ othLength = othProps.length;
+
+ if (objLength != othLength && !isPartial) {
+ return false;
+ }
+ var index = objLength;
+ while (index--) {
+ var key = objProps[index];
+ if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {
+ return false;
+ }
+ }
+ // Assume cyclic values are equal.
+ var stacked = stack.get(object);
+ if (stacked && stack.get(other)) {
+ return stacked == other;
+ }
+ var result = true;
+ stack.set(object, other);
+ stack.set(other, object);
+
+ var skipCtor = isPartial;
+ while (++index < objLength) {
+ key = objProps[index];
+ var objValue = object[key],
+ othValue = other[key];
+
+ if (customizer) {
+ var compared = isPartial
+ ? customizer(othValue, objValue, key, other, object, stack)
+ : customizer(objValue, othValue, key, object, other, stack);
+ }
+ // Recursively compare objects (susceptible to call stack limits).
+ if (!(compared === undefined
+ ? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stack))
+ : compared
+ )) {
+ result = false;
+ break;
+ }
+ skipCtor || (skipCtor = key == 'constructor');
+ }
+ if (result && !skipCtor) {
+ var objCtor = object.constructor,
+ othCtor = other.constructor;
+
+ // Non `Object` object instances with different constructors are not equal.
+ if (objCtor != othCtor &&
+ ('constructor' in object && 'constructor' in other) &&
+ !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
+ typeof othCtor == 'function' && othCtor instanceof othCtor)) {
+ result = false;
+ }
+ }
+ stack['delete'](object);
+ stack['delete'](other);
+ return result;
+ }
+
+ /**
+ * Gets the data for `map`.
+ *
+ * @private
+ * @param {Object} map The map to query.
+ * @param {string} key The reference key.
+ * @returns {*} Returns the map data.
+ */
+ function getMapData(map, key) {
+ var data = map.__data__;
+ return isKeyable(key)
+ ? data[typeof key == 'string' ? 'string' : 'hash']
+ : data.map;
+ }
+
+ /**
+ * Gets the property names, values, and compare flags of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the match data of `object`.
+ */
+ function getMatchData(object) {
+ var result = keys(object),
+ length = result.length;
+
+ while (length--) {
+ var key = result[length],
+ value = object[key];
+
+ result[length] = [key, value, isStrictComparable(value)];
+ }
+ return result;
+ }
+
+ /**
+ * Gets the native function at `key` of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the method to get.
+ * @returns {*} Returns the function if it's native, else `undefined`.
+ */
+ function getNative(object, key) {
+ var value = getValue(object, key);
+ return baseIsNative(value) ? value : undefined;
+ }
+
+ /**
+ * Gets the `toStringTag` of `value`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+ var getTag = baseGetTag;
+
+ // Fallback for data views, maps, sets, and weak maps in IE 11,
+ // for data views in Edge < 14, and promises in Node.js.
+ if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
+ (Map && getTag(new Map) != mapTag) ||
+ (Promise && getTag(Promise.resolve()) != promiseTag) ||
+ (Set && getTag(new Set) != setTag) ||
+ (WeakMap && getTag(new WeakMap) != weakMapTag)) {
+ getTag = function(value) {
+ var result = objectToString.call(value),
+ Ctor = result == objectTag ? value.constructor : undefined,
+ ctorString = Ctor ? toSource(Ctor) : undefined;
+
+ if (ctorString) {
+ switch (ctorString) {
+ case dataViewCtorString: return dataViewTag;
+ case mapCtorString: return mapTag;
+ case promiseCtorString: return promiseTag;
+ case setCtorString: return setTag;
+ case weakMapCtorString: return weakMapTag;
+ }
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Checks if `path` exists on `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path to check.
+ * @param {Function} hasFunc The function to check properties.
+ * @returns {boolean} Returns `true` if `path` exists, else `false`.
+ */
+ function hasPath(object, path, hasFunc) {
+ path = isKey(path, object) ? [path] : castPath(path);
+
+ var result,
+ index = -1,
+ length = path.length;
+
+ while (++index < length) {
+ var key = toKey(path[index]);
+ if (!(result = object != null && hasFunc(object, key))) {
+ break;
+ }
+ object = object[key];
+ }
+ if (result) {
+ return result;
+ }
+ var length = object ? object.length : 0;
+ return !!length && isLength(length) && isIndex(key, length) &&
+ (isArray(object) || isArguments(object));
+ }
+
+ /**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+ function isIndex(value, length) {
+ length = length == null ? MAX_SAFE_INTEGER : length;
+ return !!length &&
+ (typeof value == 'number' || reIsUint.test(value)) &&
+ (value > -1 && value % 1 == 0 && value < length);
+ }
+
+ /**
+ * Checks if `value` is a property name and not a property path.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {Object} [object] The object to query keys on.
+ * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
+ */
+ function isKey(value, object) {
+ if (isArray(value)) {
+ return false;
+ }
+ var type = typeof value;
+ if (type == 'number' || type == 'symbol' || type == 'boolean' ||
+ value == null || isSymbol(value)) {
+ return true;
+ }
+ return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
+ (object != null && value in Object(object));
+ }
+
+ /**
+ * Checks if `value` is suitable for use as unique object key.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
+ */
+ function isKeyable(value) {
+ var type = typeof value;
+ return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
+ ? (value !== '__proto__')
+ : (value === null);
+ }
+
+ /**
+ * Checks if `func` has its source masked.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` is masked, else `false`.
+ */
+ function isMasked(func) {
+ return !!maskSrcKey && (maskSrcKey in func);
+ }
+
+ /**
+ * Checks if `value` is likely a prototype object.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
+ */
+ function isPrototype(value) {
+ var Ctor = value && value.constructor,
+ proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
+
+ return value === proto;
+ }
+
+ /**
+ * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` if suitable for strict
+ * equality comparisons, else `false`.
+ */
+ function isStrictComparable(value) {
+ return value === value && !isObject(value);
+ }
+
+ /**
+ * A specialized version of `matchesProperty` for source values suitable
+ * for strict equality comparisons, i.e. `===`.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @param {*} srcValue The value to match.
+ * @returns {Function} Returns the new spec function.
+ */
+ function matchesStrictComparable(key, srcValue) {
+ return function(object) {
+ if (object == null) {
+ return false;
+ }
+ return object[key] === srcValue &&
+ (srcValue !== undefined || (key in Object(object)));
+ };
+ }
+
+ /**
+ * Converts `string` to a property path array.
+ *
+ * @private
+ * @param {string} string The string to convert.
+ * @returns {Array} Returns the property path array.
+ */
+ var stringToPath = memoize(function(string) {
+ string = toString(string);
+
+ var result = [];
+ if (reLeadingDot.test(string)) {
+ result.push('');
+ }
+ string.replace(rePropName, function(match, number, quote, string) {
+ result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
+ });
+ return result;
+ });
+
+ /**
+ * Converts `value` to a string key if it's not a string or symbol.
+ *
+ * @private
+ * @param {*} value The value to inspect.
+ * @returns {string|symbol} Returns the key.
+ */
+ function toKey(value) {
+ if (typeof value == 'string' || isSymbol(value)) {
+ return value;
+ }
+ var result = (value + '');
+ return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
+ }
+
+ /**
+ * Converts `func` to its source code.
+ *
+ * @private
+ * @param {Function} func The function to process.
+ * @returns {string} Returns the source code.
+ */
+ function toSource(func) {
+ if (func != null) {
+ try {
+ return funcToString.call(func);
+ } catch (e) {}
+ try {
+ return (func + '');
+ } catch (e) {}
+ }
+ return '';
+ }
+
+ /**
+ * This method is like `_.uniq` except that it accepts `iteratee` which is
+ * invoked for each element in `array` to generate the criterion by which
+ * uniqueness is computed. The iteratee is invoked with one argument: (value).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Array
+ * @param {Array} array The array to inspect.
+ * @param {Function} [iteratee=_.identity]
+ * The iteratee invoked per element.
+ * @returns {Array} Returns the new duplicate free array.
+ * @example
+ *
+ * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
+ * // => [2.1, 1.2]
+ *
+ * // The `_.property` iteratee shorthand.
+ * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
+ * // => [{ 'x': 1 }, { 'x': 2 }]
+ */
+ function uniqBy(array, iteratee) {
+ return (array && array.length)
+ ? baseUniq(array, baseIteratee(iteratee, 2))
+ : [];
+ }
+
+ /**
+ * Creates a function that memoizes the result of `func`. If `resolver` is
+ * provided, it determines the cache key for storing the result based on the
+ * arguments provided to the memoized function. By default, the first argument
+ * provided to the memoized function is used as the map cache key. The `func`
+ * is invoked with the `this` binding of the memoized function.
+ *
+ * **Note:** The cache is exposed as the `cache` property on the memoized
+ * function. Its creation may be customized by replacing the `_.memoize.Cache`
+ * constructor with one whose instances implement the
+ * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
+ * method interface of `delete`, `get`, `has`, and `set`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to have its output memoized.
+ * @param {Function} [resolver] The function to resolve the cache key.
+ * @returns {Function} Returns the new memoized function.
+ * @example
+ *
+ * var object = { 'a': 1, 'b': 2 };
+ * var other = { 'c': 3, 'd': 4 };
+ *
+ * var values = _.memoize(_.values);
+ * values(object);
+ * // => [1, 2]
+ *
+ * values(other);
+ * // => [3, 4]
+ *
+ * object.a = 2;
+ * values(object);
+ * // => [1, 2]
+ *
+ * // Modify the result cache.
+ * values.cache.set(object, ['a', 'b']);
+ * values(object);
+ * // => ['a', 'b']
+ *
+ * // Replace `_.memoize.Cache`.
+ * _.memoize.Cache = WeakMap;
+ */
+ function memoize(func, resolver) {
+ if (typeof func != 'function' || (resolver && typeof resolver != 'function')) {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ var memoized = function() {
+ var args = arguments,
+ key = resolver ? resolver.apply(this, args) : args[0],
+ cache = memoized.cache;
+
+ if (cache.has(key)) {
+ return cache.get(key);
+ }
+ var result = func.apply(this, args);
+ memoized.cache = cache.set(key, result);
+ return result;
+ };
+ memoized.cache = new (memoize.Cache || MapCache);
+ return memoized;
+ }
+
+ // Assign cache to `_.memoize`.
+ memoize.Cache = MapCache;
+
+ /**
+ * Performs a
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * comparison between two values to determine if they are equivalent.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'a': 1 };
+ * var other = { 'a': 1 };
+ *
+ * _.eq(object, object);
+ * // => true
+ *
+ * _.eq(object, other);
+ * // => false
+ *
+ * _.eq('a', 'a');
+ * // => true
+ *
+ * _.eq('a', Object('a'));
+ * // => false
+ *
+ * _.eq(NaN, NaN);
+ * // => true
+ */
+ function eq(value, other) {
+ return value === other || (value !== value && other !== other);
+ }
+
+ /**
+ * Checks if `value` is likely an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an `arguments` object,
+ * else `false`.
+ * @example
+ *
+ * _.isArguments(function() { return arguments; }());
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+ function isArguments(value) {
+ // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
+ return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&
+ (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);
+ }
+
+ /**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * _.isArray(document.body.children);
+ * // => false
+ *
+ * _.isArray('abc');
+ * // => false
+ *
+ * _.isArray(_.noop);
+ * // => false
+ */
+ var isArray = Array.isArray;
+
+ /**
+ * Checks if `value` is array-like. A value is considered array-like if it's
+ * not a function and has a `value.length` that's an integer greater than or
+ * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+ * @example
+ *
+ * _.isArrayLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLike(document.body.children);
+ * // => true
+ *
+ * _.isArrayLike('abc');
+ * // => true
+ *
+ * _.isArrayLike(_.noop);
+ * // => false
+ */
+ function isArrayLike(value) {
+ return value != null && isLength(value.length) && !isFunction(value);
+ }
+
+ /**
+ * This method is like `_.isArrayLike` except that it also checks if `value`
+ * is an object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array-like object,
+ * else `false`.
+ * @example
+ *
+ * _.isArrayLikeObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLikeObject(document.body.children);
+ * // => true
+ *
+ * _.isArrayLikeObject('abc');
+ * // => false
+ *
+ * _.isArrayLikeObject(_.noop);
+ * // => false
+ */
+ function isArrayLikeObject(value) {
+ return isObjectLike(value) && isArrayLike(value);
+ }
+
+ /**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a function, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+ function isFunction(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in Safari 8-9 which returns 'object' for typed array and other constructors.
+ var tag = isObject(value) ? objectToString.call(value) : '';
+ return tag == funcTag || tag == genTag;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This method is loosely based on
+ * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ * @example
+ *
+ * _.isLength(3);
+ * // => true
+ *
+ * _.isLength(Number.MIN_VALUE);
+ * // => false
+ *
+ * _.isLength(Infinity);
+ * // => false
+ *
+ * _.isLength('3');
+ * // => false
+ */
+ function isLength(value) {
+ return typeof value == 'number' &&
+ value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+ }
+
+ /**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+ function isObject(value) {
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+ }
+
+ /**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+ function isObjectLike(value) {
+ return !!value && typeof value == 'object';
+ }
+
+ /**
+ * Checks if `value` is classified as a `Symbol` primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
+ * @example
+ *
+ * _.isSymbol(Symbol.iterator);
+ * // => true
+ *
+ * _.isSymbol('abc');
+ * // => false
+ */
+ function isSymbol(value) {
+ return typeof value == 'symbol' ||
+ (isObjectLike(value) && objectToString.call(value) == symbolTag);
+ }
+
+ /**
+ * Checks if `value` is classified as a typed array.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
+ * @example
+ *
+ * _.isTypedArray(new Uint8Array);
+ * // => true
+ *
+ * _.isTypedArray([]);
+ * // => false
+ */
+ var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;
+
+ /**
+ * Converts `value` to a string. An empty string is returned for `null`
+ * and `undefined` values. The sign of `-0` is preserved.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to process.
+ * @returns {string} Returns the string.
+ * @example
+ *
+ * _.toString(null);
+ * // => ''
+ *
+ * _.toString(-0);
+ * // => '-0'
+ *
+ * _.toString([1, 2, 3]);
+ * // => '1,2,3'
+ */
+ function toString(value) {
+ return value == null ? '' : baseToString(value);
+ }
+
+ /**
+ * Gets the value at `path` of `object`. If the resolved value is
+ * `undefined`, the `defaultValue` is returned in its place.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.7.0
+ * @category Object
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path of the property to get.
+ * @param {*} [defaultValue] The value returned for `undefined` resolved values.
+ * @returns {*} Returns the resolved value.
+ * @example
+ *
+ * var object = { 'a': [{ 'b': { 'c': 3 } }] };
+ *
+ * _.get(object, 'a[0].b.c');
+ * // => 3
+ *
+ * _.get(object, ['a', '0', 'b', 'c']);
+ * // => 3
+ *
+ * _.get(object, 'a.b.c', 'default');
+ * // => 'default'
+ */
+ function get(object, path, defaultValue) {
+ var result = object == null ? undefined : baseGet(object, path);
+ return result === undefined ? defaultValue : result;
+ }
+
+ /**
+ * Checks if `path` is a direct or inherited property of `object`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Object
+ * @param {Object} object The object to query.
+ * @param {Array|string} path The path to check.
+ * @returns {boolean} Returns `true` if `path` exists, else `false`.
+ * @example
+ *
+ * var object = _.create({ 'a': _.create({ 'b': 2 }) });
+ *
+ * _.hasIn(object, 'a');
+ * // => true
+ *
+ * _.hasIn(object, 'a.b');
+ * // => true
+ *
+ * _.hasIn(object, ['a', 'b']);
+ * // => true
+ *
+ * _.hasIn(object, 'b');
+ * // => false
+ */
+ function hasIn(object, path) {
+ return object != null && hasPath(object, path, baseHasIn);
+ }
+
+ /**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @since 0.1.0
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+ function keys(object) {
+ return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
+ }
+
+ /**
+ * This method returns the first argument it receives.
+ *
+ * @static
+ * @since 0.1.0
+ * @memberOf _
+ * @category Util
+ * @param {*} value Any value.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * var object = { 'a': 1 };
+ *
+ * console.log(_.identity(object) === object);
+ * // => true
+ */
+ function identity(value) {
+ return value;
+ }
+
+ /**
+ * This method returns `undefined`.
+ *
+ * @static
+ * @memberOf _
+ * @since 2.3.0
+ * @category Util
+ * @example
+ *
+ * _.times(2, _.noop);
+ * // => [undefined, undefined]
+ */
+ function noop() {
+ // No operation performed.
+ }
+
+ /**
+ * Creates a function that returns the value at `path` of a given object.
+ *
+ * @static
+ * @memberOf _
+ * @since 2.4.0
+ * @category Util
+ * @param {Array|string} path The path of the property to get.
+ * @returns {Function} Returns the new accessor function.
+ * @example
+ *
+ * var objects = [
+ * { 'a': { 'b': 2 } },
+ * { 'a': { 'b': 1 } }
+ * ];
+ *
+ * _.map(objects, _.property('a.b'));
+ * // => [2, 1]
+ *
+ * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');
+ * // => [1, 2]
+ */
+ function property(path) {
+ return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
+ }
+
+ module.exports = uniqBy;
+
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(33)(module)))
+
+/***/ },
+/* 51 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(52);
+
+/***/ },
+/* 52 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /* WEBPACK VAR INJECTION */(function(process) {'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _utils = __webpack_require__(2);
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ var _styler = __webpack_require__(15);
+
+ var _styler2 = _interopRequireDefault(_styler);
+
+ var _browser = __webpack_require__(3);
+
+ var _browser2 = _interopRequireDefault(_browser);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _style = __webpack_require__(53);
+
+ var _style2 = _interopRequireDefault(_style);
+
+ var _clapprZepto = __webpack_require__(16);
+
+ var _clapprZepto2 = _interopRequireDefault(_clapprZepto);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var MIMETYPES = {
+ 'mp4': ['avc1.42E01E', 'avc1.58A01E', 'avc1.4D401E', 'avc1.64001E', 'mp4v.20.8', 'mp4v.20.240', 'mp4a.40.2'].map(function (codec) {
+ return 'video/mp4; codecs="' + codec + ', mp4a.40.2"';
+ }),
+ 'ogg': ['video/ogg; codecs="theora, vorbis"', 'video/ogg; codecs="dirac"', 'video/ogg; codecs="theora, speex"'],
+ '3gpp': ['video/3gpp; codecs="mp4v.20.8, samr"'],
+ 'webm': ['video/webm; codecs="vp8, vorbis"'],
+ 'mkv': ['video/x-matroska; codecs="theora, vorbis"'],
+ 'm3u8': ['application/x-mpegurl']
+ };
+ MIMETYPES['ogv'] = MIMETYPES['ogg'];
+ MIMETYPES['3gp'] = MIMETYPES['3gpp'];
+
+ var AUDIO_MIMETYPES = {
+ 'wav': ['audio/wav'],
+ 'mp3': ['audio/mp3', 'audio/mpeg;codecs="mp3"'],
+ 'aac': ['audio/mp4;codecs="mp4a.40.5"'],
+ 'oga': ['audio/ogg']
+ };
+
+ var KNOWN_AUDIO_MIMETYPES = Object.keys(AUDIO_MIMETYPES).reduce(function (acc, k) {
+ return [].concat(_toConsumableArray(acc), _toConsumableArray(AUDIO_MIMETYPES[k]));
+ }, []);
+
+ // TODO: rename this Playback to HTML5Playback (breaking change, only after 0.3.0)
+
+ var HTML5Video = function (_Playback) {
+ _inherits(HTML5Video, _Playback);
+
+ _createClass(HTML5Video, [{
+ key: 'name',
+ get: function get() {
+ return 'html5_video';
+ }
+ }, {
+ key: 'tagName',
+ get: function get() {
+ return this.isAudioOnly ? 'audio' : 'video';
+ }
+ }, {
+ key: 'isAudioOnly',
+ get: function get() {
+ var resourceUrl = this.options.src;
+ var mimeTypes = HTML5Video._mimeTypesForUrl(resourceUrl, AUDIO_MIMETYPES, this.options.mimeType);
+ return this.options.playback && this.options.playback.audioOnly || this.options.audioOnly || KNOWN_AUDIO_MIMETYPES.indexOf(mimeTypes[0]) >= 0;
+ }
+ }, {
+ key: 'attributes',
+ get: function get() {
+ return {
+ 'data-html5-video': ''
+ };
+ }
+ }, {
+ key: 'events',
+ get: function get() {
+ return {
+ 'canplay': '_onCanPlay',
+ 'canplaythrough': '_handleBufferingEvents',
+ 'durationchange': '_onDurationChange',
+ 'ended': '_onEnded',
+ 'error': '_onError',
+ 'loadeddata': '_onLoadedData',
+ 'loadedmetadata': '_onLoadedMetadata',
+ 'pause': '_onPause',
+ 'playing': '_onPlaying',
+ 'progress': '_onProgress',
+ 'seeked': '_handleBufferingEvents',
+ 'seeking': '_handleBufferingEvents',
+ 'stalled': '_handleBufferingEvents',
+ 'timeupdate': '_onTimeUpdate',
+ 'waiting': '_onWaiting'
+ };
+ }
+
+ /**
+ * Determine if the playback has ended.
+ * @property ended
+ * @type Boolean
+ */
+
+ }, {
+ key: 'ended',
+ get: function get() {
+ return this.el.ended;
+ }
+
+ /**
+ * Determine if the playback is having to buffer in order for
+ * playback to be smooth.
+ * This is related to the PLAYBACK_BUFFERING and PLAYBACK_BUFFERFULL events
+ * @property buffering
+ * @type Boolean
+ */
+
+ }, {
+ key: 'buffering',
+ get: function get() {
+ return !!this._bufferingState;
+ }
+ }]);
+
+ function HTML5Video() {
+ _classCallCheck(this, HTML5Video);
+
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ var _this = _possibleConstructorReturn(this, _Playback.call.apply(_Playback, [this].concat(args)));
+
+ _this._loadStarted = false;
+ _this._playheadMoving = false;
+ _this._playheadMovingTimer = null;
+ _this._stopped = false;
+ _this._setupSrc(_this.options.src);
+ // backwards compatibility (TODO: remove on 0.3.0)
+ _this.options.playback || (_this.options.playback = _this.options || {});
+ _this.options.playback.disableContextMenu = _this.options.playback.disableContextMenu || _this.options.disableVideoTagContextMenu;
+
+ var playbackConfig = _this.options.playback;
+ var preload = playbackConfig.preload || (_browser2.default.isSafari ? 'auto' : _this.options.preload);
+
+ _clapprZepto2.default.extend(_this.el, {
+ loop: _this.options.loop,
+ poster: _this.options.poster,
+ preload: preload || 'metadata',
+ controls: (playbackConfig.controls || _this.options.useVideoTagDefaultControls) && 'controls',
+ crossOrigin: playbackConfig.crossOrigin,
+ 'x-webkit-playsinline': playbackConfig.playInline
+ });
+
+ // TODO should settings be private?
+ _this.settings = { default: ['seekbar'] };
+ _this.settings.left = ['playpause', 'position', 'duration'];
+ _this.settings.right = ['fullscreen', 'volume', 'hd-indicator'];
+
+ // https://github.com/clappr/clappr/issues/1076
+ _this.options.autoPlay && process.nextTick(function () {
+ return _this.play();
+ });
+ return _this;
+ }
+
+ /**
+ * Sets the source url on the <video> element, and also the 'src' property.
+ * @method setupSrc
+ * @private
+ * @param {String} srcUrl The source URL.
+ */
+
+
+ HTML5Video.prototype._setupSrc = function _setupSrc(srcUrl) {
+ if (this.el.src === srcUrl) {
+ return;
+ }
+ this._src = srcUrl;
+ this.el.src = srcUrl;
+ };
+
+ HTML5Video.prototype._onLoadedMetadata = function _onLoadedMetadata(e) {
+ this._handleBufferingEvents();
+ this.trigger(_events2.default.PLAYBACK_LOADEDMETADATA, { duration: e.target.duration, data: e });
+ this._updateSettings();
+ var autoSeekFromUrl = typeof this._options.autoSeekFromUrl === 'undefined' || this._options.autoSeekFromUrl;
+ if (this.getPlaybackType() !== _playback2.default.LIVE && autoSeekFromUrl) {
+ this._checkInitialSeek();
+ }
+ };
+
+ HTML5Video.prototype._onDurationChange = function _onDurationChange() {
+ this._updateSettings();
+ this._onTimeUpdate();
+ // onProgress uses the duration
+ this._onProgress();
+ };
+
+ HTML5Video.prototype._updateSettings = function _updateSettings() {
+ // we can't figure out if hls resource is VoD or not until it is being loaded or duration has changed.
+ // that's why we check it again and update media control accordingly.
+ if (this.getPlaybackType() === _playback2.default.VOD || this.getPlaybackType() === _playback2.default.AOD) {
+ this.settings.left = ['playpause', 'position', 'duration'];
+ } else {
+ this.settings.left = ['playstop'];
+ }
+ this.settings.seekEnabled = this.isSeekEnabled();
+ this.trigger(_events2.default.PLAYBACK_SETTINGSUPDATE);
+ };
+
+ HTML5Video.prototype.isSeekEnabled = function isSeekEnabled() {
+ return isFinite(this.getDuration());
+ };
+
+ HTML5Video.prototype.getPlaybackType = function getPlaybackType() {
+ var onDemandType = this.tagName === 'audio' ? _playback2.default.AOD : _playback2.default.VOD;
+ return [0, undefined, Infinity].indexOf(this.el.duration) >= 0 ? _playback2.default.LIVE : onDemandType;
+ };
+
+ HTML5Video.prototype.isHighDefinitionInUse = function isHighDefinitionInUse() {
+ return false;
+ };
+
+ HTML5Video.prototype.play = function play() {
+ this.trigger(_events2.default.PLAYBACK_PLAY_INTENT);
+ this._stopped = false;
+ this._setupSrc(this._src);
+ this._handleBufferingEvents();
+ this.el.play();
+ };
+
+ HTML5Video.prototype.pause = function pause() {
+ this.el.pause();
+ };
+
+ HTML5Video.prototype.stop = function stop() {
+ this.pause();
+ this._stopped = true;
+ // src will be added again in play()
+ this.el.removeAttribute('src');
+ this._stopPlayheadMovingChecks();
+ this._handleBufferingEvents();
+ this.trigger(_events2.default.PLAYBACK_STOP);
+ };
+
+ HTML5Video.prototype.volume = function volume(value) {
+ this.el.volume = value / 100;
+ };
+
+ HTML5Video.prototype.mute = function mute() {
+ this.el.volume = 0;
+ };
+
+ HTML5Video.prototype.unmute = function unmute() {
+ this.el.volume = 1;
+ };
+
+ HTML5Video.prototype.isMuted = function isMuted() {
+ return !!this.el.volume;
+ };
+
+ HTML5Video.prototype.isPlaying = function isPlaying() {
+ return !this.el.paused && !this.el.ended;
+ };
+
+ HTML5Video.prototype._startPlayheadMovingChecks = function _startPlayheadMovingChecks() {
+ if (this._playheadMovingTimer !== null) {
+ return;
+ }
+ this._playheadMovingTimeOnCheck = null;
+ this._determineIfPlayheadMoving();
+ this._playheadMovingTimer = setInterval(this._determineIfPlayheadMoving.bind(this), 500);
+ };
+
+ HTML5Video.prototype._stopPlayheadMovingChecks = function _stopPlayheadMovingChecks() {
+ if (this._playheadMovingTimer === null) {
+ return;
+ }
+ clearInterval(this._playheadMovingTimer);
+ this._playheadMovingTimer = null;
+ this._playheadMoving = false;
+ };
+
+ HTML5Video.prototype._determineIfPlayheadMoving = function _determineIfPlayheadMoving() {
+ var before = this._playheadMovingTimeOnCheck;
+ var now = this.el.currentTime;
+ this._playheadMoving = before !== now;
+ this._playheadMovingTimeOnCheck = now;
+ this._handleBufferingEvents();
+ };
+
+ // this seems to happen when the user is having to wait
+ // for something to happen AFTER A USER INTERACTION
+ // e.g the player might be buffering, but when `play()` is called
+ // only at this point will this be called.
+ // Or the user may seek somewhere but the new area requires buffering,
+ // so it will fire then as well.
+ // On devices where playing is blocked until requested with a user action,
+ // buffering may start, but never finish until the user initiates a play,
+ // but this only happens when play is actually requested
+
+
+ HTML5Video.prototype._onWaiting = function _onWaiting() {
+ this._loadStarted = true;
+ this._handleBufferingEvents();
+ };
+
+ // called after the first frame has loaded
+ // note this doesn't fire on ios before the user has requested play
+ // ideally the "loadstart" event would be used instead, but this fires
+ // before a user has requested play on iOS, and also this is always fired
+ // even if the preload setting is "none". In both these cases this causes
+ // infinite buffering until the user does something which isn't great.
+
+
+ HTML5Video.prototype._onLoadedData = function _onLoadedData() {
+ this._loadStarted = true;
+ this._handleBufferingEvents();
+ };
+
+ // note this doesn't fire on ios before user has requested play
+
+
+ HTML5Video.prototype._onCanPlay = function _onCanPlay() {
+ this._handleBufferingEvents();
+ };
+
+ HTML5Video.prototype._onPlaying = function _onPlaying() {
+ this._startPlayheadMovingChecks();
+ this._handleBufferingEvents();
+ this.trigger(_events2.default.PLAYBACK_PLAY);
+ };
+
+ HTML5Video.prototype._onPause = function _onPause() {
+ this._stopPlayheadMovingChecks();
+ this._handleBufferingEvents();
+ this.trigger(_events2.default.PLAYBACK_PAUSE);
+ };
+
+ HTML5Video.prototype._onEnded = function _onEnded() {
+ this._handleBufferingEvents();
+ this.trigger(_events2.default.PLAYBACK_ENDED, this.name);
+ };
+
+ // The playback should be classed as buffering if the following are true:
+ // - the ready state is less then HAVE_FUTURE_DATA or the playhead isn't moving and it should be
+ // - the media hasn't "ended",
+ // - the media hasn't been stopped
+ // - loading has started
+
+
+ HTML5Video.prototype._handleBufferingEvents = function _handleBufferingEvents() {
+ var playheadShouldBeMoving = !this.el.ended && !this.el.paused;
+ var buffering = this._loadStarted && !this.el.ended && !this._stopped && (playheadShouldBeMoving && !this._playheadMoving || this.el.readyState < this.el.HAVE_FUTURE_DATA);
+ if (this._bufferingState !== buffering) {
+ this._bufferingState = buffering;
+ if (buffering) {
+ this.trigger(_events2.default.PLAYBACK_BUFFERING, this.name);
+ } else {
+ this.trigger(_events2.default.PLAYBACK_BUFFERFULL, this.name);
+ }
+ }
+ };
+
+ HTML5Video.prototype._onError = function _onError() {
+ this.trigger(_events2.default.PLAYBACK_ERROR, this.el.error, this.name);
+ };
+
+ HTML5Video.prototype.destroy = function destroy() {
+ this.$el.remove();
+ this.el.src = '';
+ this._src = null;
+ };
+
+ HTML5Video.prototype.seek = function seek(time) {
+ this.el.currentTime = time;
+ };
+
+ HTML5Video.prototype.seekPercentage = function seekPercentage(percentage) {
+ var time = this.el.duration * (percentage / 100);
+ this.seek(time);
+ };
+
+ HTML5Video.prototype._checkInitialSeek = function _checkInitialSeek() {
+ var seekTime = (0, _utils.seekStringToSeconds)(window.location.href);
+ if (seekTime !== 0) {
+ this.seek(seekTime);
+ }
+ };
+
+ HTML5Video.prototype.getCurrentTime = function getCurrentTime() {
+ return this.el.currentTime;
+ };
+
+ HTML5Video.prototype.getDuration = function getDuration() {
+ return this.el.duration;
+ };
+
+ HTML5Video.prototype._onTimeUpdate = function _onTimeUpdate() {
+ this._handleBufferingEvents();
+ if (this.getPlaybackType() === _playback2.default.LIVE) {
+ this.trigger(_events2.default.PLAYBACK_TIMEUPDATE, { current: 1, total: 1 }, this.name);
+ } else {
+ this.trigger(_events2.default.PLAYBACK_TIMEUPDATE, { current: this.el.currentTime, total: this.el.duration }, this.name);
+ }
+ };
+
+ HTML5Video.prototype._onProgress = function _onProgress() {
+ if (!this.el.buffered.length) {
+ return;
+ }
+ var buffered = [];
+ var bufferedPos = 0;
+ for (var i = 0; i < this.el.buffered.length; i++) {
+ buffered = [].concat(_toConsumableArray(buffered), [{ start: this.el.buffered.start(i), end: this.el.buffered.end(i) }]);
+ if (this.el.currentTime >= buffered[i].start && this.el.currentTime <= buffered[i].end) {
+ bufferedPos = i;
+ }
+ }
+ var progress = {
+ start: buffered[bufferedPos].start,
+ current: buffered[bufferedPos].end,
+ total: this.el.duration
+ };
+ this.trigger(_events2.default.PLAYBACK_PROGRESS, progress, buffered);
+ };
+
+ HTML5Video.prototype._typeFor = function _typeFor(src) {
+ var mimeTypes = HTML5Video._mimeTypesForUrl(src, MIMETYPES, this.options.mimeType);
+ if (mimeTypes.length == 0) {
+ mimeTypes = HTML5Video._mimeTypesForUrl(src, AUDIO_MIMETYPES, this.options.mimeType);
+ }
+ var mimeType = mimeTypes[0] || '';
+ return mimeType.split(';')[0];
+ };
+
+ HTML5Video.prototype._ready = function _ready() {
+ if (this._isReadyState) {
+ return;
+ }
+ this._isReadyState = true;
+ this.trigger(_events2.default.PLAYBACK_READY, this.name);
+ };
+
+ HTML5Video.prototype.render = function render() {
+ var style = _styler2.default.getStyleFor(_style2.default);
+
+ if (this.options.playback.disableContextMenu) {
+ this.$el.on('contextmenu', function () {
+ return false;
+ });
+ }
+
+ this.$el.append(style);
+ this._ready();
+ return this;
+ };
+
+ _createClass(HTML5Video, [{
+ key: 'isReady',
+ get: function get() {
+ return this._isReadyState;
+ }
+ }]);
+
+ return HTML5Video;
+ }(_playback2.default);
+
+ exports.default = HTML5Video;
+
+
+ HTML5Video._mimeTypesForUrl = function (resourceUrl, mimeTypesByExtension, mimeType) {
+ var extension = (resourceUrl.split('?')[0].match(/.*\.(.*)$/) || [])[1];
+ var mimeTypes = mimeType || extension && mimeTypesByExtension[extension.toLowerCase()] || [];
+ return mimeTypes.constructor === Array ? mimeTypes : [mimeTypes];
+ };
+
+ HTML5Video._canPlay = function (type, mimeTypesByExtension, resourceUrl, mimeType) {
+ var mimeTypes = HTML5Video._mimeTypesForUrl(resourceUrl, mimeTypesByExtension, mimeType);
+ var media = document.createElement(type);
+ return !!mimeTypes.filter(function (mediaType) {
+ return !!media.canPlayType(mediaType).replace(/no/, '');
+ })[0];
+ };
+
+ HTML5Video.canPlay = function (resourceUrl, mimeType) {
+ return HTML5Video._canPlay('audio', AUDIO_MIMETYPES, resourceUrl, mimeType) || HTML5Video._canPlay('video', MIMETYPES, resourceUrl, mimeType);
+ };
+
+ module.exports = HTML5Video;
+ module.exports = exports['default'];
+ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(29)))
+
+/***/ },
+/* 53 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(25)();
+ // imports
+
+
+ // module
+ exports.push([module.id, "[data-html5-video] {\n position: absolute;\n height: 100%;\n width: 100%;\n display: block; }\n", ""]);
+
+ // exports
+
+
+/***/ },
+/* 54 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(55);
+
+/***/ },
+/* 55 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _utils = __webpack_require__(2);
+
+ var _base_flash_playback = __webpack_require__(56);
+
+ var _base_flash_playback2 = _interopRequireDefault(_base_flash_playback);
+
+ var _browser = __webpack_require__(3);
+
+ var _browser2 = _interopRequireDefault(_browser);
+
+ var _mediator = __webpack_require__(30);
+
+ var _mediator2 = _interopRequireDefault(_mediator);
+
+ var _template = __webpack_require__(17);
+
+ var _template2 = _interopRequireDefault(_template);
+
+ var _clapprZepto = __webpack_require__(16);
+
+ var _clapprZepto2 = _interopRequireDefault(_clapprZepto);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ var _Player = __webpack_require__(60);
+
+ var _Player2 = _interopRequireDefault(_Player);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var MAX_ATTEMPTS = 60;
+
+ var Flash = function (_BaseFlashPlayback) {
+ _inherits(Flash, _BaseFlashPlayback);
+
+ _createClass(Flash, [{
+ key: 'name',
+ get: function get() {
+ return 'flash';
+ }
+ }, {
+ key: 'swfPath',
+ get: function get() {
+ return (0, _template2.default)(_Player2.default)({ baseUrl: this._baseUrl });
+ }
+
+ /**
+ * Determine if the playback has ended.
+ * @property ended
+ * @type Boolean
+ */
+
+ }, {
+ key: 'ended',
+ get: function get() {
+ return this._currentState === 'ENDED';
+ }
+
+ /**
+ * Determine if the playback is buffering.
+ * This is related to the PLAYBACK_BUFFERING and PLAYBACK_BUFFERFULL events
+ * @property buffering
+ * @type Boolean
+ */
+
+ }, {
+ key: 'buffering',
+ get: function get() {
+ return !!this._bufferingState && this._currentState !== 'ENDED';
+ }
+ }]);
+
+ function Flash() {
+ _classCallCheck(this, Flash);
+
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ var _this = _possibleConstructorReturn(this, _BaseFlashPlayback.call.apply(_BaseFlashPlayback, [this].concat(args)));
+
+ _this._src = _this.options.src;
+ _this._baseUrl = _this.options.baseUrl;
+ _this._autoPlay = _this.options.autoPlay;
+ _this.settings = { default: ['seekbar'] };
+ _this.settings.left = ['playpause', 'position', 'duration'];
+ _this.settings.right = ['fullscreen', 'volume'];
+ _this.settings.seekEnabled = true;
+ _this._isReadyState = false;
+ _this._addListeners();
+ return _this;
+ }
+
+ Flash.prototype._bootstrap = function _bootstrap() {
+ var _this2 = this;
+
+ if (this.el.playerPlay) {
+ this.el.width = '100%';
+ this.el.height = '100%';
+ if (this._currentState === 'PLAYING') {
+ this._firstPlay();
+ } else {
+ this._currentState = 'IDLE';
+ this._autoPlay && this.play();
+ }
+ (0, _clapprZepto2.default)('<div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%" />').insertAfter(this.$el);
+ if (this.getDuration() > 0) {
+ this._metadataLoaded();
+ } else {
+ _mediator2.default.once(this.uniqueId + ':timeupdate', this._metadataLoaded, this);
+ }
+ } else {
+ this._attempts = this._attempts || 0;
+ if (++this._attempts <= MAX_ATTEMPTS) {
+ setTimeout(function () {
+ return _this2._bootstrap();
+ }, 50);
+ } else {
+ this.trigger(_events2.default.PLAYBACK_ERROR, { message: 'Max number of attempts reached' }, this.name);
+ }
+ }
+ };
+
+ Flash.prototype._metadataLoaded = function _metadataLoaded() {
+ this._isReadyState = true;
+ this.trigger(_events2.default.PLAYBACK_READY, this.name);
+ this.trigger(_events2.default.PLAYBACK_SETTINGSUPDATE, this.name);
+ };
+
+ Flash.prototype.getPlaybackType = function getPlaybackType() {
+ return _playback2.default.VOD;
+ };
+
+ Flash.prototype.isHighDefinitionInUse = function isHighDefinitionInUse() {
+ return false;
+ };
+
+ Flash.prototype._updateTime = function _updateTime() {
+ this.trigger(_events2.default.PLAYBACK_TIMEUPDATE, { current: this.el.getPosition(), total: this.el.getDuration() }, this.name);
+ };
+
+ Flash.prototype._addListeners = function _addListeners() {
+ _mediator2.default.on(this.uniqueId + ':progress', this._progress, this);
+ _mediator2.default.on(this.uniqueId + ':timeupdate', this._updateTime, this);
+ _mediator2.default.on(this.uniqueId + ':statechanged', this._checkState, this);
+ _mediator2.default.on(this.uniqueId + ':flashready', this._bootstrap, this);
+ };
+
+ Flash.prototype.stopListening = function stopListening() {
+ _BaseFlashPlayback.prototype.stopListening.call(this);
+ _mediator2.default.off(this.uniqueId + ':progress');
+ _mediator2.default.off(this.uniqueId + ':timeupdate');
+ _mediator2.default.off(this.uniqueId + ':statechanged');
+ _mediator2.default.off(this.uniqueId + ':flashready');
+ };
+
+ Flash.prototype._checkState = function _checkState() {
+ if (this._isIdle || this._currentState === 'PAUSED') {
+ return;
+ } else if (this._currentState !== 'PLAYING_BUFFERING' && this.el.getState() === 'PLAYING_BUFFERING') {
+ this._bufferingState = true;
+ this.trigger(_events2.default.PLAYBACK_BUFFERING, this.name);
+ this._currentState = 'PLAYING_BUFFERING';
+ } else if (this.el.getState() === 'PLAYING') {
+ this._bufferingState = false;
+ this.trigger(_events2.default.PLAYBACK_BUFFERFULL, this.name);
+ this._currentState = 'PLAYING';
+ } else if (this.el.getState() === 'IDLE') {
+ this._currentState = 'IDLE';
+ } else if (this.el.getState() === 'ENDED') {
+ this.trigger(_events2.default.PLAYBACK_ENDED, this.name);
+ this.trigger(_events2.default.PLAYBACK_TIMEUPDATE, { current: 0, total: this.el.getDuration() }, this.name);
+ this._currentState = 'ENDED';
+ this._isIdle = true;
+ }
+ };
+
+ Flash.prototype._progress = function _progress() {
+ if (this._currentState !== 'IDLE' && this._currentState !== 'ENDED') {
+ this.trigger(_events2.default.PLAYBACK_PROGRESS, {
+ start: 0,
+ current: this.el.getBytesLoaded(),
+ total: this.el.getBytesTotal()
+ });
+ }
+ };
+
+ Flash.prototype._firstPlay = function _firstPlay() {
+ var _this3 = this;
+
+ if (this.el.playerPlay) {
+ this._isIdle = false;
+ this.el.playerPlay(this._src);
+ this.listenToOnce(this, _events2.default.PLAYBACK_BUFFERFULL, function () {
+ return _this3._checkInitialSeek();
+ });
+ this._currentState = 'PLAYING';
+ } else {
+ this.listenToOnce(this, _events2.default.PLAYBACK_READY, this._firstPlay);
+ }
+ };
+
+ Flash.prototype._checkInitialSeek = function _checkInitialSeek() {
+ var seekTime = (0, _utils.seekStringToSeconds)(window.location.href);
+ if (seekTime !== 0) {
+ this.seekSeconds(seekTime);
+ }
+ };
+
+ Flash.prototype.play = function play() {
+ this.trigger(_events2.default.PLAYBACK_PLAY_INTENT);
+ if (this._currentState === 'PAUSED' || this._currentState === 'PLAYING_BUFFERING') {
+ this._currentState = 'PLAYING';
+ this.el.playerResume();
+ this.trigger(_events2.default.PLAYBACK_PLAY, this.name);
+ } else if (this._currentState !== 'PLAYING') {
+ this._firstPlay();
+ this.trigger(_events2.default.PLAYBACK_PLAY, this.name);
+ }
+ };
+
+ Flash.prototype.volume = function volume(value) {
+ var _this4 = this;
+
+ if (this.isReady) {
+ this.el.playerVolume(value);
+ } else {
+ this.listenToOnce(this, _events2.default.PLAYBACK_BUFFERFULL, function () {
+ return _this4.volume(value);
+ });
+ }
+ };
+
+ Flash.prototype.pause = function pause() {
+ this._currentState = 'PAUSED';
+ this.el.playerPause();
+ this.trigger(_events2.default.PLAYBACK_PAUSE, this.name);
+ };
+
+ Flash.prototype.stop = function stop() {
+ this.el.playerStop();
+ this.trigger(_events2.default.PLAYBACK_STOP);
+ this.trigger(_events2.default.PLAYBACK_TIMEUPDATE, { current: 0, total: 0 }, this.name);
+ };
+
+ Flash.prototype.isPlaying = function isPlaying() {
+ return !!(this.isReady && this._currentState.indexOf('PLAYING') > -1);
+ };
+
+ Flash.prototype.getDuration = function getDuration() {
+ return this.el.getDuration();
+ };
+
+ Flash.prototype.seekPercentage = function seekPercentage(percentage) {
+ var _this5 = this;
+
+ if (this.el.getDuration() > 0) {
+ var seekSeconds = this.el.getDuration() * (percentage / 100);
+ this.seek(seekSeconds);
+ } else {
+ this.listenToOnce(this, _events2.default.PLAYBACK_BUFFERFULL, function () {
+ return _this5.seekPercentage(percentage);
+ });
+ }
+ };
+
+ Flash.prototype.seek = function seek(time) {
+ var _this6 = this;
+
+ if (this.isReady && this.el.playerSeek) {
+ this.el.playerSeek(time);
+ this.trigger(_events2.default.PLAYBACK_TIMEUPDATE, { current: time, total: this.el.getDuration() }, this.name);
+ if (this._currentState === 'PAUSED') {
+ this.el.playerPause();
+ }
+ } else {
+ this.listenToOnce(this, _events2.default.PLAYBACK_BUFFERFULL, function () {
+ return _this6.seek(time);
+ });
+ }
+ };
+
+ Flash.prototype.destroy = function destroy() {
+ clearInterval(this.bootstrapId);
+ _BaseFlashPlayback.prototype.stopListening.call(this);
+ this.$el.remove();
+ };
+
+ _createClass(Flash, [{
+ key: 'isReady',
+ get: function get() {
+ return this._isReadyState;
+ }
+ }]);
+
+ return Flash;
+ }(_base_flash_playback2.default);
+
+ exports.default = Flash;
+
+
+ Flash.canPlay = function (resource) {
+ if (!_browser2.default.hasFlash || !resource || resource.constructor !== String) {
+ return false;
+ } else {
+ var resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || [];
+ return resourceParts.length > 1 && !_browser2.default.isMobile && resourceParts[1].toLowerCase().match(/^(mp4|mov|f4v|3gpp|3gp)$/);
+ }
+ };
+ module.exports = exports['default'];
+
+/***/ },
+/* 56 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+ exports.default = __webpack_require__(57);
+ module.exports = exports['default'];
+
+/***/ },
+/* 57 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ var _styler = __webpack_require__(15);
+
+ var _styler2 = _interopRequireDefault(_styler);
+
+ var _template = __webpack_require__(17);
+
+ var _template2 = _interopRequireDefault(_template);
+
+ var _browser = __webpack_require__(3);
+
+ var _browser2 = _interopRequireDefault(_browser);
+
+ var _flash = __webpack_require__(58);
+
+ var _flash2 = _interopRequireDefault(_flash);
+
+ var _flash3 = __webpack_require__(59);
+
+ var _flash4 = _interopRequireDefault(_flash3);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2015 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var IE_CLASSID = 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000';
+
+ var BaseFlashPlayback = function (_Playback) {
+ _inherits(BaseFlashPlayback, _Playback);
+
+ function BaseFlashPlayback() {
+ _classCallCheck(this, BaseFlashPlayback);
+
+ return _possibleConstructorReturn(this, _Playback.apply(this, arguments));
+ }
+
+ BaseFlashPlayback.prototype.setElement = function setElement(element) {
+ this.$el = element;
+ this.el = element[0];
+ };
+
+ BaseFlashPlayback.prototype._setupFirefox = function _setupFirefox() {
+ var $el = this.$('embed');
+ $el.attr('data-flash-playback', this.name);
+ $el.addClass(this.attributes.class);
+ this.setElement($el);
+ };
+
+ BaseFlashPlayback.prototype.render = function render() {
+ this.$el.html(this.template({
+ cid: this.cid,
+ swfPath: this.swfPath,
+ baseUrl: this.baseUrl,
+ playbackId: this.uniqueId,
+ wmode: this.wmode,
+ callbackName: 'window.Clappr.flashlsCallbacks.' + this.cid }));
+
+ if (_browser2.default.isIE) {
+ this.$('embed').remove();
+
+ if (_browser2.default.isLegacyIE) {
+ this.$el.attr('classid', IE_CLASSID);
+ }
+ }
+
+ if (_browser2.default.isFirefox) {
+ this._setupFirefox();
+ }
+
+ this.el.id = this.cid;
+ this.$el.append(_styler2.default.getStyleFor(_flash4.default));
+
+ return this;
+ };
+
+ _createClass(BaseFlashPlayback, [{
+ key: 'tagName',
+ get: function get() {
+ return 'object';
+ }
+ }, {
+ key: 'swfPath',
+ get: function get() {
+ return '';
+ }
+ }, {
+ key: 'wmode',
+ get: function get() {
+ return 'transparent';
+ }
+ }, {
+ key: 'template',
+ get: function get() {
+ return (0, _template2.default)(_flash2.default);
+ }
+ }, {
+ key: 'attributes',
+ get: function get() {
+ var type = 'application/x-shockwave-flash';
+
+ if (_browser2.default.isLegacyIE) {
+ type = '';
+ }
+
+ return {
+ class: 'clappr-flash-playback',
+ type: type,
+ width: '100%',
+ height: '100%',
+ 'data-flash-playback': this.name
+ };
+ }
+ }]);
+
+ return BaseFlashPlayback;
+ }(_playback2.default);
+
+ exports.default = BaseFlashPlayback;
+ module.exports = exports['default'];
+
+/***/ },
+/* 58 */
+/***/ function(module, exports) {
+
+ module.exports = "<param name=\"movie\" value=\"<%= swfPath %>?inline=1\">\n<param name=\"quality\" value=\"autohigh\">\n<param name=\"swliveconnect\" value=\"true\">\n<param name=\"allowScriptAccess\" value=\"always\">\n<param name=\"bgcolor\" value=\"#000000\">\n<param name=\"allowFullScreen\" value=\"false\">\n<param name=\"wmode\" value=\"<%= wmode %>\">\n<param name=\"tabindex\" value=\"1\">\n<param name=\"FlashVars\" value=\"playbackId=<%= playbackId %>&callback=<%= callbackName %>\">\n<embed\n name=\"<%= cid %>\"\n type=\"application/x-shockwave-flash\"\n disabled=\"disabled\"\n tabindex=\"-1\"\n enablecontextmenu=\"false\"\n allowScriptAccess=\"always\"\n quality=\"autohigh\"\n pluginspage=\"http://www.macromedia.com/go/getflashplayer\"\n wmode=\"<%= wmode %>\"\n swliveconnect=\"true\"\n allowfullscreen=\"false\"\n bgcolor=\"#000000\"\n FlashVars=\"playbackId=<%= playbackId %>&callback=<%= callbackName %>\"\n src=\"<%= swfPath %>\"\n width=\"100%\"\n height=\"100%\">\n</embed>\n";
+
+/***/ },
+/* 59 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(25)();
+ // imports
+
+
+ // module
+ exports.push([module.id, ".clappr-flash-playback[data-flash-playback] {\n display: block;\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n width: 100%;\n pointer-events: none; }\n", ""]);
+
+ // exports
+
+
+/***/ },
+/* 60 */
+/***/ function(module, exports, __webpack_require__) {
+
+ module.exports = __webpack_require__.p + "4b76590b32dab62bc95c1b7951efae78.swf";
+
+/***/ },
+/* 61 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(62);
+
+/***/ },
+/* 62 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ var _html5_video = __webpack_require__(51);
+
+ var _html5_video2 = _interopRequireDefault(_html5_video);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ // TODO: remove this playback and change HTML5Video to HTML5Playback (breaking change, only after 0.3.0)
+ var HTML5Audio = function (_HTML5Video) {
+ _inherits(HTML5Audio, _HTML5Video);
+
+ function HTML5Audio() {
+ _classCallCheck(this, HTML5Audio);
+
+ return _possibleConstructorReturn(this, _HTML5Video.apply(this, arguments));
+ }
+
+ HTML5Audio.prototype.updateSettings = function updateSettings() {
+ this.settings.left = ['playpause', 'position', 'duration'];
+ this.settings.seekEnabled = this.isSeekEnabled();
+ this.trigger(_events2.default.PLAYBACK_SETTINGSUPDATE);
+ };
+
+ HTML5Audio.prototype.getPlaybackType = function getPlaybackType() {
+ return _playback2.default.AOD;
+ };
+
+ _createClass(HTML5Audio, [{
+ key: 'name',
+ get: function get() {
+ return 'html5_audio';
+ }
+ }, {
+ key: 'tagName',
+ get: function get() {
+ return 'audio';
+ }
+ }, {
+ key: 'isAudioOnly',
+ get: function get() {
+ return true;
+ }
+ }]);
+
+ return HTML5Audio;
+ }(_html5_video2.default);
+
+ exports.default = HTML5Audio;
+
+
+ HTML5Audio.canPlay = function (resourceUrl, mimeType) {
+ var mimetypes = {
+ 'wav': ['audio/wav'],
+ 'mp3': ['audio/mp3', 'audio/mpeg;codecs="mp3"'],
+ 'aac': ['audio/mp4;codecs="mp4a.40.5"'],
+ 'oga': ['audio/ogg']
+ };
+ return _html5_video2.default._canPlay('audio', mimetypes, resourceUrl, mimeType);
+ };
+ module.exports = exports['default'];
+
+/***/ },
+/* 63 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(64);
+
+/***/ },
+/* 64 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _base_flash_playback = __webpack_require__(56);
+
+ var _base_flash_playback2 = _interopRequireDefault(_base_flash_playback);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _template = __webpack_require__(17);
+
+ var _template2 = _interopRequireDefault(_template);
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ var _mediator = __webpack_require__(30);
+
+ var _mediator2 = _interopRequireDefault(_mediator);
+
+ var _browser = __webpack_require__(3);
+
+ var _browser2 = _interopRequireDefault(_browser);
+
+ var _flashls_events = __webpack_require__(65);
+
+ var _flashls_events2 = _interopRequireDefault(_flashls_events);
+
+ var _HLSPlayer = __webpack_require__(66);
+
+ var _HLSPlayer2 = _interopRequireDefault(_HLSPlayer);
+
+ var _clapprZepto = __webpack_require__(16);
+
+ var _clapprZepto2 = _interopRequireDefault(_clapprZepto);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var MAX_ATTEMPTS = 60;
+ var AUTO = -1;
+
+ var FlasHLS = function (_BaseFlashPlayback) {
+ _inherits(FlasHLS, _BaseFlashPlayback);
+
+ _createClass(FlasHLS, [{
+ key: 'name',
+ get: function get() {
+ return 'flashls';
+ }
+ }, {
+ key: 'swfPath',
+ get: function get() {
+ return (0, _template2.default)(_HLSPlayer2.default)({ baseUrl: this._baseUrl });
+ }
+ }, {
+ key: 'levels',
+ get: function get() {
+ return this._levels || [];
+ }
+ }, {
+ key: 'currentLevel',
+ get: function get() {
+ if (this._currentLevel === null || this._currentLevel === undefined) {
+ return AUTO;
+ } else {
+ return this._currentLevel; //0 is a valid level ID
+ }
+ },
+ set: function set(id) {
+ this._currentLevel = id;
+ this.trigger(_events2.default.PLAYBACK_LEVEL_SWITCH_START);
+ this.el.playerSetCurrentLevel(id);
+ }
+
+ /**
+ * Determine if the playback has ended.
+ * @property ended
+ * @type Boolean
+ */
+
+ }, {
+ key: 'ended',
+ get: function get() {
+ return this._hasEnded;
+ }
+
+ /**
+ * Determine if the playback is buffering.
+ * This is related to the PLAYBACK_BUFFERING and PLAYBACK_BUFFERFULL events
+ * @property buffering
+ * @type Boolean
+ */
+
+ }, {
+ key: 'buffering',
+ get: function get() {
+ return !!this._bufferingState && !this._hasEnded;
+ }
+ }]);
+
+ function FlasHLS() {
+ _classCallCheck(this, FlasHLS);
+
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ var _this = _possibleConstructorReturn(this, _BaseFlashPlayback.call.apply(_BaseFlashPlayback, [this].concat(args)));
+
+ _this._src = _this.options.src;
+ _this._baseUrl = _this.options.baseUrl;
+ _this._initHlsParameters(_this.options);
+ // TODO can this be private?
+ _this.highDefinition = false;
+ _this._autoPlay = _this.options.autoPlay;
+ _this._loop = _this.options.loop;
+ _this._defaultSettings = {
+ left: ['playstop'],
+ default: ['seekbar'],
+ right: ['fullscreen', 'volume', 'hd-indicator'],
+ seekEnabled: false
+ };
+ _this.settings = _clapprZepto2.default.extend({}, _this._defaultSettings);
+ _this._playbackType = _playback2.default.LIVE;
+ _this._hasEnded = false;
+ _this._addListeners();
+ return _this;
+ }
+
+ FlasHLS.prototype._initHlsParameters = function _initHlsParameters(options) {
+ this._autoStartLoad = options.autoStartLoad === undefined ? true : options.autoStartLoad;
+ this._capLevelToStage = options.capLevelToStage === undefined ? false : options.capLevelToStage;
+ this._maxLevelCappingMode = options.maxLevelCappingMode === undefined ? 'downscale' : options.maxLevelCappingMode;
+ this._minBufferLength = options.minBufferLength === undefined ? -1 : options.minBufferLength;
+ this._minBufferLengthCapping = options.minBufferLengthCapping === undefined ? -1 : options.minBufferLengthCapping;
+ this._maxBufferLength = options.maxBufferLength === undefined ? 120 : options.maxBufferLength;
+ this._maxBackBufferLength = options.maxBackBufferLength === undefined ? 30 : options.maxBackBufferLength;
+ this._lowBufferLength = options.lowBufferLength === undefined ? 3 : options.lowBufferLength;
+ this._mediaTimePeriod = options.mediaTimePeriod === undefined ? 100 : options.mediaTimePeriod;
+ this._fpsDroppedMonitoringPeriod = options.fpsDroppedMonitoringPeriod === undefined ? 5000 : options.fpsDroppedMonitoringPeriod;
+ this._fpsDroppedMonitoringThreshold = options.fpsDroppedMonitoringThreshold === undefined ? 0.2 : options.fpsDroppedMonitoringThreshold;
+ this._capLevelonFPSDrop = options.capLevelonFPSDrop === undefined ? false : options.capLevelonFPSDrop;
+ this._smoothAutoSwitchonFPSDrop = options.smoothAutoSwitchonFPSDrop === undefined ? this.capLevelonFPSDrop : options.smoothAutoSwitchonFPSDrop;
+ this._switchDownOnLevelError = options.switchDownOnLevelError === undefined ? true : options.switchDownOnLevelError;
+ this._seekMode = options.seekMode === undefined ? 'ACCURATE' : options.seekMode;
+ this._keyLoadMaxRetry = options.keyLoadMaxRetry === undefined ? 3 : options.keyLoadMaxRetry;
+ this._keyLoadMaxRetryTimeout = options.keyLoadMaxRetryTimeout === undefined ? 64000 : options.keyLoadMaxRetryTimeout;
+ this._fragmentLoadMaxRetry = options.fragmentLoadMaxRetry === undefined ? 3 : options.fragmentLoadMaxRetry;
+ this._fragmentLoadMaxRetryTimeout = options.fragmentLoadMaxRetryTimeout === undefined ? 4000 : options.fragmentLoadMaxRetryTimeout;
+ this._fragmentLoadSkipAfterMaxRetry = options.fragmentLoadSkipAfterMaxRetry === undefined ? true : options.fragmentLoadSkipAfterMaxRetry;
+ this._maxSkippedFragments = options.maxSkippedFragments === undefined ? 5 : options.maxSkippedFragments;
+ this._flushLiveURLCache = options.flushLiveURLCache === undefined ? false : options.flushLiveURLCache;
+ this._initialLiveManifestSize = options.initialLiveManifestSize === undefined ? 1 : options.initialLiveManifestSize;
+ this._manifestLoadMaxRetry = options.manifestLoadMaxRetry === undefined ? 3 : options.manifestLoadMaxRetry;
+ this._manifestLoadMaxRetryTimeout = options.manifestLoadMaxRetryTimeout === undefined ? 64000 : options.manifestLoadMaxRetryTimeout;
+ this._manifestRedundantLoadmaxRetry = options.manifestRedundantLoadmaxRetry === undefined ? 3 : options.manifestRedundantLoadmaxRetry;
+ this._startFromBitrate = options.startFromBitrate === undefined ? -1 : options.startFromBitrate;
+ this._startFromLevel = options.startFromLevel === undefined ? -1 : options.startFromLevel;
+ this._autoStartMaxDuration = options.autoStartMaxDuration === undefined ? -1 : options.autoStartMaxDuration;
+ this._seekFromLevel = options.seekFromLevel === undefined ? -1 : options.seekFromLevel;
+ this._useHardwareVideoDecoder = options.useHardwareVideoDecoder === undefined ? false : options.useHardwareVideoDecoder;
+ this._hlsLogEnabled = options.hlsLogEnabled === undefined ? true : options.hlsLogEnabled;
+ this._logDebug = options.logDebug === undefined ? false : options.logDebug;
+ this._logDebug2 = options.logDebug2 === undefined ? false : options.logDebug2;
+ this._logWarn = options.logWarn === undefined ? true : options.logWarn;
+ this._logError = options.logError === undefined ? true : options.logError;
+ this._hlsMinimumDvrSize = options.hlsMinimumDvrSize === undefined ? 60 : options.hlsMinimumDvrSize;
+ };
+
+ FlasHLS.prototype._addListeners = function _addListeners() {
+ var _this2 = this;
+
+ _mediator2.default.on(this.cid + ':flashready', function () {
+ return _this2._bootstrap();
+ });
+ _mediator2.default.on(this.cid + ':timeupdate', function (timeMetrics) {
+ return _this2._updateTime(timeMetrics);
+ });
+ _mediator2.default.on(this.cid + ':playbackstate', function (state) {
+ return _this2._setPlaybackState(state);
+ });
+ _mediator2.default.on(this.cid + ':levelchanged', function (level) {
+ return _this2._levelChanged(level);
+ });
+ _mediator2.default.on(this.cid + ':error', function (code, url, message) {
+ return _this2._flashPlaybackError(code, url, message);
+ });
+ _mediator2.default.on(this.cid + ':fragmentloaded', function (loadmetrics) {
+ return _this2._onFragmentLoaded(loadmetrics);
+ });
+ _mediator2.default.on(this.cid + ':levelendlist', function (level) {
+ return _this2._onLevelEndlist(level);
+ });
+ };
+
+ FlasHLS.prototype.stopListening = function stopListening() {
+ _BaseFlashPlayback.prototype.stopListening.call(this);
+ _mediator2.default.off(this.cid + ':flashready');
+ _mediator2.default.off(this.cid + ':timeupdate');
+ _mediator2.default.off(this.cid + ':playbackstate');
+ _mediator2.default.off(this.cid + ':levelchanged');
+ _mediator2.default.off(this.cid + ':playbackerror');
+ _mediator2.default.off(this.cid + ':fragmentloaded');
+ _mediator2.default.off(this.cid + ':manifestloaded');
+ _mediator2.default.off(this.cid + ':levelendlist');
+ };
+
+ FlasHLS.prototype._bootstrap = function _bootstrap() {
+ var _this3 = this;
+
+ if (this.el.playerLoad) {
+ this.el.width = '100%';
+ this.el.height = '100%';
+ this._isReadyState = true;
+ this._srcLoaded = false;
+ this._currentState = 'IDLE';
+ this._setFlashSettings();
+ this._updatePlaybackType();
+ if (this._autoPlay || this._shouldPlayOnManifestLoaded) {
+ this.play();
+ }
+ this.trigger(_events2.default.PLAYBACK_READY, this.name);
+ } else {
+ this._bootstrapAttempts = this._bootstrapAttempts || 0;
+ if (++this._bootstrapAttempts <= MAX_ATTEMPTS) {
+ setTimeout(function () {
+ return _this3._bootstrap();
+ }, 50);
+ } else {
+ this.trigger(_events2.default.PLAYBACK_ERROR, { message: 'Max number of attempts reached' }, this.name);
+ }
+ }
+ };
+
+ FlasHLS.prototype._setFlashSettings = function _setFlashSettings() {
+ this.el.playerSetAutoStartLoad(this._autoStartLoad);
+ this.el.playerSetCapLevelToStage(this._capLevelToStage);
+ this.el.playerSetMaxLevelCappingMode(this._maxLevelCappingMode);
+ this.el.playerSetMinBufferLength(this._minBufferLength);
+ this.el.playerSetMinBufferLengthCapping(this._minBufferLengthCapping);
+ this.el.playerSetMaxBufferLength(this._maxBufferLength);
+ this.el.playerSetMaxBackBufferLength(this._maxBackBufferLength);
+ this.el.playerSetLowBufferLength(this._lowBufferLength);
+ this.el.playerSetMediaTimePeriod(this._mediaTimePeriod);
+ this.el.playerSetFpsDroppedMonitoringPeriod(this._fpsDroppedMonitoringPeriod);
+ this.el.playerSetFpsDroppedMonitoringThreshold(this._fpsDroppedMonitoringThreshold);
+ this.el.playerSetCapLevelonFPSDrop(this._capLevelonFPSDrop);
+ this.el.playerSetSmoothAutoSwitchonFPSDrop(this._smoothAutoSwitchonFPSDrop);
+ this.el.playerSetSwitchDownOnLevelError(this._switchDownOnLevelError);
+ this.el.playerSetSeekMode(this._seekMode);
+ this.el.playerSetKeyLoadMaxRetry(this._keyLoadMaxRetry);
+ this.el.playerSetKeyLoadMaxRetryTimeout(this._keyLoadMaxRetryTimeout);
+ this.el.playerSetFragmentLoadMaxRetry(this._fragmentLoadMaxRetry);
+ this.el.playerSetFragmentLoadMaxRetryTimeout(this._fragmentLoadMaxRetryTimeout);
+ this.el.playerSetFragmentLoadSkipAfterMaxRetry(this._fragmentLoadSkipAfterMaxRetry);
+ this.el.playerSetMaxSkippedFragments(this._maxSkippedFragments);
+ this.el.playerSetFlushLiveURLCache(this._flushLiveURLCache);
+ this.el.playerSetInitialLiveManifestSize(this._initialLiveManifestSize);
+ this.el.playerSetManifestLoadMaxRetry(this._manifestLoadMaxRetry);
+ this.el.playerSetManifestLoadMaxRetryTimeout(this._manifestLoadMaxRetryTimeout);
+ this.el.playerSetManifestRedundantLoadmaxRetry(this._manifestRedundantLoadmaxRetry);
+ this.el.playerSetStartFromBitrate(this._startFromBitrate);
+ this.el.playerSetStartFromLevel(this._startFromLevel);
+ this.el.playerSetAutoStartMaxDuration(this._autoStartMaxDuration);
+ this.el.playerSetSeekFromLevel(this._seekFromLevel);
+ this.el.playerSetUseHardwareVideoDecoder(this._useHardwareVideoDecoder);
+ this.el.playerSetLogInfo(this._hlsLogEnabled);
+ this.el.playerSetLogDebug(this._logDebug);
+ this.el.playerSetLogDebug2(this._logDebug2);
+ this.el.playerSetLogWarn(this._logWarn);
+ this.el.playerSetLogError(this._logError);
+ };
+
+ FlasHLS.prototype.setAutoStartLoad = function setAutoStartLoad(autoStartLoad) {
+ this._autoStartLoad = autoStartLoad;
+ this.el.playerSetAutoStartLoad(this._autoStartLoad);
+ };
+
+ FlasHLS.prototype.setCapLevelToStage = function setCapLevelToStage(capLevelToStage) {
+ this._capLevelToStage = capLevelToStage;
+ this.el.playerSetCapLevelToStage(this._capLevelToStage);
+ };
+
+ FlasHLS.prototype.setMaxLevelCappingMode = function setMaxLevelCappingMode(maxLevelCappingMode) {
+ this._maxLevelCappingMode = maxLevelCappingMode;
+ this.el.playerSetMaxLevelCappingMode(this._maxLevelCappingMode);
+ };
+
+ FlasHLS.prototype.setSetMinBufferLength = function setSetMinBufferLength(minBufferLength) {
+ this._minBufferLength = minBufferLength;
+ this.el.playerSetMinBufferLength(this._minBufferLength);
+ };
+
+ FlasHLS.prototype.setMinBufferLengthCapping = function setMinBufferLengthCapping(minBufferLengthCapping) {
+ this._minBufferLengthCapping = minBufferLengthCapping;
+ this.el.playerSetMinBufferLengthCapping(this._minBufferLengthCapping);
+ };
+
+ FlasHLS.prototype.setMaxBufferLength = function setMaxBufferLength(maxBufferLength) {
+ this._maxBufferLength = maxBufferLength;
+ this.el.playerSetMaxBufferLength(this._maxBufferLength);
+ };
+
+ FlasHLS.prototype.setMaxBackBufferLength = function setMaxBackBufferLength(maxBackBufferLength) {
+ this._maxBackBufferLength = maxBackBufferLength;
+ this.el.playerSetMaxBackBufferLength(this._maxBackBufferLength);
+ };
+
+ FlasHLS.prototype.setLowBufferLength = function setLowBufferLength(lowBufferLength) {
+ this._lowBufferLength = lowBufferLength;
+ this.el.playerSetLowBufferLength(this._lowBufferLength);
+ };
+
+ FlasHLS.prototype.setMediaTimePeriod = function setMediaTimePeriod(mediaTimePeriod) {
+ this._mediaTimePeriod = mediaTimePeriod;
+ this.el.playerSetMediaTimePeriod(this._mediaTimePeriod);
+ };
+
+ FlasHLS.prototype.setFpsDroppedMonitoringPeriod = function setFpsDroppedMonitoringPeriod(fpsDroppedMonitoringPeriod) {
+ this._fpsDroppedMonitoringPeriod = fpsDroppedMonitoringPeriod;
+ this.el.playerSetFpsDroppedMonitoringPeriod(this._fpsDroppedMonitoringPeriod);
+ };
+
+ FlasHLS.prototype.setFpsDroppedMonitoringThreshold = function setFpsDroppedMonitoringThreshold(fpsDroppedMonitoringThreshold) {
+ this._fpsDroppedMonitoringThreshold = fpsDroppedMonitoringThreshold;
+ this.el.playerSetFpsDroppedMonitoringThreshold(this._fpsDroppedMonitoringThreshold);
+ };
+
+ FlasHLS.prototype.setCapLevelonFPSDrop = function setCapLevelonFPSDrop(capLevelonFPSDrop) {
+ this._capLevelonFPSDrop = capLevelonFPSDrop;
+ this.el.playerSetCapLevelonFPSDrop(this._capLevelonFPSDrop);
+ };
+
+ FlasHLS.prototype.setSmoothAutoSwitchonFPSDrop = function setSmoothAutoSwitchonFPSDrop(smoothAutoSwitchonFPSDrop) {
+ this._smoothAutoSwitchonFPSDrop = smoothAutoSwitchonFPSDrop;
+ this.el.playerSetSmoothAutoSwitchonFPSDrop(this._smoothAutoSwitchonFPSDrop);
+ };
+
+ FlasHLS.prototype.setSwitchDownOnLevelError = function setSwitchDownOnLevelError(switchDownOnLevelError) {
+ this._switchDownOnLevelError = switchDownOnLevelError;
+ this.el.playerSetSwitchDownOnLevelError(this._switchDownOnLevelError);
+ };
+
+ FlasHLS.prototype.setSeekMode = function setSeekMode(seekMode) {
+ this._seekMode = seekMode;
+ this.el.playerSetSeekMode(this._seekMode);
+ };
+
+ FlasHLS.prototype.setKeyLoadMaxRetry = function setKeyLoadMaxRetry(keyLoadMaxRetry) {
+ this._keyLoadMaxRetry = keyLoadMaxRetry;
+ this.el.playerSetKeyLoadMaxRetry(this._keyLoadMaxRetry);
+ };
+
+ FlasHLS.prototype.setKeyLoadMaxRetryTimeout = function setKeyLoadMaxRetryTimeout(keyLoadMaxRetryTimeout) {
+ this._keyLoadMaxRetryTimeout = keyLoadMaxRetryTimeout;
+ this.el.playerSetKeyLoadMaxRetryTimeout(this._keyLoadMaxRetryTimeout);
+ };
+
+ FlasHLS.prototype.setFragmentLoadMaxRetry = function setFragmentLoadMaxRetry(fragmentLoadMaxRetry) {
+ this._fragmentLoadMaxRetry = fragmentLoadMaxRetry;
+ this.el.playerSetFragmentLoadMaxRetry(this._fragmentLoadMaxRetry);
+ };
+
+ FlasHLS.prototype.setFragmentLoadMaxRetryTimeout = function setFragmentLoadMaxRetryTimeout(fragmentLoadMaxRetryTimeout) {
+ this._fragmentLoadMaxRetryTimeout = fragmentLoadMaxRetryTimeout;
+ this.el.playerSetFragmentLoadMaxRetryTimeout(this._fragmentLoadMaxRetryTimeout);
+ };
+
+ FlasHLS.prototype.setFragmentLoadSkipAfterMaxRetry = function setFragmentLoadSkipAfterMaxRetry(fragmentLoadSkipAfterMaxRetry) {
+ this._fragmentLoadSkipAfterMaxRetry = fragmentLoadSkipAfterMaxRetry;
+ this.el.playerSetFragmentLoadSkipAfterMaxRetry(this._fragmentLoadSkipAfterMaxRetry);
+ };
+
+ FlasHLS.prototype.setMaxSkippedFragments = function setMaxSkippedFragments(maxSkippedFragments) {
+ this._maxSkippedFragments = maxSkippedFragments;
+ this.el.playerSetMaxSkippedFragments(this._maxSkippedFragments);
+ };
+
+ FlasHLS.prototype.setFlushLiveURLCache = function setFlushLiveURLCache(flushLiveURLCache) {
+ this._flushLiveURLCache = flushLiveURLCache;
+ this.el.playerSetFlushLiveURLCache(this._flushLiveURLCache);
+ };
+
+ FlasHLS.prototype.setInitialLiveManifestSize = function setInitialLiveManifestSize(initialLiveManifestSize) {
+ this._initialLiveManifestSize = initialLiveManifestSize;
+ this.el.playerSetInitialLiveManifestSize(this._initialLiveManifestSize);
+ };
+
+ FlasHLS.prototype.setManifestLoadMaxRetry = function setManifestLoadMaxRetry(manifestLoadMaxRetry) {
+ this._manifestLoadMaxRetry = manifestLoadMaxRetry;
+ this.el.playerSetManifestLoadMaxRetry(this._manifestLoadMaxRetry);
+ };
+
+ FlasHLS.prototype.setManifestLoadMaxRetryTimeout = function setManifestLoadMaxRetryTimeout(manifestLoadMaxRetryTimeout) {
+ this._manifestLoadMaxRetryTimeout = manifestLoadMaxRetryTimeout;
+ this.el.playerSetManifestLoadMaxRetryTimeout(this._manifestLoadMaxRetryTimeout);
+ };
+
+ FlasHLS.prototype.setManifestRedundantLoadmaxRetry = function setManifestRedundantLoadmaxRetry(manifestRedundantLoadmaxRetry) {
+ this._manifestRedundantLoadmaxRetry = manifestRedundantLoadmaxRetry;
+ this.el.playerSetManifestRedundantLoadmaxRetry(this._manifestRedundantLoadmaxRetry);
+ };
+
+ FlasHLS.prototype.setStartFromBitrate = function setStartFromBitrate(startFromBitrate) {
+ this._startFromBitrate = startFromBitrate;
+ this.el.playerSetStartFromBitrate(this._startFromBitrate);
+ };
+
+ FlasHLS.prototype.setStartFromLevel = function setStartFromLevel(startFromLevel) {
+ this._startFromLevel = startFromLevel;
+ this.el.playerSetStartFromLevel(this._startFromLevel);
+ };
+
+ FlasHLS.prototype.setAutoStartMaxDuration = function setAutoStartMaxDuration(autoStartMaxDuration) {
+ this._autoStartMaxDuration = autoStartMaxDuration;
+ this.el.playerSetAutoStartMaxDuration(this._autoStartMaxDuration);
+ };
+
+ FlasHLS.prototype.setSeekFromLevel = function setSeekFromLevel(seekFromLevel) {
+ this._seekFromLevel = seekFromLevel;
+ this.el.playerSetSeekFromLevel(this._seekFromLevel);
+ };
+
+ FlasHLS.prototype.setUseHardwareVideoDecoder = function setUseHardwareVideoDecoder(useHardwareVideoDecoder) {
+ this._useHardwareVideoDecoder = useHardwareVideoDecoder;
+ this.el.playerSetUseHardwareVideoDecoder(this._useHardwareVideoDecoder);
+ };
+
+ FlasHLS.prototype.setSetLogInfo = function setSetLogInfo(hlsLogEnabled) {
+ this._hlsLogEnabled = hlsLogEnabled;
+ this.el.playerSetLogInfo(this._hlsLogEnabled);
+ };
+
+ FlasHLS.prototype.setLogDebug = function setLogDebug(logDebug) {
+ this._logDebug = logDebug;
+ this.el.playerSetLogDebug(this._logDebug);
+ };
+
+ FlasHLS.prototype.setLogDebug2 = function setLogDebug2(logDebug2) {
+ this._logDebug2 = logDebug2;
+ this.el.playerSetLogDebug2(this._logDebug2);
+ };
+
+ FlasHLS.prototype.setLogWarn = function setLogWarn(logWarn) {
+ this._logWarn = logWarn;
+ this.el.playerSetLogWarn(this._logWarn);
+ };
+
+ FlasHLS.prototype.setLogError = function setLogError(logError) {
+ this._logError = logError;
+ this.el.playerSetLogError(this._logError);
+ };
+
+ FlasHLS.prototype._levelChanged = function _levelChanged(level) {
+ var currentLevel = this.el.getLevels()[level];
+ if (currentLevel) {
+ this.highDefinition = currentLevel.height >= 720 || currentLevel.bitrate / 1000 >= 2000;
+ this.trigger(_events2.default.PLAYBACK_HIGHDEFINITIONUPDATE, this.highDefinition);
+
+ if (!this._levels || this._levels.length === 0) this._fillLevels();
+
+ this.trigger(_events2.default.PLAYBACK_BITRATE, {
+ height: currentLevel.height,
+ width: currentLevel.width,
+ bandwidth: currentLevel.bitrate,
+ bitrate: currentLevel.bitrate,
+ level: level
+ });
+ this.trigger(_events2.default.PLAYBACK_LEVEL_SWITCH_END);
+ }
+ };
+
+ FlasHLS.prototype._updateTime = function _updateTime(timeMetrics) {
+ if (this._currentState === 'IDLE') {
+ return;
+ }
+
+ var duration = this._normalizeDuration(timeMetrics.duration);
+ var position = Math.min(Math.max(timeMetrics.position, 0), duration);
+ var previousDVRStatus = this._dvrEnabled;
+ var livePlayback = this._playbackType === _playback2.default.LIVE;
+ this._dvrEnabled = livePlayback && duration > this._hlsMinimumDvrSize;
+
+ if (duration === 100 || livePlayback === undefined) {
+ return;
+ }
+
+ if (this._dvrEnabled !== previousDVRStatus) {
+ this._updateSettings();
+ this.trigger(_events2.default.PLAYBACK_SETTINGSUPDATE, this.name);
+ }
+
+ if (livePlayback && (!this._dvrEnabled || !this._dvrInUse)) {
+ position = duration;
+ }
+
+ this.trigger(_events2.default.PLAYBACK_TIMEUPDATE, { current: position, total: duration }, this.name);
+ };
+
+ FlasHLS.prototype.play = function play() {
+ this.trigger(_events2.default.PLAYBACK_PLAY_INTENT);
+ if (this._currentState === 'PAUSED') {
+ this.el.playerResume();
+ } else if (!this._srcLoaded && this._currentState !== 'PLAYING') {
+ this._firstPlay();
+ } else {
+ this.el.playerPlay();
+ }
+ };
+
+ FlasHLS.prototype.getPlaybackType = function getPlaybackType() {
+ return this._playbackType ? this._playbackType : null;
+ };
+
+ FlasHLS.prototype.getCurrentLevelIndex = function getCurrentLevelIndex() {
+ return this._currentLevel;
+ };
+
+ FlasHLS.prototype.getCurrentLevel = function getCurrentLevel() {
+ return this.levels[this.currentLevel];
+ };
+
+ FlasHLS.prototype.getCurrentBitrate = function getCurrentBitrate() {
+ return this.levels[this.currentLevel].bitrate;
+ };
+
+ FlasHLS.prototype.setCurrentLevel = function setCurrentLevel(level) {
+ this.currentLevel = level;
+ };
+
+ FlasHLS.prototype.isHighDefinitionInUse = function isHighDefinitionInUse() {
+ return this.highDefinition;
+ };
+
+ FlasHLS.prototype.getLevels = function getLevels() {
+ return this.levels;
+ };
+
+ FlasHLS.prototype._setPlaybackState = function _setPlaybackState(state) {
+ if (['PLAYING_BUFFERING', 'PAUSED_BUFFERING'].indexOf(state) >= 0) {
+ this._bufferingState = true;
+ this.trigger(_events2.default.PLAYBACK_BUFFERING, this.name);
+ this._updateCurrentState(state);
+ } else if (['PLAYING', 'PAUSED'].indexOf(state) >= 0) {
+ if (['PLAYING_BUFFERING', 'PAUSED_BUFFERING', 'IDLE'].indexOf(this._currentState) >= 0) {
+ this._bufferingState = false;
+ this.trigger(_events2.default.PLAYBACK_BUFFERFULL, this.name);
+ }
+ this._updateCurrentState(state);
+ } else if (state === 'IDLE') {
+ this._srcLoaded = false;
+ if (this._loop && ['PLAYING_BUFFERING', 'PLAYING'].indexOf(this._currentState) >= 0) {
+ this.play();
+ this.seek(0);
+ } else {
+ this._updateCurrentState(state);
+ this._hasEnded = true;
+ this.trigger(_events2.default.PLAYBACK_TIMEUPDATE, { current: 0, total: this.getDuration() }, this.name);
+ this.trigger(_events2.default.PLAYBACK_ENDED, this.name);
+ }
+ }
+ };
+
+ FlasHLS.prototype._updateCurrentState = function _updateCurrentState(state) {
+ this._currentState = state;
+ if (state !== 'IDLE') {
+ this._hasEnded = false;
+ }
+ this._updatePlaybackType();
+ if (state === 'PLAYING') {
+ this.trigger(_events2.default.PLAYBACK_PLAY, this.name);
+ } else if (state === 'PAUSED') {
+ this.trigger(_events2.default.PLAYBACK_PAUSE, this.name);
+ }
+ };
+
+ FlasHLS.prototype._updatePlaybackType = function _updatePlaybackType() {
+ this._playbackType = this.el.getType();
+ if (this._playbackType) {
+ this._playbackType = this._playbackType.toLowerCase();
+ if (this._playbackType === _playback2.default.VOD) {
+ this._startReportingProgress();
+ } else {
+ this._stopReportingProgress();
+ }
+ }
+ this.trigger(_events2.default.PLAYBACK_PLAYBACKSTATE, { type: this._playbackType });
+ };
+
+ FlasHLS.prototype._startReportingProgress = function _startReportingProgress() {
+ if (!this._reportingProgress) {
+ this._reportingProgress = true;
+ }
+ };
+
+ FlasHLS.prototype._stopReportingProgress = function _stopReportingProgress() {
+ this._reportingProgress = false;
+ };
+
+ FlasHLS.prototype._onFragmentLoaded = function _onFragmentLoaded(loadmetrics) {
+ this.trigger(_events2.default.PLAYBACK_FRAGMENT_LOADED, loadmetrics);
+ if (this._reportingProgress && this.el.getPosition) {
+ var buffered = this.el.getPosition() + this.el.getbufferLength();
+ this.trigger(_events2.default.PLAYBACK_PROGRESS, {
+ start: this.el.getPosition(),
+ current: buffered,
+ total: this.el.getDuration()
+ });
+ }
+ };
+
+ FlasHLS.prototype._onLevelEndlist = function _onLevelEndlist() {
+ this._updatePlaybackType();
+ };
+
+ FlasHLS.prototype._firstPlay = function _firstPlay() {
+ var _this4 = this;
+
+ this._shouldPlayOnManifestLoaded = true;
+ if (this.el.playerLoad) {
+ _mediator2.default.once(this.cid + ':manifestloaded', function (duration, loadmetrics) {
+ return _this4._manifestLoaded(duration, loadmetrics);
+ });
+ this._setFlashSettings(); //ensure flushLiveURLCache will work (#327)
+ this.el.playerLoad(this._src);
+ this._srcLoaded = true;
+ }
+ };
+
+ FlasHLS.prototype.volume = function volume(value) {
+ var _this5 = this;
+
+ if (this.isReady) {
+ this.el.playerVolume(value);
+ } else {
+ this.listenToOnce(this, _events2.default.PLAYBACK_BUFFERFULL, function () {
+ return _this5.volume(value);
+ });
+ }
+ };
+
+ FlasHLS.prototype.pause = function pause() {
+ if (this._playbackType !== _playback2.default.LIVE || this._dvrEnabled) {
+ this.el.playerPause();
+ if (this._playbackType === _playback2.default.LIVE && this._dvrEnabled) {
+ this._updateDvr(true);
+ }
+ }
+ };
+
+ FlasHLS.prototype.stop = function stop() {
+ this._srcLoaded = false;
+ this.el.playerStop();
+ this.trigger(_events2.default.PLAYBACK_STOP);
+ this.trigger(_events2.default.PLAYBACK_TIMEUPDATE, { current: 0, total: 0 }, this.name);
+ };
+
+ FlasHLS.prototype.isPlaying = function isPlaying() {
+ if (this._currentState) {
+ return !!this._currentState.match(/playing/i);
+ }
+ return false;
+ };
+
+ FlasHLS.prototype.getDuration = function getDuration() {
+ return this._normalizeDuration(this.el.getDuration());
+ };
+
+ FlasHLS.prototype._normalizeDuration = function _normalizeDuration(duration) {
+ if (this._playbackType === _playback2.default.LIVE) {
+ // estimate 10 seconds of buffer time for live streams for seek positions
+ duration = Math.max(0, duration - 10);
+ }
+ return duration;
+ };
+
+ FlasHLS.prototype.seekPercentage = function seekPercentage(percentage) {
+ var duration = this.el.getDuration();
+ var time = 0;
+ if (percentage > 0) {
+ time = duration * percentage / 100;
+ }
+ this.seek(time);
+ };
+
+ FlasHLS.prototype.seek = function seek(time) {
+ var duration = this.getDuration();
+ if (this._playbackType === _playback2.default.LIVE) {
+ // seek operations to a time within 3 seconds from live stream will position playhead back to live
+ var dvrInUse = duration - time > 3;
+ this._updateDvr(dvrInUse);
+ }
+ this.el.playerSeek(time);
+ this.trigger(_events2.default.PLAYBACK_TIMEUPDATE, { current: time, total: duration }, this.name);
+ };
+
+ FlasHLS.prototype._updateDvr = function _updateDvr(dvrInUse) {
+ var previousDvrInUse = !!this._dvrInUse;
+ this._dvrInUse = dvrInUse;
+ if (this._dvrInUse !== previousDvrInUse) {
+ this._updateSettings();
+ this.trigger(_events2.default.PLAYBACK_DVR, this._dvrInUse);
+ this.trigger(_events2.default.PLAYBACK_STATS_ADD, { 'dvr': this._dvrInUse });
+ }
+ };
+
+ FlasHLS.prototype._flashPlaybackError = function _flashPlaybackError(code, url, message) {
+ this.trigger(_events2.default.PLAYBACK_ERROR, { code: code, url: url, message: message });
+ this.trigger(_events2.default.PLAYBACK_STOP);
+ };
+
+ FlasHLS.prototype._manifestLoaded = function _manifestLoaded(duration, loadmetrics) {
+ if (this._shouldPlayOnManifestLoaded) {
+ this._shouldPlayOnManifestLoaded = false;
+ // this method initialises the player (and starts playback)
+ // this needs to happen before PLAYBACK_LOADEDMETADATA is fired
+ // as the user may call seek() in a LOADEDMETADATA listener.
+ /// when playerPlay() is called the player seeks to 0
+ this.el.playerPlay();
+ }
+
+ this._fillLevels();
+ this.trigger(_events2.default.PLAYBACK_LOADEDMETADATA, { duration: duration, data: loadmetrics });
+ };
+
+ FlasHLS.prototype._fillLevels = function _fillLevels() {
+ var levels = this.el.getLevels();
+ var levelsLength = levels.length;
+ this._levels = [];
+
+ for (var index = 0; index < levelsLength; index++) {
+ this._levels.push({ id: index, label: levels[index].height + 'p', level: levels[index] });
+ }
+ this.trigger(_events2.default.PLAYBACK_LEVELS_AVAILABLE, this._levels);
+ };
+
+ FlasHLS.prototype.destroy = function destroy() {
+ this.stopListening();
+ this.$el.remove();
+ };
+
+ FlasHLS.prototype._updateSettings = function _updateSettings() {
+ this.settings = _clapprZepto2.default.extend({}, this._defaultSettings);
+ if (this._playbackType === _playback2.default.VOD || this._dvrInUse) {
+ this.settings.left = ['playpause', 'position', 'duration'];
+ this.settings.seekEnabled = true;
+ } else if (this._dvrEnabled) {
+ this.settings.left = ['playpause'];
+ this.settings.seekEnabled = true;
+ } else {
+ this.settings.seekEnabled = false;
+ }
+ };
+
+ FlasHLS.prototype._createCallbacks = function _createCallbacks() {
+ var _this6 = this;
+
+ if (!window.Clappr) {
+ window.Clappr = {};
+ }
+ if (!window.Clappr.flashlsCallbacks) {
+ window.Clappr.flashlsCallbacks = {};
+ }
+ this.flashlsEvents = new _flashls_events2.default(this.cid);
+ window.Clappr.flashlsCallbacks[this.cid] = function (eventName, args) {
+ _this6.flashlsEvents[eventName].apply(_this6.flashlsEvents, args);
+ };
+ };
+
+ FlasHLS.prototype.render = function render() {
+ _BaseFlashPlayback.prototype.render.call(this);
+ this._createCallbacks();
+ return this;
+ };
+
+ _createClass(FlasHLS, [{
+ key: 'isReady',
+ get: function get() {
+ return this._isReadyState;
+ }
+ }, {
+ key: 'dvrEnabled',
+ get: function get() {
+ return !!this._dvrEnabled;
+ }
+ }]);
+
+ return FlasHLS;
+ }(_base_flash_playback2.default);
+
+ exports.default = FlasHLS;
+
+
+ FlasHLS.canPlay = function (resource, mimeType) {
+ var resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || [];
+ return _browser2.default.hasFlash && (resourceParts.length > 1 && resourceParts[1].toLowerCase() === 'm3u8' || mimeType === 'application/x-mpegURL' || mimeType === 'application/vnd.apple.mpegurl');
+ };
+ module.exports = exports['default'];
+
+/***/ },
+/* 65 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _mediator = __webpack_require__(30);
+
+ var _mediator2 = _interopRequireDefault(_mediator);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var HLSEvents = function () {
+ function HLSEvents(instanceId) {
+ _classCallCheck(this, HLSEvents);
+
+ this.instanceId = instanceId;
+ }
+
+ HLSEvents.prototype.ready = function ready() {
+ _mediator2.default.trigger(this.instanceId + ':flashready');
+ };
+
+ HLSEvents.prototype.videoSize = function videoSize(width, height) {
+ _mediator2.default.trigger(this.instanceId + ':videosizechanged', width, height);
+ };
+
+ HLSEvents.prototype.complete = function complete() {
+ _mediator2.default.trigger(this.instanceId + ':complete');
+ };
+
+ HLSEvents.prototype.error = function error(code, url, message) {
+ _mediator2.default.trigger(this.instanceId + ':error', code, url, message);
+ };
+
+ HLSEvents.prototype.manifest = function manifest(duration, loadmetrics) {
+ _mediator2.default.trigger(this.instanceId + ':manifestloaded', duration, loadmetrics);
+ };
+
+ HLSEvents.prototype.audioLevelLoaded = function audioLevelLoaded(loadmetrics) {
+ _mediator2.default.trigger(this.instanceId + ':audiolevelloaded', loadmetrics);
+ };
+
+ HLSEvents.prototype.levelLoaded = function levelLoaded(loadmetrics) {
+ _mediator2.default.trigger(this.instanceId + ':levelloaded', loadmetrics);
+ };
+
+ HLSEvents.prototype.levelEndlist = function levelEndlist(level) {
+ _mediator2.default.trigger(this.instanceId + ':levelendlist', level);
+ };
+
+ HLSEvents.prototype.fragmentLoaded = function fragmentLoaded(loadmetrics) {
+ _mediator2.default.trigger(this.instanceId + ':fragmentloaded', loadmetrics);
+ };
+
+ HLSEvents.prototype.fragmentPlaying = function fragmentPlaying(playmetrics) {
+ _mediator2.default.trigger(this.instanceId + ':fragmentplaying', playmetrics);
+ };
+
+ HLSEvents.prototype.position = function position(timemetrics) {
+ _mediator2.default.trigger(this.instanceId + ':timeupdate', timemetrics);
+ };
+
+ HLSEvents.prototype.state = function state(newState) {
+ _mediator2.default.trigger(this.instanceId + ':playbackstate', newState);
+ };
+
+ HLSEvents.prototype.seekState = function seekState(newState) {
+ _mediator2.default.trigger(this.instanceId + ':seekstate', newState);
+ };
+
+ HLSEvents.prototype.switch = function _switch(newLevel) {
+ _mediator2.default.trigger(this.instanceId + ':levelchanged', newLevel);
+ };
+
+ HLSEvents.prototype.audioTracksListChange = function audioTracksListChange(trackList) {
+ _mediator2.default.trigger(this.instanceId + ':audiotracklistchanged', trackList);
+ };
+
+ HLSEvents.prototype.audioTrackChange = function audioTrackChange(trackId) {
+ _mediator2.default.trigger(this.instanceId + ':audiotrackchanged', trackId);
+ };
+
+ return HLSEvents;
+ }();
+
+ exports.default = HLSEvents;
+ module.exports = exports['default'];
+
+/***/ },
+/* 66 */
+/***/ function(module, exports, __webpack_require__) {
+
+ module.exports = __webpack_require__.p + "809981e5b09d5336c45d72d0869ada2a.swf";
+
+/***/ },
+/* 67 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(68);
+
+/***/ },
+/* 68 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _html5_video = __webpack_require__(51);
+
+ var _html5_video2 = _interopRequireDefault(_html5_video);
+
+ var _hls = __webpack_require__(69);
+
+ var _hls2 = _interopRequireDefault(_hls);
+
+ var _lodash = __webpack_require__(70);
+
+ var _lodash2 = _interopRequireDefault(_lodash);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ var _browser = __webpack_require__(3);
+
+ var _browser2 = _interopRequireDefault(_browser);
+
+ var _utils = __webpack_require__(2);
+
+ var _log = __webpack_require__(6);
+
+ var _log2 = _interopRequireDefault(_log);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var AUTO = -1;
+
+ var HLS = function (_HTML5VideoPlayback) {
+ _inherits(HLS, _HTML5VideoPlayback);
+
+ _createClass(HLS, [{
+ key: 'name',
+ get: function get() {
+ return 'hls';
+ }
+ }, {
+ key: 'levels',
+ get: function get() {
+ return this._levels || [];
+ }
+ }, {
+ key: 'currentLevel',
+ get: function get() {
+ if (this._currentLevel === null || this._currentLevel === undefined) {
+ return AUTO;
+ } else {
+ return this._currentLevel; //0 is a valid level ID
+ }
+ },
+ set: function set(id) {
+ this._currentLevel = id;
+ this.trigger(_events2.default.PLAYBACK_LEVEL_SWITCH_START);
+ this._hls.currentLevel = this._currentLevel;
+ }
+ }, {
+ key: '_startTime',
+ get: function get() {
+ if (this._playbackType === _playback2.default.LIVE && this._playlistType !== 'EVENT') {
+ return this._extrapolatedStartTime;
+ }
+ return this._playableRegionStartTime;
+ }
+ }, {
+ key: '_now',
+ get: function get() {
+ return (0, _utils.now)();
+ }
+
+ // the time in the video element which should represent the start of the sliding window
+ // extrapolated to increase in real time (instead of jumping as the early segments are removed)
+
+ }, {
+ key: '_extrapolatedStartTime',
+ get: function get() {
+ if (!this._localStartTimeCorrelation) {
+ return this._playableRegionStartTime;
+ }
+ var corr = this._localStartTimeCorrelation;
+ var timePassed = this._now - corr.local;
+ var extrapolatedWindowStartTime = (corr.remote + timePassed) / 1000;
+ // cap at the end of the extrapolated window duration
+ return Math.min(extrapolatedWindowStartTime, this._playableRegionStartTime + this._extrapolatedWindowDuration);
+ }
+
+ // the time in the video element which should represent the end of the content
+ // extrapolated to increase in real time (instead of jumping as segments are added)
+
+ }, {
+ key: '_extrapolatedEndTime',
+ get: function get() {
+ var actualEndTime = this._playableRegionStartTime + this._playableRegionDuration;
+ if (!this._localEndTimeCorrelation) {
+ return actualEndTime;
+ }
+ var corr = this._localEndTimeCorrelation;
+ var timePassed = this._now - corr.local;
+ var extrapolatedEndTime = (corr.remote + timePassed) / 1000;
+ return Math.max(actualEndTime - this._extrapolatedWindowDuration, Math.min(extrapolatedEndTime, actualEndTime));
+ }
+ }, {
+ key: '_duration',
+ get: function get() {
+ return this._extrapolatedEndTime - this._startTime;
+ }
+
+ // Returns the duration (seconds) of the window that the extrapolated start time is allowed
+ // to move in before being capped.
+ // The extrapolated start time should never reach the cap at the end of the window as the
+ // window should slide as chunks are removed from the start.
+ // This also applies to the extrapolated end time in the same way.
+ //
+ // If chunks aren't being removed for some reason that the start time will reach and remain fixed at
+ // playableRegionStartTime + extrapolatedWindowDuration
+ //
+ // <-- window duration -->
+ // I.e playableRegionStartTime |-----------------------|
+ // | --> . . .
+ // . --> | --> . .
+ // . . --> | --> .
+ // . . . --> |
+ // . . . .
+ // extrapolatedStartTime
+
+ }, {
+ key: '_extrapolatedWindowDuration',
+ get: function get() {
+ if (this._segmentTargetDuration === null) {
+ return 0;
+ }
+ return this._extrapolatedWindowNumSegments * this._segmentTargetDuration;
+ }
+ }]);
+
+ function HLS() {
+ _classCallCheck(this, HLS);
+
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ // backwards compatibility (TODO: remove on 0.3.0)
+ var _this = _possibleConstructorReturn(this, _HTML5VideoPlayback.call.apply(_HTML5VideoPlayback, [this].concat(args)));
+
+ _this.options.playback || (_this.options.playback = _this.options);
+ _this._minDvrSize = typeof _this.options.hlsMinimumDvrSize === 'undefined' ? 60 : _this.options.hlsMinimumDvrSize;
+ // The size of the start time extrapolation window measured as a multiple of segments.
+ // Should be 2 or higher, or 0 to disable. Should only need to be increased above 2 if more than one segment is
+ // removed from the start of the playlist at a time. E.g if the playlist is cached for 10 seconds and new chunks are
+ // added/removed every 5.
+ _this._extrapolatedWindowNumSegments = !_this.options.playback || typeof _this.options.playback.extrapolatedWindowNumSegments === 'undefined' ? 2 : _this.options.playback.extrapolatedWindowNumSegments;
+
+ _this._playbackType = _playback2.default.VOD;
+ _this._lastTimeUpdate = null;
+ _this._lastDuration = null;
+ // for hls streams which have dvr with a sliding window,
+ // the content at the start of the playlist is removed as new
+ // content is appended at the end.
+ // this means the actual playable start time will increase as the
+ // start content is deleted
+ // For streams with dvr where the entire recording is kept from the
+ // beginning this should stay as 0
+ _this._playableRegionStartTime = 0;
+ // {local, remote} remote is the time in the video element that should represent 0
+ // local is the system time when the 'remote' measurment took place
+ _this._localStartTimeCorrelation = null;
+ // {local, remote} remote is the time in the video element that should represents the end
+ // local is the system time when the 'remote' measurment took place
+ _this._localEndTimeCorrelation = null;
+ // if content is removed from the beginning then this empty area should
+ // be ignored. "playableRegionDuration" excludes the empty area
+ _this._playableRegionDuration = 0;
+ // true when the actual duration is longer than hlsjs's live sync point
+ // when this is false playableRegionDuration will be the actual duration
+ // when this is true playableRegionDuration will exclude the time after the sync point
+ _this._durationExcludesAfterLiveSyncPoint = false;
+ // #EXT-X-TARGETDURATION
+ _this._segmentTargetDuration = null;
+ // #EXT-X-PLAYLIST-TYPE
+ _this._playlistType = null;
+ _this._recoverAttemptsRemaining = _this.options.hlsRecoverAttempts || 16;
+ _this._startTimeUpdateTimer();
+ return _this;
+ }
+
+ HLS.prototype._setupHls = function _setupHls() {
+ var _this2 = this;
+
+ this._hls = new _hls2.default(this.options.playback.hlsjsConfig || {});
+ this._hls.on(_hls2.default.Events.MEDIA_ATTACHED, function () {
+ return _this2._hls.loadSource(_this2.options.src);
+ });
+ this._hls.on(_hls2.default.Events.LEVEL_LOADED, function (evt, data) {
+ return _this2._updatePlaybackType(evt, data);
+ });
+ this._hls.on(_hls2.default.Events.LEVEL_UPDATED, function (evt, data) {
+ return _this2._onLevelUpdated(evt, data);
+ });
+ this._hls.on(_hls2.default.Events.LEVEL_SWITCH, function (evt, data) {
+ return _this2._onLevelSwitch(evt, data);
+ });
+ this._hls.on(_hls2.default.Events.FRAG_LOADED, function (evt, data) {
+ return _this2._onFragmentLoaded(evt, data);
+ });
+ this._hls.on(_hls2.default.Events.ERROR, function (evt, data) {
+ return _this2._onHLSJSError(evt, data);
+ });
+ this._hls.attachMedia(this.el);
+ };
+
+ HLS.prototype._recover = function _recover(evt, data) {
+ if (!this._recoveredDecodingError) {
+ this._recoveredDecodingError = true;
+ this._hls.recoverMediaError();
+ } else if (!this._recoveredAudioCodecError) {
+ this._recoveredAudioCodecError = true;
+ this._hls.swapAudioCodec();
+ this._hls.recoverMediaError();
+ } else {
+ _log2.default.error('hlsjs: failed to recover');
+ this.trigger(_events2.default.PLAYBACK_ERROR, 'hlsjs: could not recover from error, evt ' + evt + ', data ' + data + ' ', this.name);
+ }
+ };
+
+ // override
+
+
+ HLS.prototype._setupSrc = function _setupSrc(srcUrl) {// eslint-disable-line no-unused-vars
+ // this playback manages the src on the video element itself
+ };
+
+ HLS.prototype._startTimeUpdateTimer = function _startTimeUpdateTimer() {
+ var _this3 = this;
+
+ this._timeUpdateTimer = setInterval(function () {
+ _this3._onDurationChange();
+ _this3._onTimeUpdate();
+ }, 100);
+ };
+
+ HLS.prototype._stopTimeUpdateTimer = function _stopTimeUpdateTimer() {
+ clearInterval(this._timeUpdateTimer);
+ };
+
+ // the duration on the video element itself should not be used
+ // as this does not necesarily represent the duration of the stream
+ // https://github.com/clappr/clappr/issues/668#issuecomment-157036678
+
+
+ HLS.prototype.getDuration = function getDuration() {
+ return this._duration;
+ };
+
+ HLS.prototype.getCurrentTime = function getCurrentTime() {
+ // e.g. can be < 0 if user pauses near the start
+ // eventually they will then be kicked to the end by hlsjs if they run out of buffer
+ // before the official start time
+ return Math.max(0, this.el.currentTime - this._startTime);
+ };
+
+ // the time that "0" now represents relative to when playback started
+ // for a stream with a sliding window this will increase as content is
+ // removed from the beginning
+
+
+ HLS.prototype.getStartTimeOffset = function getStartTimeOffset() {
+ return this._startTime;
+ };
+
+ HLS.prototype.seekPercentage = function seekPercentage(percentage) {
+ var seekTo = this._duration;
+ if (percentage > 0) {
+ seekTo = this._duration * (percentage / 100);
+ }
+ this.seek(seekTo);
+ };
+
+ HLS.prototype.seek = function seek(time) {
+ if (time < 0) {
+ _log2.default.warn('Attempt to seek to a negative time. Resetting to live point. Use seekToLivePoint() to seek to the live point.');
+ time = this.getDuration();
+ }
+ // assume live if time within 3 seconds of end of stream
+ this.dvrEnabled && this._updateDvr(time < this.getDuration() - 3);
+ time += this._startTime;
+ _HTML5VideoPlayback.prototype.seek.call(this, time);
+ };
+
+ HLS.prototype.seekToLivePoint = function seekToLivePoint() {
+ this.seek(this.getDuration());
+ };
+
+ HLS.prototype._updateDvr = function _updateDvr(status) {
+ this.trigger(_events2.default.PLAYBACK_DVR, status);
+ this.trigger(_events2.default.PLAYBACK_STATS_ADD, { 'dvr': status });
+ };
+
+ HLS.prototype._updateSettings = function _updateSettings() {
+ if (this._playbackType === _playback2.default.VOD) {
+ this.settings.left = ['playpause', 'position', 'duration'];
+ } else if (this.dvrEnabled) {
+ this.settings.left = ['playpause'];
+ } else {
+ this.settings.left = ['playstop'];
+ }
+ this.settings.seekEnabled = this.isSeekEnabled();
+ this.trigger(_events2.default.PLAYBACK_SETTINGSUPDATE);
+ };
+
+ HLS.prototype._onHLSJSError = function _onHLSJSError(evt, data) {
+ // only report/handle errors if they are fatal
+ // hlsjs should automatically handle non fatal errors
+ if (data.fatal) {
+ if (this._recoverAttemptsRemaining > 0) {
+ this._recoverAttemptsRemaining -= 1;
+ switch (data.type) {
+ case _hls2.default.ErrorTypes.NETWORK_ERROR:
+ _log2.default.warn('hlsjs: trying to recover from network error, evt ' + evt + ', data ' + data + ' ');
+ this._hls.startLoad();
+ break;
+ case _hls2.default.ErrorTypes.MEDIA_ERROR:
+ _log2.default.warn('hlsjs: trying to recover from media error, evt ' + evt + ', data ' + data + ' ');
+ this._recover(evt, data);
+ break;
+ default:
+ _log2.default.error('hlsjs: trying to recover from error, evt ' + evt + ', data ' + data + ' ');
+ this.trigger(_events2.default.PLAYBACK_ERROR, 'hlsjs: could not recover from error, evt ' + evt + ', data ' + data + ' ', this.name);
+ break;
+ }
+ } else {
+ _log2.default.error('hlsjs: could not recover from error after maximum number of attempts, evt ' + evt + ', data ' + data + ' ');
+ this.trigger(_events2.default.PLAYBACK_ERROR, { evt: evt, data: data }, this.name);
+ }
+ } else {
+ _log2.default.warn('hlsjs: non-fatal error occurred, evt ' + evt + ', data ' + data + ' ');
+ }
+ };
+
+ HLS.prototype._onTimeUpdate = function _onTimeUpdate() {
+ var update = { current: this.getCurrentTime(), total: this.getDuration() };
+ if ((0, _lodash2.default)(update, this._lastTimeUpdate)) {
+ return;
+ }
+ this._lastTimeUpdate = update;
+ this.trigger(_events2.default.PLAYBACK_TIMEUPDATE, update, this.name);
+ };
+
+ HLS.prototype._onDurationChange = function _onDurationChange() {
+ var duration = this.getDuration();
+ if (this._lastDuration === duration) {
+ return;
+ }
+ this._lastDuration = duration;
+ _HTML5VideoPlayback.prototype._onDurationChange.call(this);
+ };
+
+ HLS.prototype._onProgress = function _onProgress() {
+ if (!this.el.buffered.length) {
+ return;
+ }
+ var buffered = [];
+ var bufferedPos = 0;
+ for (var i = 0; i < this.el.buffered.length; i++) {
+ buffered = [].concat(_toConsumableArray(buffered), [{
+ // for a stream with sliding window dvr something that is buffered my slide off the start of the timeline
+ start: Math.max(0, this.el.buffered.start(i) - this._playableRegionStartTime),
+ end: Math.max(0, this.el.buffered.end(i) - this._playableRegionStartTime)
+ }]);
+ if (this.el.currentTime >= buffered[i].start && this.el.currentTime <= buffered[i].end) {
+ bufferedPos = i;
+ }
+ }
+ var progress = {
+ start: buffered[bufferedPos].start,
+ current: buffered[bufferedPos].end,
+ total: this.getDuration()
+ };
+ this.trigger(_events2.default.PLAYBACK_PROGRESS, progress, buffered);
+ };
+
+ HLS.prototype.play = function play() {
+ if (!this._hls) {
+ this._setupHls();
+ }
+ _HTML5VideoPlayback.prototype.play.call(this);
+ };
+
+ HLS.prototype.pause = function pause() {
+ if (!this._hls) {
+ return;
+ }
+ _HTML5VideoPlayback.prototype.pause.call(this);
+ if (this.dvrEnabled) {
+ this._updateDvr(true);
+ }
+ };
+
+ HLS.prototype.stop = function stop() {
+ if (this._hls) {
+ _HTML5VideoPlayback.prototype.stop.call(this);
+ this._hls.destroy();
+ delete this._hls;
+ }
+ };
+
+ HLS.prototype.destroy = function destroy() {
+ this._stopTimeUpdateTimer();
+ if (this._hls) {
+ this._hls.destroy();
+ delete this._hls;
+ }
+ _HTML5VideoPlayback.prototype.destroy.call(this);
+ };
+
+ HLS.prototype._updatePlaybackType = function _updatePlaybackType(evt, data) {
+ this._playbackType = data.details.live ? _playback2.default.LIVE : _playback2.default.VOD;
+ this._fillLevels();
+ this._onLevelUpdated(evt, data);
+ };
+
+ HLS.prototype._fillLevels = function _fillLevels() {
+ this._levels = this._hls.levels.map(function (level, index) {
+ return { id: index, level: level, label: level.bitrate / 1000 + 'Kbps' };
+ });
+ this.trigger(_events2.default.PLAYBACK_LEVELS_AVAILABLE, this._levels);
+ };
+
+ HLS.prototype._onLevelUpdated = function _onLevelUpdated(evt, data) {
+ this._segmentTargetDuration = data.details.targetduration;
+ this._playlistType = data.details.type || null;
+
+ var startTimeChanged = false;
+ var durationChanged = false;
+ var fragments = data.details.fragments;
+ var previousPlayableRegionStartTime = this._playableRegionStartTime;
+ var previousPlayableRegionDuration = this._playableRegionDuration;
+
+ if (fragments.length === 0) {
+ return;
+ }
+
+ if (this._playableRegionStartTime !== fragments[0].start) {
+ startTimeChanged = true;
+ this._playableRegionStartTime = fragments[0].start;
+ }
+
+ if (startTimeChanged) {
+ if (!this._localStartTimeCorrelation) {
+ // set the correlation to map to middle of the extrapolation window
+ this._localStartTimeCorrelation = {
+ local: this._now,
+ remote: (fragments[0].start + this._extrapolatedWindowDuration / 2) * 1000
+ };
+ } else {
+ // check if the correlation still works
+ var corr = this._localStartTimeCorrelation;
+ var timePassed = this._now - corr.local;
+ // this should point to a time within the extrapolation window
+ var startTime = (corr.remote + timePassed) / 1000;
+ if (startTime < fragments[0].start) {
+ // our start time is now earlier than the first chunk
+ // (maybe the chunk was removed early)
+ // reset correlation so that it sits at the beginning of the first available chunk
+ this._localStartTimeCorrelation = {
+ local: this._now,
+ remote: fragments[0].start * 1000
+ };
+ } else if (startTime > previousPlayableRegionStartTime + this._extrapolatedWindowDuration) {
+ // start time was past the end of the old extrapolation window (so would have been capped)
+ // see if now that time would be inside the window, and if it would be set the correlation
+ // so that it resumes from the time it was at at the end of the old window
+ // update the correlation so that the time starts counting again from the value it's on now
+ this._localStartTimeCorrelation = {
+ local: this._now,
+ remote: Math.max(fragments[0].start, previousPlayableRegionStartTime + this._extrapolatedWindowDuration) * 1000
+ };
+ }
+ }
+ }
+
+ var newDuration = data.details.totalduration;
+ // if it's a live stream then shorten the duration to remove access
+ // to the area after hlsjs's live sync point
+ // seeks to areas after this point sometimes have issues
+ if (this._playbackType === _playback2.default.LIVE) {
+ var fragmentTargetDuration = data.details.targetduration;
+ var hlsjsConfig = this.options.playback || {};
+ var liveSyncDurationCount = hlsjsConfig.liveSyncDurationCount || _hls2.default.DefaultConfig.liveSyncDurationCount;
+ var hiddenAreaDuration = fragmentTargetDuration * liveSyncDurationCount;
+ if (hiddenAreaDuration <= newDuration) {
+ newDuration -= hiddenAreaDuration;
+ this._durationExcludesAfterLiveSyncPoint = true;
+ } else {
+ this._durationExcludesAfterLiveSyncPoint = false;
+ }
+ }
+
+ if (newDuration !== this._playableRegionDuration) {
+ durationChanged = true;
+ this._playableRegionDuration = newDuration;
+ }
+
+ // Note the end time is not the playableRegionDuration
+ // The end time will always increase even if content is removed from the beginning
+ var endTime = fragments[0].start + newDuration;
+ var previousEndTime = previousPlayableRegionStartTime + previousPlayableRegionDuration;
+ var endTimeChanged = endTime !== previousEndTime;
+ if (endTimeChanged) {
+ if (!this._localEndTimeCorrelation) {
+ // set the correlation to map to the end
+ this._localEndTimeCorrelation = {
+ local: this._now,
+ remote: endTime * 1000
+ };
+ } else {
+ // check if the correlation still works
+ var _corr = this._localEndTimeCorrelation;
+ var _timePassed = this._now - _corr.local;
+ // this should point to a time within the extrapolation window from the end
+ var extrapolatedEndTime = (_corr.remote + _timePassed) / 1000;
+ if (extrapolatedEndTime > endTime) {
+ this._localEndTimeCorrelation = {
+ local: this._now,
+ remote: endTime * 1000
+ };
+ } else if (extrapolatedEndTime < endTime - this._extrapolatedWindowDuration) {
+ // our extrapolated end time is now earlier than the extrapolation window from the actual end time
+ // (maybe a chunk became available early)
+ // reset correlation so that it sits at the beginning of the extrapolation window from the end time
+ this._localEndTimeCorrelation = {
+ local: this._now,
+ remote: (endTime - this._extrapolatedWindowDuration) * 1000
+ };
+ } else if (extrapolatedEndTime > previousEndTime) {
+ // end time was past the old end time (so would have been capped)
+ // set the correlation so that it resumes from the time it was at at the end of the old window
+ this._localEndTimeCorrelation = {
+ local: this._now,
+ remote: previousEndTime * 1000
+ };
+ }
+ }
+ }
+
+ // now that the values have been updated call any methods that use on them so they get the updated values
+ // immediately
+ durationChanged && this._onDurationChange();
+ startTimeChanged && this._onProgress();
+ };
+
+ HLS.prototype._onFragmentLoaded = function _onFragmentLoaded(evt, data) {
+ this.trigger(_events2.default.PLAYBACK_FRAGMENT_LOADED, data);
+ };
+
+ HLS.prototype._onLevelSwitch = function _onLevelSwitch(evt, data) {
+ if (!this.levels.length) {
+ this._fillLevels();
+ }
+ this.trigger(_events2.default.PLAYBACK_LEVEL_SWITCH_END);
+ this.trigger(_events2.default.PLAYBACK_LEVEL_SWITCH, data);
+ var currentLevel = this._hls.levels[data.level];
+ if (currentLevel) {
+ // TODO should highDefinition be private and maybe have a read only accessor if it's used somewhere
+ this.highDefinition = currentLevel.height >= 720 || currentLevel.bitrate / 1000 >= 2000;
+ this.trigger(_events2.default.PLAYBACK_HIGHDEFINITIONUPDATE, this.highDefinition);
+ this.trigger(_events2.default.PLAYBACK_BITRATE, {
+ height: currentLevel.height,
+ width: currentLevel.width,
+ bandwidth: currentLevel.bitrate,
+ bitrate: currentLevel.bitrate,
+ level: data.level
+ });
+ }
+ };
+
+ HLS.prototype.getPlaybackType = function getPlaybackType() {
+ return this._playbackType;
+ };
+
+ HLS.prototype.isSeekEnabled = function isSeekEnabled() {
+ return this._playbackType === _playback2.default.VOD || this.dvrEnabled;
+ };
+
+ _createClass(HLS, [{
+ key: 'dvrEnabled',
+ get: function get() {
+ // enabled when:
+ // - the duration does not include content after hlsjs's live sync point
+ // - the playable region duration is longer than the configured duration to enable dvr after
+ // - the playback type is LIVE.
+ return this._durationExcludesAfterLiveSyncPoint && this._duration >= this._minDvrSize && this.getPlaybackType() === _playback2.default.LIVE;
+ }
+ }]);
+
+ return HLS;
+ }(_html5_video2.default);
+
+ exports.default = HLS;
+
+
+ HLS.canPlay = function (resource, mimeType) {
+ var resourceParts = resource.split('?')[0].match(/.*\.(.*)$/) || [];
+ var isHls = resourceParts.length > 1 && resourceParts[1].toLowerCase() === 'm3u8' || mimeType === 'application/x-mpegURL' || mimeType === 'application/vnd.apple.mpegurl';
+
+ return !!(_hls2.default.isSupported() && isHls && !_browser2.default.isSafari);
+ };
+ module.exports = exports['default'];
+
+/***/ },
+/* 69 */
+/***/ function(module, exports, __webpack_require__) {
+
+ var require;var require;(function(f){if(true){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.Hls = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return require(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
+ // Copyright Joyent, Inc. and other Node contributors.
+ //
+ // Permission is hereby granted, free of charge, to any person obtaining a
+ // copy of this software and associated documentation files (the
+ // "Software"), to deal in the Software without restriction, including
+ // without limitation the rights to use, copy, modify, merge, publish,
+ // distribute, sublicense, and/or sell copies of the Software, and to permit
+ // persons to whom the Software is furnished to do so, subject to the
+ // following conditions:
+ //
+ // The above copyright notice and this permission notice shall be included
+ // in all copies or substantial portions of the Software.
+ //
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ // USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ function EventEmitter() {
+ this._events = this._events || {};
+ this._maxListeners = this._maxListeners || undefined;
+ }
+ module.exports = EventEmitter;
+
+ // Backwards-compat with node 0.10.x
+ EventEmitter.EventEmitter = EventEmitter;
+
+ EventEmitter.prototype._events = undefined;
+ EventEmitter.prototype._maxListeners = undefined;
+
+ // By default EventEmitters will print a warning if more than 10 listeners are
+ // added to it. This is a useful default which helps finding memory leaks.
+ EventEmitter.defaultMaxListeners = 10;
+
+ // Obviously not all Emitters should be limited to 10. This function allows
+ // that to be increased. Set to zero for unlimited.
+ EventEmitter.prototype.setMaxListeners = function(n) {
+ if (!isNumber(n) || n < 0 || isNaN(n))
+ throw TypeError('n must be a positive number');
+ this._maxListeners = n;
+ return this;
+ };
+
+ EventEmitter.prototype.emit = function(type) {
+ var er, handler, len, args, i, listeners;
+
+ if (!this._events)
+ this._events = {};
+
+ // If there is no 'error' event listener then throw.
+ if (type === 'error') {
+ if (!this._events.error ||
+ (isObject(this._events.error) && !this._events.error.length)) {
+ er = arguments[1];
+ if (er instanceof Error) {
+ throw er; // Unhandled 'error' event
+ }
+ throw TypeError('Uncaught, unspecified "error" event.');
+ }
+ }
+
+ handler = this._events[type];
+
+ if (isUndefined(handler))
+ return false;
+
+ if (isFunction(handler)) {
+ switch (arguments.length) {
+ // fast cases
+ case 1:
+ handler.call(this);
+ break;
+ case 2:
+ handler.call(this, arguments[1]);
+ break;
+ case 3:
+ handler.call(this, arguments[1], arguments[2]);
+ break;
+ // slower
+ default:
+ args = Array.prototype.slice.call(arguments, 1);
+ handler.apply(this, args);
+ }
+ } else if (isObject(handler)) {
+ args = Array.prototype.slice.call(arguments, 1);
+ listeners = handler.slice();
+ len = listeners.length;
+ for (i = 0; i < len; i++)
+ listeners[i].apply(this, args);
+ }
+
+ return true;
+ };
+
+ EventEmitter.prototype.addListener = function(type, listener) {
+ var m;
+
+ if (!isFunction(listener))
+ throw TypeError('listener must be a function');
+
+ if (!this._events)
+ this._events = {};
+
+ // To avoid recursion in the case that type === "newListener"! Before
+ // adding it to the listeners, first emit "newListener".
+ if (this._events.newListener)
+ this.emit('newListener', type,
+ isFunction(listener.listener) ?
+ listener.listener : listener);
+
+ if (!this._events[type])
+ // Optimize the case of one listener. Don't need the extra array object.
+ this._events[type] = listener;
+ else if (isObject(this._events[type]))
+ // If we've already got an array, just append.
+ this._events[type].push(listener);
+ else
+ // Adding the second element, need to change to array.
+ this._events[type] = [this._events[type], listener];
+
+ // Check for listener leak
+ if (isObject(this._events[type]) && !this._events[type].warned) {
+ if (!isUndefined(this._maxListeners)) {
+ m = this._maxListeners;
+ } else {
+ m = EventEmitter.defaultMaxListeners;
+ }
+
+ if (m && m > 0 && this._events[type].length > m) {
+ this._events[type].warned = true;
+ console.error('(node) warning: possible EventEmitter memory ' +
+ 'leak detected. %d listeners added. ' +
+ 'Use emitter.setMaxListeners() to increase limit.',
+ this._events[type].length);
+ if (typeof console.trace === 'function') {
+ // not supported in IE 10
+ console.trace();
+ }
+ }
+ }
+
+ return this;
+ };
+
+ EventEmitter.prototype.on = EventEmitter.prototype.addListener;
+
+ EventEmitter.prototype.once = function(type, listener) {
+ if (!isFunction(listener))
+ throw TypeError('listener must be a function');
+
+ var fired = false;
+
+ function g() {
+ this.removeListener(type, g);
+
+ if (!fired) {
+ fired = true;
+ listener.apply(this, arguments);
+ }
+ }
+
+ g.listener = listener;
+ this.on(type, g);
+
+ return this;
+ };
+
+ // emits a 'removeListener' event iff the listener was removed
+ EventEmitter.prototype.removeListener = function(type, listener) {
+ var list, position, length, i;
+
+ if (!isFunction(listener))
+ throw TypeError('listener must be a function');
+
+ if (!this._events || !this._events[type])
+ return this;
+
+ list = this._events[type];
+ length = list.length;
+ position = -1;
+
+ if (list === listener ||
+ (isFunction(list.listener) && list.listener === listener)) {
+ delete this._events[type];
+ if (this._events.removeListener)
+ this.emit('removeListener', type, listener);
+
+ } else if (isObject(list)) {
+ for (i = length; i-- > 0;) {
+ if (list[i] === listener ||
+ (list[i].listener && list[i].listener === listener)) {
+ position = i;
+ break;
+ }
+ }
+
+ if (position < 0)
+ return this;
+
+ if (list.length === 1) {
+ list.length = 0;
+ delete this._events[type];
+ } else {
+ list.splice(position, 1);
+ }
+
+ if (this._events.removeListener)
+ this.emit('removeListener', type, listener);
+ }
+
+ return this;
+ };
+
+ EventEmitter.prototype.removeAllListeners = function(type) {
+ var key, listeners;
+
+ if (!this._events)
+ return this;
+
+ // not listening for removeListener, no need to emit
+ if (!this._events.removeListener) {
+ if (arguments.length === 0)
+ this._events = {};
+ else if (this._events[type])
+ delete this._events[type];
+ return this;
+ }
+
+ // emit removeListener for all listeners on all events
+ if (arguments.length === 0) {
+ for (key in this._events) {
+ if (key === 'removeListener') continue;
+ this.removeAllListeners(key);
+ }
+ this.removeAllListeners('removeListener');
+ this._events = {};
+ return this;
+ }
+
+ listeners = this._events[type];
+
+ if (isFunction(listeners)) {
+ this.removeListener(type, listeners);
+ } else if (listeners) {
+ // LIFO order
+ while (listeners.length)
+ this.removeListener(type, listeners[listeners.length - 1]);
+ }
+ delete this._events[type];
+
+ return this;
+ };
+
+ EventEmitter.prototype.listeners = function(type) {
+ var ret;
+ if (!this._events || !this._events[type])
+ ret = [];
+ else if (isFunction(this._events[type]))
+ ret = [this._events[type]];
+ else
+ ret = this._events[type].slice();
+ return ret;
+ };
+
+ EventEmitter.prototype.listenerCount = function(type) {
+ if (this._events) {
+ var evlistener = this._events[type];
+
+ if (isFunction(evlistener))
+ return 1;
+ else if (evlistener)
+ return evlistener.length;
+ }
+ return 0;
+ };
+
+ EventEmitter.listenerCount = function(emitter, type) {
+ return emitter.listenerCount(type);
+ };
+
+ function isFunction(arg) {
+ return typeof arg === 'function';
+ }
+
+ function isNumber(arg) {
+ return typeof arg === 'number';
+ }
+
+ function isObject(arg) {
+ return typeof arg === 'object' && arg !== null;
+ }
+
+ function isUndefined(arg) {
+ return arg === void 0;
+ }
+
+ },{}],2:[function(_dereq_,module,exports){
+ var bundleFn = arguments[3];
+ var sources = arguments[4];
+ var cache = arguments[5];
+
+ var stringify = JSON.stringify;
+
+ module.exports = function (fn, options) {
+ var wkey;
+ var cacheKeys = Object.keys(cache);
+
+ for (var i = 0, l = cacheKeys.length; i < l; i++) {
+ var key = cacheKeys[i];
+ var exp = cache[key].exports;
+ // Using babel as a transpiler to use esmodule, the export will always
+ // be an object with the default export as a property of it. To ensure
+ // the existing api and babel esmodule exports are both supported we
+ // check for both
+ if (exp === fn || exp && exp.default === fn) {
+ wkey = key;
+ break;
+ }
+ }
+
+ if (!wkey) {
+ wkey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16);
+ var wcache = {};
+ for (var i = 0, l = cacheKeys.length; i < l; i++) {
+ var key = cacheKeys[i];
+ wcache[key] = key;
+ }
+ sources[wkey] = [
+ Function(['require','module','exports'], '(' + fn + ')(self)'),
+ wcache
+ ];
+ }
+ var skey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16);
+
+ var scache = {}; scache[wkey] = wkey;
+ sources[skey] = [
+ Function(['require'], (
+ // try to call default if defined to also support babel esmodule
+ // exports
+ 'var f = require(' + stringify(wkey) + ');' +
+ '(f.default ? f.default : f)(self);'
+ )),
+ scache
+ ];
+
+ var workerSources = {};
+ resolveSources(skey);
+
+ function resolveSources(key) {
+ workerSources[key] = true;
+
+ for (var depPath in sources[key][1]) {
+ var depKey = sources[key][1][depPath];
+ if (!workerSources[depKey]) {
+ resolveSources(depKey);
+ }
+ }
+ }
+
+ var src = '(' + bundleFn + ')({'
+ + Object.keys(workerSources).map(function (key) {
+ return stringify(key) + ':['
+ + sources[key][0]
+ + ',' + stringify(sources[key][1]) + ']'
+ ;
+ }).join(',')
+ + '},{},[' + stringify(skey) + '])'
+ ;
+
+ var URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
+
+ var blob = new Blob([src], { type: 'text/javascript' });
+ if (options && options.bare) { return blob; }
+ var workerUrl = URL.createObjectURL(blob);
+ var worker = new Worker(workerUrl);
+ worker.objectURL = workerUrl;
+ return worker;
+ };
+
+ },{}],3:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _eventHandler = _dereq_(25);
+
+ var _eventHandler2 = _interopRequireDefault(_eventHandler);
+
+ var _bufferHelper = _dereq_(28);
+
+ var _bufferHelper2 = _interopRequireDefault(_bufferHelper);
+
+ var _errors = _dereq_(24);
+
+ var _logger = _dereq_(43);
+
+ var _ewmaBandwidthEstimator = _dereq_(8);
+
+ var _ewmaBandwidthEstimator2 = _interopRequireDefault(_ewmaBandwidthEstimator);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
+ * simple ABR Controller
+ * - compute next level based on last fragment bw heuristics
+ * - implement an abandon rules triggered if we have less than 2 frag buffered and if computed bw shows that we risk buffer stalling
+ */
+
+ var AbrController = function (_EventHandler) {
+ _inherits(AbrController, _EventHandler);
+
+ function AbrController(hls) {
+ _classCallCheck(this, AbrController);
+
+ var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(AbrController).call(this, hls, _events2.default.FRAG_LOADING, _events2.default.FRAG_LOADED, _events2.default.FRAG_BUFFERED, _events2.default.ERROR));
+
+ _this.lastLoadedFragLevel = 0;
+ _this._autoLevelCapping = -1;
+ _this._nextAutoLevel = -1;
+ _this.hls = hls;
+ _this.onCheck = _this.abandonRulesCheck.bind(_this);
+ return _this;
+ }
+
+ _createClass(AbrController, [{
+ key: 'destroy',
+ value: function destroy() {
+ this.clearTimer();
+ _eventHandler2.default.prototype.destroy.call(this);
+ }
+ }, {
+ key: 'onFragLoading',
+ value: function onFragLoading(data) {
+ var frag = data.frag;
+ if (frag.type === 'main') {
+ if (!this.timer) {
+ this.timer = setInterval(this.onCheck, 100);
+ }
+ // lazy init of bw Estimator, rationale is that we use different params for Live/VoD
+ // so we need to wait for stream manifest / playlist type to instantiate it.
+ if (!this.bwEstimator) {
+ var hls = this.hls,
+ level = data.frag.level,
+ isLive = hls.levels[level].details.live,
+ config = hls.config,
+ ewmaFast = void 0,
+ ewmaSlow = void 0;
+
+ if (isLive) {
+ ewmaFast = config.abrEwmaFastLive;
+ ewmaSlow = config.abrEwmaSlowLive;
+ } else {
+ ewmaFast = config.abrEwmaFastVoD;
+ ewmaSlow = config.abrEwmaSlowVoD;
+ }
+ this.bwEstimator = new _ewmaBandwidthEstimator2.default(hls, ewmaSlow, ewmaFast, config.abrEwmaDefaultEstimate);
+ }
+ this.fragCurrent = frag;
+ }
+ }
+ }, {
+ key: 'abandonRulesCheck',
+ value: function abandonRulesCheck() {
+ /*
+ monitor fragment retrieval time...
+ we compute expected time of arrival of the complete fragment.
+ we compare it to expected time of buffer starvation
+ */
+ var hls = this.hls,
+ v = hls.media,
+ frag = this.fragCurrent,
+ loader = frag.loader;
+
+ // if loader has been destroyed or loading has been aborted, stop timer and return
+ if (!loader || loader.stats && loader.stats.aborted) {
+ _logger.logger.warn('frag loader destroy or aborted, disarm abandonRules');
+ this.clearTimer();
+ return;
+ }
+ var stats = loader.stats;
+ /* only monitor frag retrieval time if
+ (video not paused OR first fragment being loaded(ready state === HAVE_NOTHING = 0)) AND autoswitching enabled AND not lowest level (=> means that we have several levels) */
+ if (v && (!v.paused && v.playbackRate !== 0 || !v.readyState) && frag.autoLevel && frag.level) {
+ var requestDelay = performance.now() - stats.trequest,
+ playbackRate = Math.abs(v.playbackRate);
+ // monitor fragment load progress after half of expected fragment duration,to stabilize bitrate
+ if (requestDelay > 500 * frag.duration / playbackRate) {
+ var levels = hls.levels,
+ loadRate = Math.max(1, stats.bw ? stats.bw / 8 : stats.loaded * 1000 / requestDelay),
+ // byte/s; at least 1 byte/s to avoid division by zero
+ // compute expected fragment length using frag duration and level bitrate. also ensure that expected len is gte than already loaded size
+ expectedLen = stats.total ? stats.total : Math.max(stats.loaded, Math.round(frag.duration * levels[frag.level].bitrate / 8)),
+ pos = v.currentTime,
+ fragLoadedDelay = (expectedLen - stats.loaded) / loadRate,
+ bufferStarvationDelay = (_bufferHelper2.default.bufferInfo(v, pos, hls.config.maxBufferHole).end - pos) / playbackRate;
+ // consider emergency switch down only if we have less than 2 frag buffered AND
+ // time to finish loading current fragment is bigger than buffer starvation delay
+ // ie if we risk buffer starvation if bw does not increase quickly
+ if (bufferStarvationDelay < 2 * frag.duration / playbackRate && fragLoadedDelay > bufferStarvationDelay) {
+ var fragLevelNextLoadedDelay = void 0,
+ nextLoadLevel = void 0;
+ // lets iterate through lower level and try to find the biggest one that could avoid rebuffering
+ // we start from current level - 1 and we step down , until we find a matching level
+ for (nextLoadLevel = frag.level - 1; nextLoadLevel >= 0; nextLoadLevel--) {
+ // compute time to load next fragment at lower level
+ // 0.8 : consider only 80% of current bw to be conservative
+ // 8 = bits per byte (bps/Bps)
+ fragLevelNextLoadedDelay = frag.duration * levels[nextLoadLevel].bitrate / (8 * 0.8 * loadRate);
+ if (fragLevelNextLoadedDelay < bufferStarvationDelay) {
+ // we found a lower level that be rebuffering free with current estimated bw !
+ break;
+ }
+ }
+ // only emergency switch down if it takes less time to load new fragment at lowest level instead
+ // of finishing loading current one ...
+ if (fragLevelNextLoadedDelay < fragLoadedDelay) {
+ // ensure nextLoadLevel is not negative
+ nextLoadLevel = Math.max(0, nextLoadLevel);
+ _logger.logger.warn('loading too slow, abort fragment loading and switch to level ' + nextLoadLevel + ':fragLoadedDelay[' + nextLoadLevel + ']<fragLoadedDelay[' + (frag.level - 1) + '];bufferStarvationDelay:' + fragLevelNextLoadedDelay.toFixed(1) + '<' + fragLoadedDelay.toFixed(1) + ':' + bufferStarvationDelay.toFixed(1));
+ // force next load level in auto mode
+ hls.nextLoadLevel = nextLoadLevel;
+ // update bw estimate for this fragment before cancelling load (this will help reducing the bw)
+ this.bwEstimator.sample(requestDelay, stats.loaded);
+ //abort fragment loading
+ loader.abort();
+ // stop abandon rules timer
+ this.clearTimer();
+ hls.trigger(_events2.default.FRAG_LOAD_EMERGENCY_ABORTED, { frag: frag, stats: stats });
+ }
+ }
+ }
+ }
+ }
+ }, {
+ key: 'onFragLoaded',
+ value: function onFragLoaded(data) {
+ var frag = data.frag;
+ if (frag.type === 'main') {
+ // stop monitoring bw once frag loaded
+ this.clearTimer();
+ // store level id after successful fragment load
+ this.lastLoadedFragLevel = frag.level;
+ // reset forced auto level value so that next level will be selected
+ this._nextAutoLevel = -1;
+ // if fragment has been loaded to perform a bitrate test,
+ if (data.frag.bitrateTest) {
+ var stats = data.stats;
+ stats.tparsed = stats.tbuffered = stats.tload;
+ this.onFragBuffered(data);
+ }
+ }
+ }
+ }, {
+ key: 'onFragBuffered',
+ value: function onFragBuffered(data) {
+ var stats = data.stats,
+ frag = data.frag;
+ // only update stats on first frag buffering
+ // if same frag is loaded multiple times, it might be in browser cache, and loaded quickly
+ // and leading to wrong bw estimation
+ // on bitrate test, also only update stats once (if tload = tbuffered == on FRAG_LOADED)
+ if (stats.aborted !== true && frag.loadCounter === 1 && frag.type === 'main' && (!frag.bitrateTest || stats.tload === stats.tbuffered)) {
+ var fragLoadingProcessingMs = stats.tbuffered - stats.trequest;
+ _logger.logger.log('latency/loading/parsing/append/kbps:' + Math.round(stats.tfirst - stats.trequest) + '/' + Math.round(stats.tload - stats.tfirst) + '/' + Math.round(stats.tparsed - stats.tload) + '/' + Math.round(stats.tbuffered - stats.tparsed) + '/' + Math.round(8 * stats.loaded / (stats.tbuffered - stats.trequest)));
+ this.bwEstimator.sample(fragLoadingProcessingMs, stats.loaded);
+ // if fragment has been loaded to perform a bitrate test, (hls.startLevel = -1), store bitrate test delay duration
+ if (frag.bitrateTest) {
+ this.bitrateTestDelay = fragLoadingProcessingMs / 1000;
+ } else {
+ this.bitrateTestDelay = 0;
+ }
+ }
+ }
+ }, {
+ key: 'onError',
+ value: function onError(data) {
+ // stop timer in case of frag loading error
+ switch (data.details) {
+ case _errors.ErrorDetails.FRAG_LOAD_ERROR:
+ case _errors.ErrorDetails.FRAG_LOAD_TIMEOUT:
+ this.clearTimer();
+ break;
+ default:
+ break;
+ }
+ }
+ }, {
+ key: 'clearTimer',
+ value: function clearTimer() {
+ if (this.timer) {
+ clearInterval(this.timer);
+ this.timer = null;
+ }
+ }
+
+ /** Return the capping/max level value that could be used by automatic level selection algorithm **/
+
+ }, {
+ key: 'findBestLevel',
+ value: function findBestLevel(currentLevel, currentFragDuration, currentBw, minAutoLevel, maxAutoLevel, maxFetchDuration, bwFactor, bwUpFactor, levels) {
+ for (var i = maxAutoLevel; i >= minAutoLevel; i--) {
+ var levelInfo = levels[i],
+ levelDetails = levelInfo.details,
+ avgDuration = levelDetails ? levelDetails.totalduration / levelDetails.fragments.length : currentFragDuration,
+ adjustedbw = void 0;
+ // follow algorithm captured from stagefright :
+ // https://android.googlesource.com/platform/frameworks/av/+/master/media/libstagefright/httplive/LiveSession.cpp
+ // Pick the highest bandwidth stream below or equal to estimated bandwidth.
+ // consider only 80% of the available bandwidth, but if we are switching up,
+ // be even more conservative (70%) to avoid overestimating and immediately
+ // switching back.
+ if (i <= currentLevel) {
+ adjustedbw = bwFactor * currentBw;
+ } else {
+ adjustedbw = bwUpFactor * currentBw;
+ }
+ var bitrate = levels[i].bitrate,
+ fetchDuration = bitrate * avgDuration / adjustedbw;
+
+ _logger.logger.trace('level/adjustedbw/bitrate/avgDuration/maxFetchDuration/fetchDuration: ' + i + '/' + Math.round(adjustedbw) + '/' + bitrate + '/' + avgDuration + '/' + maxFetchDuration + '/' + fetchDuration);
+ // if adjusted bw is greater than level bitrate AND
+ if (adjustedbw > bitrate && (
+ // fragment fetchDuration unknown or fragment fetchDuration less than max allowed fetch duration, then this level matches
+ !fetchDuration || fetchDuration < maxFetchDuration)) {
+ // as we are looping from highest to lowest, this will return the best achievable quality level
+
+ return i;
+ }
+ }
+ // not enough time budget even with quality level 0 ... rebuffering might happen
+ return -1;
+ }
+ }, {
+ key: 'autoLevelCapping',
+ get: function get() {
+ return this._autoLevelCapping;
+ }
+
+ /** set the capping/max level value that could be used by automatic level selection algorithm **/
+ ,
+ set: function set(newLevel) {
+ this._autoLevelCapping = newLevel;
+ }
+ }, {
+ key: 'nextAutoLevel',
+ get: function get() {
+ var nextAutoLevel = this._nextAutoLevel,
+ bwEstimator = this.bwEstimator,
+ hls = this.hls,
+ levels = hls.levels,
+ minAutoBitrate = hls.config.minAutoBitrate;
+ // in case next auto level has been forced, and bw not available or not reliable
+ if (nextAutoLevel !== -1 && (!bwEstimator || !bwEstimator.canEstimate())) {
+ // cap next auto level by max auto level
+ return Math.min(nextAutoLevel, this.maxAutoLevel);
+ }
+ // compute next level using ABR logic
+ var nextABRAutoLevel = this.nextABRAutoLevel;
+ if (nextAutoLevel !== -1) {
+ // nextAutoLevel is defined, use it to cap ABR computed quality level
+ nextABRAutoLevel = Math.min(nextAutoLevel, nextABRAutoLevel);
+ }
+ if (minAutoBitrate !== undefined) {
+ while (levels[nextABRAutoLevel].bitrate < minAutoBitrate) {
+ nextABRAutoLevel++;
+ }
+ }
+ return nextABRAutoLevel;
+ },
+ set: function set(nextLevel) {
+ this._nextAutoLevel = nextLevel;
+ }
+ }, {
+ key: 'minAutoLevel',
+ get: function get() {
+ var hls = this.hls,
+ levels = hls.levels,
+ minAutoBitrate = hls.config.minAutoBitrate;
+ for (var i = 0; i < levels.length; i++) {
+ if (levels[i].bitrate > minAutoBitrate) {
+ return i;
+ }
+ }
+ return 0;
+ }
+ }, {
+ key: 'maxAutoLevel',
+ get: function get() {
+ var levels = this.hls.levels,
+ autoLevelCapping = this._autoLevelCapping,
+ maxAutoLevel;
+ if (autoLevelCapping === -1 && levels && levels.length) {
+ maxAutoLevel = levels.length - 1;
+ } else {
+ maxAutoLevel = autoLevelCapping;
+ }
+ return maxAutoLevel;
+ }
+ }, {
+ key: 'nextABRAutoLevel',
+ get: function get() {
+ var hls = this.hls,
+ maxAutoLevel = this.maxAutoLevel,
+ levels = hls.levels,
+ config = hls.config,
+ minAutoLevel = this.minAutoLevel;
+ var v = hls.media,
+ currentLevel = this.lastLoadedFragLevel,
+ currentFragDuration = this.fragCurrent ? this.fragCurrent.duration : 0,
+ pos = v ? v.currentTime : 0,
+
+ // playbackRate is the absolute value of the playback rate; if v.playbackRate is 0, we use 1 to load as
+ // if we're playing back at the normal rate.
+ playbackRate = v && v.playbackRate !== 0 ? Math.abs(v.playbackRate) : 1.0,
+ avgbw = this.bwEstimator ? this.bwEstimator.getEstimate() : config.abrEwmaDefaultEstimate,
+
+ // bufferStarvationDelay is the wall-clock time left until the playback buffer is exhausted.
+ bufferStarvationDelay = (_bufferHelper2.default.bufferInfo(v, pos, config.maxBufferHole).end - pos) / playbackRate;
+
+ // First, look to see if we can find a level matching with our avg bandwidth AND that could also guarantee no rebuffering at all
+ var bestLevel = this.findBestLevel(currentLevel, currentFragDuration, avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, config.abrBandWidthFactor, config.abrBandWidthUpFactor, levels);
+ if (bestLevel >= 0) {
+ return bestLevel;
+ } else {
+ _logger.logger.trace('rebuffering expected to happen, lets try to find a quality level minimizing the rebuffering');
+ // not possible to get rid of rebuffering ... let's try to find level that will guarantee less than maxStarvationDelay of rebuffering
+ // if no matching level found, logic will return 0
+ var maxStarvationDelay = config.maxStarvationDelay,
+ bwFactor = config.abrBandWidthFactor,
+ bwUpFactor = config.abrBandWidthUpFactor;
+ if (bufferStarvationDelay === 0) {
+ // in case buffer is empty, let's check if previous fragment was loaded to perform a bitrate test
+ var bitrateTestDelay = this.bitrateTestDelay;
+ if (bitrateTestDelay) {
+ // if it is the case, then we need to adjust our max starvation delay using maxLoadingDelay config value
+ // max video loading delay used in automatic start level selection :
+ // in that mode ABR controller will ensure that video loading time (ie the time to fetch the first fragment at lowest quality level +
+ // the time to fetch the fragment at the appropriate quality level is less than ```maxLoadingDelay``` )
+ maxStarvationDelay = config.maxLoadingDelay - bitrateTestDelay;
+ _logger.logger.trace('bitrate test took ' + Math.round(1000 * bitrateTestDelay) + 'ms, set first fragment max fetchDuration to ' + Math.round(1000 * maxStarvationDelay) + ' ms');
+ // don't use conservative factor on bitrate test
+ bwFactor = bwUpFactor = 1;
+ }
+ }
+ bestLevel = this.findBestLevel(currentLevel, currentFragDuration, avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay + maxStarvationDelay, bwFactor, bwUpFactor, levels);
+ return Math.max(bestLevel, 0);
+ }
+ }
+ }]);
+
+ return AbrController;
+ }(_eventHandler2.default);
+
+ exports.default = AbrController;
+
+ },{"24":24,"25":25,"26":26,"28":28,"43":43,"8":8}],4:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _binarySearch = _dereq_(39);
+
+ var _binarySearch2 = _interopRequireDefault(_binarySearch);
+
+ var _bufferHelper = _dereq_(28);
+
+ var _bufferHelper2 = _interopRequireDefault(_bufferHelper);
+
+ var _demuxer = _dereq_(20);
+
+ var _demuxer2 = _interopRequireDefault(_demuxer);
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _eventHandler = _dereq_(25);
+
+ var _eventHandler2 = _interopRequireDefault(_eventHandler);
+
+ var _levelHelper = _dereq_(29);
+
+ var _levelHelper2 = _interopRequireDefault(_levelHelper);
+
+ var _timeRanges = _dereq_(45);
+
+ var _timeRanges2 = _interopRequireDefault(_timeRanges);
+
+ var _errors = _dereq_(24);
+
+ var _logger = _dereq_(43);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
+ * Audio Stream Controller
+ */
+
+ var State = {
+ STOPPED: 'STOPPED',
+ STARTING: 'STARTING',
+ IDLE: 'IDLE',
+ PAUSED: 'PAUSED',
+ KEY_LOADING: 'KEY_LOADING',
+ FRAG_LOADING: 'FRAG_LOADING',
+ FRAG_LOADING_WAITING_RETRY: 'FRAG_LOADING_WAITING_RETRY',
+ WAITING_TRACK: 'WAITING_TRACK',
+ PARSING: 'PARSING',
+ PARSED: 'PARSED',
+ ENDED: 'ENDED',
+ ERROR: 'ERROR'
+ };
+
+ var AudioStreamController = function (_EventHandler) {
+ _inherits(AudioStreamController, _EventHandler);
+
+ function AudioStreamController(hls) {
+ _classCallCheck(this, AudioStreamController);
+
+ var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(AudioStreamController).call(this, hls, _events2.default.MEDIA_ATTACHED, _events2.default.MEDIA_DETACHING, _events2.default.AUDIO_TRACKS_UPDATED, _events2.default.AUDIO_TRACK_SWITCH, _events2.default.AUDIO_TRACK_LOADED, _events2.default.KEY_LOADED, _events2.default.FRAG_LOADED, _events2.default.FRAG_PARSING_INIT_SEGMENT, _events2.default.FRAG_PARSING_DATA, _events2.default.FRAG_PARSED, _events2.default.ERROR, _events2.default.BUFFER_CREATED, _events2.default.BUFFER_APPENDED, _events2.default.BUFFER_FLUSHED));
+
+ _this.config = hls.config;
+ _this.audioCodecSwap = false;
+ _this.ticks = 0;
+ _this.ontick = _this.tick.bind(_this);
+ return _this;
+ }
+
+ _createClass(AudioStreamController, [{
+ key: 'destroy',
+ value: function destroy() {
+ this.stopLoad();
+ if (this.timer) {
+ clearInterval(this.timer);
+ this.timer = null;
+ }
+ _eventHandler2.default.prototype.destroy.call(this);
+ this.state = State.STOPPED;
+ }
+ }, {
+ key: 'startLoad',
+ value: function startLoad(startPosition) {
+ if (this.tracks) {
+ var media = this.media,
+ lastCurrentTime = this.lastCurrentTime;
+ this.stopLoad();
+ if (!this.timer) {
+ this.timer = setInterval(this.ontick, 100);
+ }
+ this.fragLoadError = 0;
+ if (media && lastCurrentTime) {
+ _logger.logger.log('configure startPosition @' + lastCurrentTime);
+ this.state = State.IDLE;
+ } else {
+ this.lastCurrentTime = this.startPosition ? this.startPosition : startPosition;
+ this.state = State.STARTING;
+ }
+ this.nextLoadPosition = this.startPosition = this.lastCurrentTime;
+ this.tick();
+ } else {
+ this.startPosition = startPosition;
+ this.state = State.STOPPED;
+ }
+ }
+ }, {
+ key: 'stopLoad',
+ value: function stopLoad() {
+ var frag = this.fragCurrent;
+ if (frag) {
+ if (frag.loader) {
+ frag.loader.abort();
+ }
+ this.fragCurrent = null;
+ }
+ this.fragPrevious = null;
+ if (this.demuxer) {
+ this.demuxer.destroy();
+ this.demuxer = null;
+ }
+ this.state = State.STOPPED;
+ }
+ }, {
+ key: 'tick',
+ value: function tick() {
+ this.ticks++;
+ if (this.ticks === 1) {
+ this.doTick();
+ if (this.ticks > 1) {
+ setTimeout(this.tick, 1);
+ }
+ this.ticks = 0;
+ }
+ }
+ }, {
+ key: 'doTick',
+ value: function doTick() {
+ var pos,
+ track,
+ trackDetails,
+ hls = this.hls,
+ config = hls.config;
+ //logger.log('audioStream:' + this.state);
+ switch (this.state) {
+ case State.ERROR:
+ //don't do anything in error state to avoid breaking further ...
+ case State.PAUSED:
+ //don't do anything in paused state either ...
+ break;
+ case State.STARTING:
+ this.state = State.WAITING_TRACK;
+ this.loadedmetadata = false;
+ break;
+ case State.IDLE:
+ // if video not attached AND
+ // start fragment already requested OR start frag prefetch disable
+ // exit loop
+ // => if media not attached but start frag prefetch is enabled and start frag not requested yet, we will not exit loop
+ if (!this.media && (this.startFragRequested || !config.startFragPrefetch)) {
+ break;
+ }
+ // determine next candidate fragment to be loaded, based on current position and
+ // end of buffer position
+ // if we have not yet loaded any fragment, start loading from start position
+ if (this.loadedmetadata) {
+ pos = this.media.currentTime;
+ } else {
+ pos = this.nextLoadPosition;
+ }
+ var media = this.mediaBuffer ? this.mediaBuffer : this.media;
+ var bufferInfo = _bufferHelper2.default.bufferInfo(media, pos, config.maxBufferHole),
+ bufferLen = bufferInfo.len,
+ bufferEnd = bufferInfo.end,
+ fragPrevious = this.fragPrevious,
+ maxBufLen = config.maxMaxBufferLength;
+
+ // if buffer length is less than maxBufLen try to load a new fragment
+ if (bufferLen < maxBufLen && this.trackId < this.tracks.length) {
+ trackDetails = this.tracks[this.trackId].details;
+ // if track info not retrieved yet, switch state and wait for track retrieval
+ if (typeof trackDetails === 'undefined') {
+ this.state = State.WAITING_TRACK;
+ break;
+ }
+
+ // we just got done loading the final fragment, check if we need to finalize media stream
+ if (!trackDetails.live && fragPrevious && fragPrevious.sn === trackDetails.endSN) {
+ // if we are not seeking or if we are seeking but everything (almost) til the end is buffered, let's signal eos
+ // we don't compare exactly media.duration === bufferInfo.end as there could be some subtle media duration difference when switching
+ // between different renditions. using half frag duration should help cope with these cases.
+ if (!this.media.seeking || this.media.duration - bufferEnd < fragPrevious.duration / 2) {
+ // Finalize the media stream
+ this.hls.trigger(_events2.default.BUFFER_EOS, { type: 'audio' });
+ this.state = State.ENDED;
+ break;
+ }
+ }
+
+ // find fragment index, contiguous with end of buffer position
+ var fragments = trackDetails.fragments,
+ fragLen = fragments.length,
+ start = fragments[0].start,
+ end = fragments[fragLen - 1].start + fragments[fragLen - 1].duration,
+ frag = void 0;
+
+ // if bufferEnd before start of playlist, load first fragment
+ if (bufferEnd < start) {
+ frag = fragments[0];
+ } else {
+ (function () {
+ var foundFrag = void 0;
+ var maxFragLookUpTolerance = config.maxFragLookUpTolerance;
+ if (bufferEnd < end) {
+ if (bufferEnd > end - maxFragLookUpTolerance) {
+ maxFragLookUpTolerance = 0;
+ }
+ foundFrag = _binarySearch2.default.search(fragments, function (candidate) {
+ // offset should be within fragment boundary - config.maxFragLookUpTolerance
+ // this is to cope with situations like
+ // bufferEnd = 9.991
+ // frag[Ø] : [0,10]
+ // frag[1] : [10,20]
+ // bufferEnd is within frag[0] range ... although what we are expecting is to return frag[1] here
+ // frag start frag start+duration
+ // |-----------------------------|
+ // <---> <--->
+ // ...--------><-----------------------------><---------....
+ // previous frag matching fragment next frag
+ // return -1 return 0 return 1
+ //logger.log(`level/sn/start/end/bufEnd:${level}/${candidate.sn}/${candidate.start}/${(candidate.start+candidate.duration)}/${bufferEnd}`);
+ if (candidate.start + candidate.duration - maxFragLookUpTolerance <= bufferEnd) {
+ return 1;
+ } else if (candidate.start - maxFragLookUpTolerance > bufferEnd) {
+ return -1;
+ }
+ return 0;
+ });
+ } else {
+ // reach end of playlist
+ foundFrag = fragments[fragLen - 1];
+ }
+ if (foundFrag) {
+ frag = foundFrag;
+ start = foundFrag.start;
+ //logger.log('find SN matching with pos:' + bufferEnd + ':' + frag.sn);
+ if (fragPrevious && frag.level === fragPrevious.level && frag.sn === fragPrevious.sn) {
+ if (frag.sn < trackDetails.endSN) {
+ frag = fragments[frag.sn + 1 - trackDetails.startSN];
+ _logger.logger.log('SN just loaded, load next one: ' + frag.sn);
+ } else {
+ frag = null;
+ }
+ }
+ }
+ })();
+ }
+ if (frag) {
+ //logger.log(' loading frag ' + i +',pos/bufEnd:' + pos.toFixed(3) + '/' + bufferEnd.toFixed(3));
+ if (frag.decryptdata.uri != null && frag.decryptdata.key == null) {
+ _logger.logger.log('Loading key for ' + frag.sn + ' of [' + trackDetails.startSN + ' ,' + trackDetails.endSN + '],track ' + this.trackId);
+ this.state = State.KEY_LOADING;
+ hls.trigger(_events2.default.KEY_LOADING, { frag: frag });
+ } else {
+ _logger.logger.log('Loading ' + frag.sn + ' of [' + trackDetails.startSN + ' ,' + trackDetails.endSN + '],track ' + this.trackId + ', currentTime:' + pos + ',bufferEnd:' + bufferEnd.toFixed(3));
+ // ensure that we are not reloading the same fragments in loop ...
+ if (this.fragLoadIdx !== undefined) {
+ this.fragLoadIdx++;
+ } else {
+ this.fragLoadIdx = 0;
+ }
+ if (frag.loadCounter) {
+ frag.loadCounter++;
+ var maxThreshold = config.fragLoadingLoopThreshold;
+ // if this frag has already been loaded 3 times, and if it has been reloaded recently
+ if (frag.loadCounter > maxThreshold && Math.abs(this.fragLoadIdx - frag.loadIdx) < maxThreshold) {
+ hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, details: _errors.ErrorDetails.FRAG_LOOP_LOADING_ERROR, fatal: false, frag: frag });
+ return;
+ }
+ } else {
+ frag.loadCounter = 1;
+ }
+ frag.loadIdx = this.fragLoadIdx;
+ this.fragCurrent = frag;
+ this.startFragRequested = true;
+ hls.trigger(_events2.default.FRAG_LOADING, { frag: frag });
+ this.state = State.FRAG_LOADING;
+ }
+ }
+ }
+ break;
+ case State.WAITING_TRACK:
+ track = this.tracks[this.trackId];
+ // check if playlist is already loaded
+ if (track && track.details) {
+ this.state = State.IDLE;
+ }
+ break;
+ case State.FRAG_LOADING_WAITING_RETRY:
+ var now = performance.now();
+ var retryDate = this.retryDate;
+ media = this.media;
+ var isSeeking = media && media.seeking;
+ // if current time is gt than retryDate, or if media seeking let's switch to IDLE state to retry loading
+ if (!retryDate || now >= retryDate || isSeeking) {
+ _logger.logger.log('audioStreamController: retryDate reached, switch back to IDLE state');
+ this.state = State.IDLE;
+ }
+ break;
+ case State.STOPPED:
+ case State.FRAG_LOADING:
+ case State.PARSING:
+ case State.PARSED:
+ case State.ENDED:
+ break;
+ default:
+ break;
+ }
+ }
+ }, {
+ key: 'onMediaAttached',
+ value: function onMediaAttached(data) {
+ var media = this.media = this.mediaBuffer = data.media;
+ this.onvseeking = this.onMediaSeeking.bind(this);
+ this.onvended = this.onMediaEnded.bind(this);
+ media.addEventListener('seeking', this.onvseeking);
+ media.addEventListener('ended', this.onvended);
+ var config = this.config;
+ if (this.tracks && config.autoStartLoad) {
+ this.startLoad(config.startPosition);
+ }
+ }
+ }, {
+ key: 'onMediaDetaching',
+ value: function onMediaDetaching() {
+ var media = this.media;
+ if (media && media.ended) {
+ _logger.logger.log('MSE detaching and video ended, reset startPosition');
+ this.startPosition = this.lastCurrentTime = 0;
+ }
+
+ // reset fragment loading counter on MSE detaching to avoid reporting FRAG_LOOP_LOADING_ERROR after error recovery
+ var tracks = this.tracks;
+ if (tracks) {
+ // reset fragment load counter
+ tracks.forEach(function (track) {
+ if (track.details) {
+ track.details.fragments.forEach(function (fragment) {
+ fragment.loadCounter = undefined;
+ });
+ }
+ });
+ }
+ // remove video listeners
+ if (media) {
+ media.removeEventListener('seeking', this.onvseeking);
+ media.removeEventListener('ended', this.onvended);
+ this.onvseeking = this.onvseeked = this.onvended = null;
+ }
+ this.media = null;
+ this.loadedmetadata = false;
+ this.stopLoad();
+ }
+ }, {
+ key: 'onMediaSeeking',
+ value: function onMediaSeeking() {
+ if (this.state === State.ENDED) {
+ // switch to IDLE state to check for potential new fragment
+ this.state = State.IDLE;
+ }
+ if (this.media) {
+ this.lastCurrentTime = this.media.currentTime;
+ }
+ // avoid reporting fragment loop loading error in case user is seeking several times on same position
+ if (this.fragLoadIdx !== undefined) {
+ this.fragLoadIdx += 2 * this.config.fragLoadingLoopThreshold;
+ }
+ // tick to speed up processing
+ this.tick();
+ }
+ }, {
+ key: 'onMediaEnded',
+ value: function onMediaEnded() {
+ // reset startPosition and lastCurrentTime to restart playback @ stream beginning
+ this.startPosition = this.lastCurrentTime = 0;
+ }
+ }, {
+ key: 'onAudioTracksUpdated',
+ value: function onAudioTracksUpdated(data) {
+ _logger.logger.log('audio tracks updated');
+ this.tracks = data.audioTracks;
+ }
+ }, {
+ key: 'onAudioTrackSwitch',
+ value: function onAudioTrackSwitch(data) {
+ // if any URL found on new audio track, it is an alternate audio track
+ var altAudio = !!data.url;
+ this.trackId = data.id;
+ this.state = State.IDLE;
+
+ this.fragCurrent = null;
+ this.state = State.PAUSED;
+ // destroy useless demuxer when switching audio to main
+ if (!altAudio) {
+ if (this.demuxer) {
+ this.demuxer.destroy();
+ this.demuxer = null;
+ }
+ } else {
+ // switching to audio track, start timer if not already started
+ if (!this.timer) {
+ this.timer = setInterval(this.ontick, 100);
+ }
+ }
+ // flush audio source buffer
+ this.hls.trigger(_events2.default.BUFFER_FLUSHING, { startOffset: 0, endOffset: Number.POSITIVE_INFINITY, type: 'audio' });
+ this.tick();
+ }
+ }, {
+ key: 'onAudioTrackLoaded',
+ value: function onAudioTrackLoaded(data) {
+ var details = data.details,
+ trackId = data.id,
+ track = this.tracks[trackId],
+ duration = details.totalduration;
+
+ _logger.logger.log('track ' + trackId + ' loaded [' + details.startSN + ',' + details.endSN + '],duration:' + duration);
+ details.PTSKnown = false;
+ track.details = details;
+
+ // compute start position
+ if (!this.startFragRequested) {
+ // compute start position if set to -1. use it straight away if value is defined
+ if (this.startPosition === -1) {
+ // first, check if start time offset has been set in playlist, if yes, use this value
+ var startTimeOffset = details.startTimeOffset;
+ if (!isNaN(startTimeOffset)) {
+ _logger.logger.log('start time offset found in playlist, adjust startPosition to ' + startTimeOffset);
+ this.startPosition = startTimeOffset;
+ } else {
+ this.startPosition = 0;
+ }
+ }
+ this.nextLoadPosition = this.startPosition;
+ }
+ // only switch batck to IDLE state if we were waiting for track to start downloading a new fragment
+ if (this.state === State.WAITING_TRACK) {
+ this.state = State.IDLE;
+ }
+ //trigger handler right now
+ this.tick();
+ }
+ }, {
+ key: 'onKeyLoaded',
+ value: function onKeyLoaded() {
+ if (this.state === State.KEY_LOADING) {
+ this.state = State.IDLE;
+ this.tick();
+ }
+ }
+ }, {
+ key: 'onFragLoaded',
+ value: function onFragLoaded(data) {
+ var fragCurrent = this.fragCurrent;
+ if (this.state === State.FRAG_LOADING && fragCurrent && data.frag.type === 'audio' && data.frag.level === fragCurrent.level && data.frag.sn === fragCurrent.sn) {
+ this.state = State.PARSING;
+ // transmux the MPEG-TS data to ISO-BMFF segments
+ this.stats = data.stats;
+ var track = this.tracks[this.trackId],
+ details = track.details,
+ duration = details.totalduration,
+ start = fragCurrent.start,
+ trackId = fragCurrent.level,
+ sn = fragCurrent.sn,
+ audioCodec = this.config.defaultAudioCodec || track.audioCodec;
+ this.pendingAppending = 0;
+ if (!this.demuxer) {
+ this.demuxer = new _demuxer2.default(this.hls, 'audio');
+ }
+ _logger.logger.log('Demuxing ' + sn + ' of [' + details.startSN + ' ,' + details.endSN + '],track ' + trackId);
+ // time Offset is accurate if level PTS is known, or if playlist is not sliding (not live)
+ var accurateTimeOffset = details.PTSKnown || !details.live;
+ this.demuxer.push(data.payload, audioCodec, null, start, fragCurrent.cc, trackId, sn, duration, fragCurrent.decryptdata, accurateTimeOffset);
+ }
+ this.fragLoadError = 0;
+ }
+ }, {
+ key: 'onFragParsingInitSegment',
+ value: function onFragParsingInitSegment(data) {
+ var fragCurrent = this.fragCurrent;
+ if (fragCurrent && data.id === 'audio' && data.sn === fragCurrent.sn && data.level === fragCurrent.level && this.state === State.PARSING) {
+ var tracks = data.tracks,
+ track = void 0;
+
+ // include levelCodec in audio and video tracks
+ track = tracks.audio;
+ if (track) {
+ track.levelCodec = 'mp4a.40.2';
+ track.id = data.id;
+ this.hls.trigger(_events2.default.BUFFER_CODECS, tracks);
+ _logger.logger.log('audio track:audio,container:' + track.container + ',codecs[level/parsed]=[' + track.levelCodec + '/' + track.codec + ']');
+ var initSegment = track.initSegment;
+ if (initSegment) {
+ this.pendingAppending++;
+ this.hls.trigger(_events2.default.BUFFER_APPENDING, { type: 'audio', data: initSegment, parent: 'audio', content: 'initSegment' });
+ }
+ //trigger handler right now
+ this.tick();
+ }
+ }
+ }
+ }, {
+ key: 'onFragParsingData',
+ value: function onFragParsingData(data) {
+ var _this2 = this;
+
+ var fragCurrent = this.fragCurrent;
+ if (fragCurrent && data.id === 'audio' && data.sn === fragCurrent.sn && data.level === fragCurrent.level && this.state === State.PARSING) {
+ var track = this.tracks[this.trackId],
+ frag = this.fragCurrent;
+
+ _logger.logger.log('parsed ' + data.type + ',PTS:[' + data.startPTS.toFixed(3) + ',' + data.endPTS.toFixed(3) + '],DTS:[' + data.startDTS.toFixed(3) + '/' + data.endDTS.toFixed(3) + '],nb:' + data.nb);
+ _levelHelper2.default.updateFragPTSDTS(track.details, frag.sn, data.startPTS, data.endPTS);
+
+ [data.data1, data.data2].forEach(function (buffer) {
+ if (buffer) {
+ _this2.pendingAppending++;
+ _this2.hls.trigger(_events2.default.BUFFER_APPENDING, { type: data.type, data: buffer, parent: 'audio', content: 'data' });
+ }
+ });
+ this.nextLoadPosition = data.endPTS;
+ //trigger handler right now
+ this.tick();
+ }
+ }
+ }, {
+ key: 'onFragParsed',
+ value: function onFragParsed(data) {
+ var fragCurrent = this.fragCurrent;
+ if (fragCurrent && data.id === 'audio' && data.sn === fragCurrent.sn && data.level === fragCurrent.level && this.state === State.PARSING) {
+ this.stats.tparsed = performance.now();
+ this.state = State.PARSED;
+ this._checkAppendedParsed();
+ }
+ }
+ }, {
+ key: 'onBufferCreated',
+ value: function onBufferCreated(data) {
+ var audioTrack = data.tracks.audio;
+ if (audioTrack) {
+ this.mediaBuffer = audioTrack.buffer;
+ this.loadedmetadata = true;
+ }
+ }
+ }, {
+ key: 'onBufferAppended',
+ value: function onBufferAppended(data) {
+ if (data.parent === 'audio') {
+ switch (this.state) {
+ case State.PARSING:
+ case State.PARSED:
+ this.pendingAppending--;
+ this._checkAppendedParsed();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }, {
+ key: '_checkAppendedParsed',
+ value: function _checkAppendedParsed() {
+ //trigger handler right now
+ if (this.state === State.PARSED && this.pendingAppending === 0) {
+ var frag = this.fragCurrent,
+ stats = this.stats;
+ if (frag) {
+ this.fragPrevious = frag;
+ stats.tbuffered = performance.now();
+ this.hls.trigger(_events2.default.FRAG_BUFFERED, { stats: stats, frag: frag, id: 'audio' });
+ var media = this.mediaBuffer ? this.mediaBuffer : this.media;
+ _logger.logger.log('audio buffered : ' + _timeRanges2.default.toString(media.buffered));
+ this.state = State.IDLE;
+ }
+ this.tick();
+ }
+ }
+ }, {
+ key: 'onError',
+ value: function onError(data) {
+ var frag = data.frag;
+ // don't handle frag error not related to audio fragment
+ if (frag && frag.type !== 'audio') {
+ return;
+ }
+ switch (data.details) {
+ case _errors.ErrorDetails.FRAG_LOAD_ERROR:
+ case _errors.ErrorDetails.FRAG_LOAD_TIMEOUT:
+ if (!data.fatal) {
+ var loadError = this.fragLoadError;
+ if (loadError) {
+ loadError++;
+ } else {
+ loadError = 1;
+ }
+ var config = this.config;
+ if (loadError <= config.fragLoadingMaxRetry) {
+ this.fragLoadError = loadError;
+ // reset load counter to avoid frag loop loading error
+ frag.loadCounter = 0;
+ // exponential backoff capped to config.fragLoadingMaxRetryTimeout
+ var delay = Math.min(Math.pow(2, loadError - 1) * config.fragLoadingRetryDelay, config.fragLoadingMaxRetryTimeout);
+ _logger.logger.warn('audioStreamController: frag loading failed, retry in ' + delay + ' ms');
+ this.retryDate = performance.now() + delay;
+ // retry loading state
+ this.state = State.FRAG_LOADING_WAITING_RETRY;
+ } else {
+ _logger.logger.error('audioStreamController: ' + data.details + ' reaches max retry, redispatch as fatal ...');
+ // redispatch same error but with fatal set to true
+ data.fatal = true;
+ this.hls.trigger(_events2.default.ERROR, data);
+ this.state = State.ERROR;
+ }
+ }
+ break;
+ case _errors.ErrorDetails.FRAG_LOOP_LOADING_ERROR:
+ case _errors.ErrorDetails.AUDIO_TRACK_LOAD_ERROR:
+ case _errors.ErrorDetails.AUDIO_TRACK_LOAD_TIMEOUT:
+ case _errors.ErrorDetails.KEY_LOAD_ERROR:
+ case _errors.ErrorDetails.KEY_LOAD_TIMEOUT:
+ // when in ERROR state, don't switch back to IDLE state in case a non-fatal error is received
+ if (this.state !== State.ERROR) {
+ // if fatal error, stop processing, otherwise move to IDLE to retry loading
+ this.state = data.fatal ? State.ERROR : State.IDLE;
+ _logger.logger.warn('audioStreamController: ' + data.details + ' while loading frag,switch to ' + this.state + ' state ...');
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }, {
+ key: 'onBufferFlushed',
+ value: function onBufferFlushed() {
+ // increase fragment load Index to avoid frag loop loading error after buffer flush
+ this.fragLoadIdx += 2 * this.config.fragLoadingLoopThreshold;
+ // move to IDLE once flush complete. this should trigger new fragment loading
+ this.state = State.IDLE;
+ // reset reference to frag
+ this.fragPrevious = null;
+ this.tick();
+ }
+ }]);
+
+ return AudioStreamController;
+ }(_eventHandler2.default);
+
+ exports.default = AudioStreamController;
+
+ },{"20":20,"24":24,"25":25,"26":26,"28":28,"29":29,"39":39,"43":43,"45":45}],5:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _eventHandler = _dereq_(25);
+
+ var _eventHandler2 = _interopRequireDefault(_eventHandler);
+
+ var _logger = _dereq_(43);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
+ * audio track controller
+ */
+
+ var AudioTrackController = function (_EventHandler) {
+ _inherits(AudioTrackController, _EventHandler);
+
+ function AudioTrackController(hls) {
+ _classCallCheck(this, AudioTrackController);
+
+ return _possibleConstructorReturn(this, Object.getPrototypeOf(AudioTrackController).call(this, hls, _events2.default.MANIFEST_LOADING, _events2.default.MANIFEST_LOADED, _events2.default.AUDIO_TRACK_LOADED));
+ }
+
+ _createClass(AudioTrackController, [{
+ key: 'destroy',
+ value: function destroy() {
+ _eventHandler2.default.prototype.destroy.call(this);
+ }
+ }, {
+ key: 'onManifestLoading',
+ value: function onManifestLoading() {
+ // reset audio tracks on manifest loading
+ this.tracks = [];
+ this.trackId = -1;
+ }
+ }, {
+ key: 'onManifestLoaded',
+ value: function onManifestLoaded(data) {
+ var _this2 = this;
+
+ var tracks = data.audioTracks || [];
+ var defaultFound = false;
+ this.tracks = tracks;
+ this.hls.trigger(_events2.default.AUDIO_TRACKS_UPDATED, { audioTracks: tracks });
+ // loop through available audio tracks and autoselect default if needed
+ var id = 0;
+ tracks.forEach(function (track) {
+ if (track.default) {
+ _this2.audioTrack = id;
+ defaultFound = true;
+ return;
+ }
+ id++;
+ });
+ if (defaultFound === false && tracks.length) {
+ _logger.logger.log('no default audio track defined, use first audio track as default');
+ this.audioTrack = 0;
+ }
+ }
+ }, {
+ key: 'onAudioTrackLoaded',
+ value: function onAudioTrackLoaded(data) {
+ if (data.id < this.tracks.length) {
+ _logger.logger.log('audioTrack ' + data.id + ' loaded');
+ this.tracks[data.id].details = data.details;
+ // check if current playlist is a live playlist
+ if (data.details.live && !this.timer) {
+ // if live playlist we will have to reload it periodically
+ // set reload period to playlist target duration
+ this.timer = setInterval(this.ontick, 1000 * data.details.targetduration);
+ }
+ if (!data.details.live && this.timer) {
+ // playlist is not live and timer is armed : stopping it
+ clearInterval(this.timer);
+ this.timer = null;
+ }
+ }
+ }
+
+ /** get alternate audio tracks list from playlist **/
+
+ }, {
+ key: 'setAudioTrackInternal',
+ value: function setAudioTrackInternal(newId) {
+ // check if level idx is valid
+ if (newId >= 0 && newId < this.tracks.length) {
+ // stopping live reloading timer if any
+ if (this.timer) {
+ clearInterval(this.timer);
+ this.timer = null;
+ }
+ this.trackId = newId;
+ _logger.logger.log('switching to audioTrack ' + newId);
+ var audioTrack = this.tracks[newId],
+ type = audioTrack.type,
+ url = audioTrack.url;
+ this.hls.trigger(_events2.default.AUDIO_TRACK_SWITCH, { id: newId, type: type, url: url });
+ // check if we need to load playlist for this audio Track
+ var details = audioTrack.details;
+ if (url && (details === undefined || details.live === true)) {
+ // track not retrieved yet, or live playlist we need to (re)load it
+ _logger.logger.log('(re)loading playlist for audioTrack ' + newId);
+ this.hls.trigger(_events2.default.AUDIO_TRACK_LOADING, { url: url, id: newId });
+ }
+ }
+ }
+ }, {
+ key: 'audioTracks',
+ get: function get() {
+ return this.tracks;
+ }
+
+ /** get index of the selected audio track (index in audio track lists) **/
+
+ }, {
+ key: 'audioTrack',
+ get: function get() {
+ return this.trackId;
+ }
+
+ /** select an audio track, based on its index in audio track lists**/
+ ,
+ set: function set(audioTrackId) {
+ if (this.trackId !== audioTrackId || this.tracks[audioTrackId].details === undefined) {
+ this.setAudioTrackInternal(audioTrackId);
+ }
+ }
+ }]);
+
+ return AudioTrackController;
+ }(_eventHandler2.default);
+
+ exports.default = AudioTrackController;
+
+ },{"25":25,"26":26,"43":43}],6:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _eventHandler = _dereq_(25);
+
+ var _eventHandler2 = _interopRequireDefault(_eventHandler);
+
+ var _logger = _dereq_(43);
+
+ var _errors = _dereq_(24);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
+ * Buffer Controller
+ */
+
+ var BufferController = function (_EventHandler) {
+ _inherits(BufferController, _EventHandler);
+
+ function BufferController(hls) {
+ _classCallCheck(this, BufferController);
+
+ // the value that we have set mediasource.duration to
+ // (the actual duration may be tweaked slighly by the browser)
+
+ var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(BufferController).call(this, hls, _events2.default.MEDIA_ATTACHING, _events2.default.MEDIA_DETACHING, _events2.default.MANIFEST_PARSED, _events2.default.BUFFER_RESET, _events2.default.BUFFER_APPENDING, _events2.default.BUFFER_CODECS, _events2.default.BUFFER_EOS, _events2.default.BUFFER_FLUSHING, _events2.default.LEVEL_UPDATED));
+
+ _this._msDuration = null;
+ // the value that we want to set mediaSource.duration to
+ _this._levelDuration = null;
+
+ // Source Buffer listeners
+ _this.onsbue = _this.onSBUpdateEnd.bind(_this);
+ _this.onsbe = _this.onSBUpdateError.bind(_this);
+ _this.pendingTracks = {};
+ return _this;
+ }
+
+ _createClass(BufferController, [{
+ key: 'destroy',
+ value: function destroy() {
+ _eventHandler2.default.prototype.destroy.call(this);
+ }
+ }, {
+ key: 'onManifestParsed',
+ value: function onManifestParsed(data) {
+ var audioExpected = data.audio,
+ videoExpected = data.video,
+ sourceBufferNb = 0;
+ // in case of alt audio 2 BUFFER_CODECS events will be triggered, one per stream controller
+ // sourcebuffers will be created all at once when the expected nb of tracks will be reached
+ // in case alt audio is not used, only one BUFFER_CODEC event will be fired from main stream controller
+ // it will contain the expected nb of source buffers, no need to compute it
+ if (data.altAudio && (audioExpected || videoExpected)) {
+ sourceBufferNb = (audioExpected ? 1 : 0) + (videoExpected ? 1 : 0);
+ _logger.logger.log(sourceBufferNb + ' sourceBuffer(s) expected');
+ }
+ this.sourceBufferNb = sourceBufferNb;
+ }
+ }, {
+ key: 'onMediaAttaching',
+ value: function onMediaAttaching(data) {
+ var media = this.media = data.media;
+ if (media) {
+ // setup the media source
+ var ms = this.mediaSource = new MediaSource();
+ //Media Source listeners
+ this.onmso = this.onMediaSourceOpen.bind(this);
+ this.onmse = this.onMediaSourceEnded.bind(this);
+ this.onmsc = this.onMediaSourceClose.bind(this);
+ ms.addEventListener('sourceopen', this.onmso);
+ ms.addEventListener('sourceended', this.onmse);
+ ms.addEventListener('sourceclose', this.onmsc);
+ // link video and media Source
+ media.src = URL.createObjectURL(ms);
+ }
+ }
+ }, {
+ key: 'onMediaDetaching',
+ value: function onMediaDetaching() {
+ _logger.logger.log('media source detaching');
+ var ms = this.mediaSource;
+ if (ms) {
+ if (ms.readyState === 'open') {
+ try {
+ // endOfStream could trigger exception if any sourcebuffer is in updating state
+ // we don't really care about checking sourcebuffer state here,
+ // as we are anyway detaching the MediaSource
+ // let's just avoid this exception to propagate
+ ms.endOfStream();
+ } catch (err) {
+ _logger.logger.warn('onMediaDetaching:' + err.message + ' while calling endOfStream');
+ }
+ }
+ ms.removeEventListener('sourceopen', this.onmso);
+ ms.removeEventListener('sourceended', this.onmse);
+ ms.removeEventListener('sourceclose', this.onmsc);
+
+ // Detach properly the MediaSource from the HTMLMediaElement as
+ // suggested in https://github.com/w3c/media-source/issues/53.
+ if (this.media) {
+ this.media.removeAttribute('src');
+ this.media.load();
+ }
+
+ this.mediaSource = null;
+ this.media = null;
+ this.pendingTracks = {};
+ this.sourceBuffer = {};
+ this.flushRange = [];
+ this.segments = [];
+ this.appended = 0;
+ }
+ this.onmso = this.onmse = this.onmsc = null;
+ this.hls.trigger(_events2.default.MEDIA_DETACHED);
+ }
+ }, {
+ key: 'onMediaSourceOpen',
+ value: function onMediaSourceOpen() {
+ _logger.logger.log('media source opened');
+ this.hls.trigger(_events2.default.MEDIA_ATTACHED, { media: this.media });
+ var mediaSource = this.mediaSource;
+ if (mediaSource) {
+ // once received, don't listen anymore to sourceopen event
+ mediaSource.removeEventListener('sourceopen', this.onmso);
+ }
+ this.checkPendingTracks();
+ }
+ }, {
+ key: 'checkPendingTracks',
+ value: function checkPendingTracks() {
+ // if any buffer codecs pending, check if we have enough to create sourceBuffers
+ var pendingTracks = this.pendingTracks,
+ pendingTracksNb = Object.keys(pendingTracks).length;
+ // if any pending tracks and (if nb of pending tracks gt or equal than expected nb or if unknown expected nb)
+ if (pendingTracksNb && (this.sourceBufferNb <= pendingTracksNb || this.sourceBufferNb === 0)) {
+ // ok, let's create them now !
+ this.createSourceBuffers(pendingTracks);
+ this.pendingTracks = {};
+ // append any pending segments now !
+ this.doAppending();
+ }
+ }
+ }, {
+ key: 'onMediaSourceClose',
+ value: function onMediaSourceClose() {
+ _logger.logger.log('media source closed');
+ }
+ }, {
+ key: 'onMediaSourceEnded',
+ value: function onMediaSourceEnded() {
+ _logger.logger.log('media source ended');
+ }
+ }, {
+ key: 'onSBUpdateEnd',
+ value: function onSBUpdateEnd() {
+
+ if (this._needsFlush) {
+ this.doFlush();
+ }
+
+ if (this._needsEos) {
+ this.checkEos();
+ }
+ this.appending = false;
+ this.hls.trigger(_events2.default.BUFFER_APPENDED, { parent: this.parent });
+
+ // don't append in flushing mode
+ if (!this._needsFlush) {
+ this.doAppending();
+ }
+
+ this.updateMediaElementDuration();
+ }
+ }, {
+ key: 'onSBUpdateError',
+ value: function onSBUpdateError(event) {
+ _logger.logger.error('sourceBuffer error:' + event);
+ // according to http://www.w3.org/TR/media-source/#sourcebuffer-append-error
+ // this error might not always be fatal (it is fatal if decode error is set, in that case
+ // it will be followed by a mediaElement error ...)
+ this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, details: _errors.ErrorDetails.BUFFER_APPENDING_ERROR, fatal: false });
+ // we don't need to do more than that, as accordin to the spec, updateend will be fired just after
+ }
+ }, {
+ key: 'onBufferReset',
+ value: function onBufferReset() {
+ var sourceBuffer = this.sourceBuffer;
+ for (var type in sourceBuffer) {
+ var sb = sourceBuffer[type];
+ try {
+ this.mediaSource.removeSourceBuffer(sb);
+ sb.removeEventListener('updateend', this.onsbue);
+ sb.removeEventListener('error', this.onsbe);
+ } catch (err) {}
+ }
+ this.sourceBuffer = {};
+ this.flushRange = [];
+ this.segments = [];
+ this.appended = 0;
+ }
+ }, {
+ key: 'onBufferCodecs',
+ value: function onBufferCodecs(tracks) {
+ // if source buffer(s) not created yet, appended buffer tracks in this.pendingTracks
+ // if sourcebuffers already created, do nothing ...
+ if (Object.keys(this.sourceBuffer).length === 0) {
+ for (var trackName in tracks) {
+ this.pendingTracks[trackName] = tracks[trackName];
+ }
+ var mediaSource = this.mediaSource;
+ if (mediaSource && mediaSource.readyState === 'open') {
+ // try to create sourcebuffers if mediasource opened
+ this.checkPendingTracks();
+ }
+ }
+ }
+ }, {
+ key: 'createSourceBuffers',
+ value: function createSourceBuffers(tracks) {
+ var sourceBuffer = this.sourceBuffer,
+ mediaSource = this.mediaSource;
+
+ for (var trackName in tracks) {
+ if (!sourceBuffer[trackName]) {
+ var track = tracks[trackName];
+ // use levelCodec as first priority
+ var codec = track.levelCodec || track.codec;
+ var mimeType = track.container + ';codecs=' + codec;
+ _logger.logger.log('creating sourceBuffer(' + mimeType + ')');
+ try {
+ var sb = sourceBuffer[trackName] = mediaSource.addSourceBuffer(mimeType);
+ sb.addEventListener('updateend', this.onsbue);
+ sb.addEventListener('error', this.onsbe);
+ track.buffer = sb;
+ } catch (err) {
+ _logger.logger.error('error while trying to add sourceBuffer:' + err.message);
+ this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, details: _errors.ErrorDetails.BUFFER_ADD_CODEC_ERROR, fatal: false, err: err, mimeType: mimeType });
+ }
+ }
+ }
+ this.hls.trigger(_events2.default.BUFFER_CREATED, { tracks: tracks });
+ }
+ }, {
+ key: 'onBufferAppending',
+ value: function onBufferAppending(data) {
+ if (!this._needsFlush) {
+ if (!this.segments) {
+ this.segments = [data];
+ } else {
+ this.segments.push(data);
+ }
+ this.doAppending();
+ }
+ }
+ }, {
+ key: 'onBufferAppendFail',
+ value: function onBufferAppendFail(data) {
+ _logger.logger.error('sourceBuffer error:' + data.event);
+ // according to http://www.w3.org/TR/media-source/#sourcebuffer-append-error
+ // this error might not always be fatal (it is fatal if decode error is set, in that case
+ // it will be followed by a mediaElement error ...)
+ this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, details: _errors.ErrorDetails.BUFFER_APPENDING_ERROR, fatal: false, frag: this.fragCurrent });
+ }
+
+ // on BUFFER_EOS mark matching sourcebuffer(s) as ended and trigger checkEos()
+
+ }, {
+ key: 'onBufferEos',
+ value: function onBufferEos(data) {
+ var sb = this.sourceBuffer;
+ var dataType = data.type;
+ for (var type in sb) {
+ if (!dataType || type === dataType) {
+ if (!sb[type].ended) {
+ sb[type].ended = true;
+ _logger.logger.log(type + ' sourceBuffer now EOS');
+ }
+ }
+ }
+ this.checkEos();
+ }
+
+ // if all source buffers are marked as ended, signal endOfStream() to MediaSource.
+
+ }, {
+ key: 'checkEos',
+ value: function checkEos() {
+ var sb = this.sourceBuffer,
+ mediaSource = this.mediaSource;
+ if (!mediaSource || mediaSource.readyState !== 'open') {
+ this._needsEos = false;
+ return;
+ }
+ for (var type in sb) {
+ if (!sb[type].ended) {
+ return;
+ }
+ if (sb[type].updating) {
+ this._needsEos = true;
+ return;
+ }
+ }
+ _logger.logger.log('all media data available, signal endOfStream() to MediaSource and stop loading fragment');
+ //Notify the media element that it now has all of the media data
+ mediaSource.endOfStream();
+ this._needsEos = false;
+ }
+ }, {
+ key: 'onBufferFlushing',
+ value: function onBufferFlushing(data) {
+ this.flushRange.push({ start: data.startOffset, end: data.endOffset, type: data.type });
+ // attempt flush immediatly
+ this.flushBufferCounter = 0;
+ this.doFlush();
+ }
+ }, {
+ key: 'onLevelUpdated',
+ value: function onLevelUpdated(event) {
+ var details = event.details;
+ if (details.fragments.length === 0) {
+ return;
+ }
+ this._levelDuration = details.totalduration + details.fragments[0].start;
+ this.updateMediaElementDuration();
+ }
+
+ // https://github.com/dailymotion/hls.js/issues/355
+
+ }, {
+ key: 'updateMediaElementDuration',
+ value: function updateMediaElementDuration() {
+ if (this._levelDuration === null) {
+ return;
+ }
+ var media = this.media,
+ mediaSource = this.mediaSource,
+ sourceBuffer = this.sourceBuffer;
+ if (!media || !mediaSource || !sourceBuffer || media.readyState === 0 || mediaSource.readyState !== 'open') {
+ return;
+ }
+ for (var type in sourceBuffer) {
+ if (sourceBuffer[type].updating) {
+ // can't set duration whilst a buffer is updating
+ return;
+ }
+ }
+ if (this._msDuration === null) {
+ // initialise to the value that the media source is reporting
+ this._msDuration = mediaSource.duration;
+ }
+ // this._levelDuration was the last value we set.
+ // not using mediaSource.duration as the browser may tweak this value
+ // only update mediasource duration if its value increase, this is to avoid
+ // flushing already buffered portion when switching between quality level, as they
+ if (this._levelDuration > this._msDuration) {
+ _logger.logger.log('Updating mediasource duration to ' + this._levelDuration);
+ mediaSource.duration = this._levelDuration;
+ this._msDuration = this._levelDuration;
+ }
+ }
+ }, {
+ key: 'doFlush',
+ value: function doFlush() {
+ // loop through all buffer ranges to flush
+ while (this.flushRange.length) {
+ var range = this.flushRange[0];
+ // flushBuffer will abort any buffer append in progress and flush Audio/Video Buffer
+ if (this.flushBuffer(range.start, range.end, range.type)) {
+ // range flushed, remove from flush array
+ this.flushRange.shift();
+ this.flushBufferCounter = 0;
+ } else {
+ this._needsFlush = true;
+ // avoid looping, wait for SB update end to retrigger a flush
+ return;
+ }
+ }
+ if (this.flushRange.length === 0) {
+ // everything flushed
+ this._needsFlush = false;
+
+ // let's recompute this.appended, which is used to avoid flush looping
+ var appended = 0;
+ var sourceBuffer = this.sourceBuffer;
+ for (var type in sourceBuffer) {
+ appended += sourceBuffer[type].buffered.length;
+ }
+ this.appended = appended;
+ this.hls.trigger(_events2.default.BUFFER_FLUSHED);
+ }
+ }
+ }, {
+ key: 'doAppending',
+ value: function doAppending() {
+ var hls = this.hls,
+ sourceBuffer = this.sourceBuffer,
+ segments = this.segments;
+ if (Object.keys(sourceBuffer).length) {
+ if (this.media.error) {
+ this.segments = [];
+ _logger.logger.error('trying to append although a media error occured, flush segment and abort');
+ return;
+ }
+ if (this.appending) {
+ //logger.log(`sb appending in progress`);
+ return;
+ }
+ if (segments && segments.length) {
+ var segment = segments.shift();
+ try {
+ var type = segment.type;
+ if (sourceBuffer[type]) {
+ // reset sourceBuffer ended flag before appending segment
+ sourceBuffer[type].ended = false;
+ //logger.log(`appending ${segment.content} ${segment.type} SB, size:${segment.data.length}, ${segment.parent}`);
+ this.parent = segment.parent;
+ sourceBuffer[type].appendBuffer(segment.data);
+ this.appendError = 0;
+ this.appended++;
+ this.appending = true;
+ } else {
+ // in case we don't have any source buffer matching with this segment type,
+ // it means that Mediasource fails to create sourcebuffer
+ // discard this segment, and trigger update end
+ this.onSBUpdateEnd();
+ }
+ } catch (err) {
+ // in case any error occured while appending, put back segment in segments table
+ _logger.logger.error('error while trying to append buffer:' + err.message);
+ segments.unshift(segment);
+ var event = { type: _errors.ErrorTypes.MEDIA_ERROR };
+ if (err.code !== 22) {
+ if (this.appendError) {
+ this.appendError++;
+ } else {
+ this.appendError = 1;
+ }
+ event.details = _errors.ErrorDetails.BUFFER_APPEND_ERROR;
+ event.frag = this.fragCurrent;
+ /* with UHD content, we could get loop of quota exceeded error until
+ browser is able to evict some data from sourcebuffer. retrying help recovering this
+ */
+ if (this.appendError > hls.config.appendErrorMaxRetry) {
+ _logger.logger.log('fail ' + hls.config.appendErrorMaxRetry + ' times to append segment in sourceBuffer');
+ segments = [];
+ event.fatal = true;
+ hls.trigger(_events2.default.ERROR, event);
+ return;
+ } else {
+ event.fatal = false;
+ hls.trigger(_events2.default.ERROR, event);
+ }
+ } else {
+ // QuotaExceededError: http://www.w3.org/TR/html5/infrastructure.html#quotaexceedederror
+ // let's stop appending any segments, and report BUFFER_FULL_ERROR error
+ this.segments = [];
+ event.details = _errors.ErrorDetails.BUFFER_FULL_ERROR;
+ hls.trigger(_events2.default.ERROR, event);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ flush specified buffered range,
+ return true once range has been flushed.
+ as sourceBuffer.remove() is asynchronous, flushBuffer will be retriggered on sourceBuffer update end
+ */
+
+ }, {
+ key: 'flushBuffer',
+ value: function flushBuffer(startOffset, endOffset, typeIn) {
+ var sb,
+ i,
+ bufStart,
+ bufEnd,
+ flushStart,
+ flushEnd,
+ sourceBuffer = this.sourceBuffer;
+ if (Object.keys(sourceBuffer).length) {
+ _logger.logger.log('flushBuffer,pos/start/end: ' + this.media.currentTime + '/' + startOffset + '/' + endOffset);
+ // safeguard to avoid infinite looping : don't try to flush more than the nb of appended segments
+ if (this.flushBufferCounter < this.appended) {
+ for (var type in sourceBuffer) {
+ // check if sourcebuffer type is defined (typeIn): if yes, let's only flush this one
+ // if no, let's flush all sourcebuffers
+ if (typeIn && type !== typeIn) {
+ continue;
+ }
+ sb = sourceBuffer[type];
+ // we are going to flush buffer, mark source buffer as 'not ended'
+ sb.ended = false;
+ if (!sb.updating) {
+ for (i = 0; i < sb.buffered.length; i++) {
+ bufStart = sb.buffered.start(i);
+ bufEnd = sb.buffered.end(i);
+ // workaround firefox not able to properly flush multiple buffered range.
+ if (navigator.userAgent.toLowerCase().indexOf('firefox') !== -1 && endOffset === Number.POSITIVE_INFINITY) {
+ flushStart = startOffset;
+ flushEnd = endOffset;
+ } else {
+ flushStart = Math.max(bufStart, startOffset);
+ flushEnd = Math.min(bufEnd, endOffset);
+ }
+ /* sometimes sourcebuffer.remove() does not flush
+ the exact expected time range.
+ to avoid rounding issues/infinite loop,
+ only flush buffer range of length greater than 500ms.
+ */
+ if (Math.min(flushEnd, bufEnd) - flushStart > 0.5) {
+ this.flushBufferCounter++;
+ _logger.logger.log('flush ' + type + ' [' + flushStart + ',' + flushEnd + '], of [' + bufStart + ',' + bufEnd + '], pos:' + this.media.currentTime);
+ sb.remove(flushStart, flushEnd);
+ return false;
+ }
+ }
+ } else {
+ //logger.log('abort ' + type + ' append in progress');
+ // this will abort any appending in progress
+ //sb.abort();
+ _logger.logger.warn('cannot flush, sb updating in progress');
+ return false;
+ }
+ }
+ } else {
+ _logger.logger.warn('abort flushing too many retries');
+ }
+ _logger.logger.log('buffer flushed');
+ }
+ // everything flushed !
+ return true;
+ }
+ }]);
+
+ return BufferController;
+ }(_eventHandler2.default);
+
+ exports.default = BufferController;
+
+ },{"24":24,"25":25,"26":26,"43":43}],7:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _eventHandler = _dereq_(25);
+
+ var _eventHandler2 = _interopRequireDefault(_eventHandler);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
+ * cap stream level to media size dimension controller
+ */
+
+ var CapLevelController = function (_EventHandler) {
+ _inherits(CapLevelController, _EventHandler);
+
+ function CapLevelController(hls) {
+ _classCallCheck(this, CapLevelController);
+
+ return _possibleConstructorReturn(this, Object.getPrototypeOf(CapLevelController).call(this, hls, _events2.default.FPS_DROP_LEVEL_CAPPING, _events2.default.MEDIA_ATTACHING, _events2.default.MANIFEST_PARSED));
+ }
+
+ _createClass(CapLevelController, [{
+ key: 'destroy',
+ value: function destroy() {
+ if (this.hls.config.capLevelToPlayerSize) {
+ this.media = this.restrictedLevels = null;
+ this.autoLevelCapping = Number.POSITIVE_INFINITY;
+ if (this.timer) {
+ this.timer = clearInterval(this.timer);
+ }
+ }
+ }
+ }, {
+ key: 'onFpsDropLevelCapping',
+ value: function onFpsDropLevelCapping(data) {
+ if (!this.restrictedLevels) {
+ this.restrictedLevels = [];
+ }
+ if (!this.isLevelRestricted(data.droppedLevel)) {
+ this.restrictedLevels.push(data.droppedLevel);
+ }
+ }
+ }, {
+ key: 'onMediaAttaching',
+ value: function onMediaAttaching(data) {
+ this.media = data.media instanceof HTMLVideoElement ? data.media : null;
+ }
+ }, {
+ key: 'onManifestParsed',
+ value: function onManifestParsed(data) {
+ if (this.hls.config.capLevelToPlayerSize) {
+ this.autoLevelCapping = Number.POSITIVE_INFINITY;
+ this.levels = data.levels;
+ this.hls.firstLevel = this.getMaxLevel(data.firstLevel);
+ clearInterval(this.timer);
+ this.timer = setInterval(this.detectPlayerSize.bind(this), 1000);
+ this.detectPlayerSize();
+ }
+ }
+ }, {
+ key: 'detectPlayerSize',
+ value: function detectPlayerSize() {
+ if (this.media) {
+ var levelsLength = this.levels ? this.levels.length : 0;
+ if (levelsLength) {
+ this.hls.autoLevelCapping = this.getMaxLevel(levelsLength - 1);
+ if (this.hls.autoLevelCapping > this.autoLevelCapping) {
+ // if auto level capping has a higher value for the previous one, flush the buffer using nextLevelSwitch
+ // usually happen when the user go to the fullscreen mode.
+ this.hls.streamController.nextLevelSwitch();
+ }
+ this.autoLevelCapping = this.hls.autoLevelCapping;
+ }
+ }
+ }
+
+ /*
+ * returns level should be the one with the dimensions equal or greater than the media (player) dimensions (so the video will be downscaled)
+ */
+
+ }, {
+ key: 'getMaxLevel',
+ value: function getMaxLevel(capLevelIndex) {
+ var result = 0,
+ i = void 0,
+ level = void 0,
+ mWidth = this.mediaWidth,
+ mHeight = this.mediaHeight,
+ lWidth = 0,
+ lHeight = 0;
+
+ for (i = 0; i <= capLevelIndex; i++) {
+ level = this.levels[i];
+ if (this.isLevelRestricted(i)) {
+ break;
+ }
+ result = i;
+ lWidth = level.width;
+ lHeight = level.height;
+ if (mWidth <= lWidth || mHeight <= lHeight) {
+ break;
+ }
+ }
+ return result;
+ }
+ }, {
+ key: 'isLevelRestricted',
+ value: function isLevelRestricted(level) {
+ return this.restrictedLevels && this.restrictedLevels.indexOf(level) !== -1 ? true : false;
+ }
+ }, {
+ key: 'contentScaleFactor',
+ get: function get() {
+ var pixelRatio = 1;
+ try {
+ pixelRatio = window.devicePixelRatio;
+ } catch (e) {}
+ return pixelRatio;
+ }
+ }, {
+ key: 'mediaWidth',
+ get: function get() {
+ var width = void 0;
+ if (this.media) {
+ width = this.media.width || this.media.clientWidth || this.media.offsetWidth;
+ width *= this.contentScaleFactor;
+ }
+ return width;
+ }
+ }, {
+ key: 'mediaHeight',
+ get: function get() {
+ var height = void 0;
+ if (this.media) {
+ height = this.media.height || this.media.clientHeight || this.media.offsetHeight;
+ height *= this.contentScaleFactor;
+ }
+ return height;
+ }
+ }]);
+
+ return CapLevelController;
+ }(_eventHandler2.default);
+
+ exports.default = CapLevelController;
+
+ },{"25":25,"26":26}],8:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
+ * EWMA Bandwidth Estimator
+ * - heavily inspired from shaka-player
+ * Tracks bandwidth samples and estimates available bandwidth.
+ * Based on the minimum of two exponentially-weighted moving averages with
+ * different half-lives.
+ */
+
+ var _ewma = _dereq_(42);
+
+ var _ewma2 = _interopRequireDefault(_ewma);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var EwmaBandWidthEstimator = function () {
+ function EwmaBandWidthEstimator(hls, slow, fast, defaultEstimate) {
+ _classCallCheck(this, EwmaBandWidthEstimator);
+
+ this.hls = hls;
+ this.defaultEstimate_ = defaultEstimate;
+ this.minWeight_ = 0.001;
+ this.minDelayMs_ = 50;
+ this.slow_ = new _ewma2.default(slow);
+ this.fast_ = new _ewma2.default(fast);
+ }
+
+ _createClass(EwmaBandWidthEstimator, [{
+ key: 'sample',
+ value: function sample(durationMs, numBytes) {
+ durationMs = Math.max(durationMs, this.minDelayMs_);
+ var bandwidth = 8000 * numBytes / durationMs,
+
+ //console.log('instant bw:'+ Math.round(bandwidth));
+ // we weight sample using loading duration....
+ weight = durationMs / 1000;
+ this.fast_.sample(weight, bandwidth);
+ this.slow_.sample(weight, bandwidth);
+ }
+ }, {
+ key: 'canEstimate',
+ value: function canEstimate() {
+ var fast = this.fast_;
+ return fast && fast.getTotalWeight() >= this.minWeight_;
+ }
+ }, {
+ key: 'getEstimate',
+ value: function getEstimate() {
+ if (this.canEstimate()) {
+ //console.log('slow estimate:'+ Math.round(this.slow_.getEstimate()));
+ //console.log('fast estimate:'+ Math.round(this.fast_.getEstimate()));
+ // Take the minimum of these two estimates. This should have the effect of
+ // adapting down quickly, but up more slowly.
+ return Math.min(this.fast_.getEstimate(), this.slow_.getEstimate());
+ } else {
+ return this.defaultEstimate_;
+ }
+ }
+ }, {
+ key: 'destroy',
+ value: function destroy() {}
+ }]);
+
+ return EwmaBandWidthEstimator;
+ }();
+
+ exports.default = EwmaBandWidthEstimator;
+
+ },{"42":42}],9:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _eventHandler = _dereq_(25);
+
+ var _eventHandler2 = _interopRequireDefault(_eventHandler);
+
+ var _logger = _dereq_(43);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
+ * FPS Controller
+ */
+
+ var FPSController = function (_EventHandler) {
+ _inherits(FPSController, _EventHandler);
+
+ function FPSController(hls) {
+ _classCallCheck(this, FPSController);
+
+ return _possibleConstructorReturn(this, Object.getPrototypeOf(FPSController).call(this, hls, _events2.default.MEDIA_ATTACHING));
+ }
+
+ _createClass(FPSController, [{
+ key: 'destroy',
+ value: function destroy() {
+ if (this.timer) {
+ clearInterval(this.timer);
+ }
+ this.isVideoPlaybackQualityAvailable = false;
+ }
+ }, {
+ key: 'onMediaAttaching',
+ value: function onMediaAttaching(data) {
+ if (this.hls.config.capLevelOnFPSDrop) {
+ this.video = data.media instanceof HTMLVideoElement ? data.media : null;
+ if (typeof this.video.getVideoPlaybackQuality === 'function') {
+ this.isVideoPlaybackQualityAvailable = true;
+ }
+ clearInterval(this.timer);
+ this.timer = setInterval(this.checkFPSInterval.bind(this), this.hls.config.fpsDroppedMonitoringPeriod);
+ }
+ }
+ }, {
+ key: 'checkFPS',
+ value: function checkFPS(video, decodedFrames, droppedFrames) {
+ var currentTime = performance.now();
+ if (decodedFrames) {
+ if (this.lastTime) {
+ var currentPeriod = currentTime - this.lastTime,
+ currentDropped = droppedFrames - this.lastDroppedFrames,
+ currentDecoded = decodedFrames - this.lastDecodedFrames,
+ droppedFPS = 1000 * currentDropped / currentPeriod;
+ this.hls.trigger(_events2.default.FPS_DROP, { currentDropped: currentDropped, currentDecoded: currentDecoded, totalDroppedFrames: droppedFrames });
+ if (droppedFPS > 0) {
+ //logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
+ if (currentDropped > this.hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
+ var currentLevel = this.hls.currentLevel;
+ _logger.logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
+ if (currentLevel > 0 && (this.hls.autoLevelCapping === -1 || this.hls.autoLevelCapping >= currentLevel)) {
+ currentLevel = currentLevel - 1;
+ this.hls.trigger(_events2.default.FPS_DROP_LEVEL_CAPPING, { level: currentLevel, droppedLevel: this.hls.currentLevel });
+ this.hls.autoLevelCapping = currentLevel;
+ this.hls.streamController.nextLevelSwitch();
+ }
+ }
+ }
+ }
+ this.lastTime = currentTime;
+ this.lastDroppedFrames = droppedFrames;
+ this.lastDecodedFrames = decodedFrames;
+ }
+ }
+ }, {
+ key: 'checkFPSInterval',
+ value: function checkFPSInterval() {
+ if (this.video) {
+ if (this.isVideoPlaybackQualityAvailable) {
+ var videoPlaybackQuality = this.video.getVideoPlaybackQuality();
+ this.checkFPS(this.video, videoPlaybackQuality.totalVideoFrames, videoPlaybackQuality.droppedVideoFrames);
+ } else {
+ this.checkFPS(this.video, this.video.webkitDecodedFrameCount, this.video.webkitDroppedFrameCount);
+ }
+ }
+ }
+ }]);
+
+ return FPSController;
+ }(_eventHandler2.default);
+
+ exports.default = FPSController;
+
+ },{"25":25,"26":26,"43":43}],10:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _eventHandler = _dereq_(25);
+
+ var _eventHandler2 = _interopRequireDefault(_eventHandler);
+
+ var _logger = _dereq_(43);
+
+ var _errors = _dereq_(24);
+
+ var _bufferHelper = _dereq_(28);
+
+ var _bufferHelper2 = _interopRequireDefault(_bufferHelper);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
+ * Level Controller
+ */
+
+ var LevelController = function (_EventHandler) {
+ _inherits(LevelController, _EventHandler);
+
+ function LevelController(hls) {
+ _classCallCheck(this, LevelController);
+
+ var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(LevelController).call(this, hls, _events2.default.MANIFEST_LOADED, _events2.default.LEVEL_LOADED, _events2.default.ERROR));
+
+ _this.ontick = _this.tick.bind(_this);
+ _this._manualLevel = _this._autoLevelCapping = -1;
+ return _this;
+ }
+
+ _createClass(LevelController, [{
+ key: 'destroy',
+ value: function destroy() {
+ if (this.timer) {
+ clearTimeout(this.timer);
+ this.timer = null;
+ }
+ this._manualLevel = -1;
+ }
+ }, {
+ key: 'startLoad',
+ value: function startLoad() {
+ this.canload = true;
+ // speed up live playlist refresh if timer exists
+ if (this.timer) {
+ this.tick();
+ }
+ }
+ }, {
+ key: 'stopLoad',
+ value: function stopLoad() {
+ this.canload = false;
+ }
+ }, {
+ key: 'onManifestLoaded',
+ value: function onManifestLoaded(data) {
+ var levels0 = [],
+ levels = [],
+ bitrateStart,
+ i,
+ bitrateSet = {},
+ videoCodecFound = false,
+ audioCodecFound = false,
+ hls = this.hls;
+
+ // regroup redundant level together
+ data.levels.forEach(function (level) {
+ if (level.videoCodec) {
+ videoCodecFound = true;
+ }
+ if (level.audioCodec || level.attrs && level.attrs.AUDIO) {
+ audioCodecFound = true;
+ }
+ var redundantLevelId = bitrateSet[level.bitrate];
+ if (redundantLevelId === undefined) {
+ bitrateSet[level.bitrate] = levels0.length;
+ level.url = [level.url];
+ level.urlId = 0;
+ levels0.push(level);
+ } else {
+ levels0[redundantLevelId].url.push(level.url);
+ }
+ });
+
+ // remove audio-only level if we also have levels with audio+video codecs signalled
+ if (videoCodecFound && audioCodecFound) {
+ levels0.forEach(function (level) {
+ if (level.videoCodec) {
+ levels.push(level);
+ }
+ });
+ } else {
+ levels = levels0;
+ }
+
+ // only keep level with supported audio/video codecs
+ levels = levels.filter(function (level) {
+ var checkSupportedAudio = function checkSupportedAudio(codec) {
+ return MediaSource.isTypeSupported('audio/mp4;codecs=' + codec);
+ };
+ var checkSupportedVideo = function checkSupportedVideo(codec) {
+ return MediaSource.isTypeSupported('video/mp4;codecs=' + codec);
+ };
+ var audioCodec = level.audioCodec,
+ videoCodec = level.videoCodec;
+
+ return (!audioCodec || checkSupportedAudio(audioCodec)) && (!videoCodec || checkSupportedVideo(videoCodec));
+ });
+
+ if (levels.length) {
+ // start bitrate is the first bitrate of the manifest
+ bitrateStart = levels[0].bitrate;
+ // sort level on bitrate
+ levels.sort(function (a, b) {
+ return a.bitrate - b.bitrate;
+ });
+ this._levels = levels;
+ // find index of first level in sorted levels
+ for (i = 0; i < levels.length; i++) {
+ if (levels[i].bitrate === bitrateStart) {
+ this._firstLevel = i;
+ _logger.logger.log('manifest loaded,' + levels.length + ' level(s) found, first bitrate:' + bitrateStart);
+ break;
+ }
+ }
+ hls.trigger(_events2.default.MANIFEST_PARSED, { levels: this._levels, firstLevel: this._firstLevel, stats: data.stats, audio: audioCodecFound, video: videoCodecFound, altAudio: data.audioTracks.length > 0 });
+ } else {
+ hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, details: _errors.ErrorDetails.MANIFEST_INCOMPATIBLE_CODECS_ERROR, fatal: true, url: hls.url, reason: 'no level with compatible codecs found in manifest' });
+ }
+ return;
+ }
+ }, {
+ key: 'setLevelInternal',
+ value: function setLevelInternal(newLevel) {
+ var levels = this._levels;
+ // check if level idx is valid
+ if (newLevel >= 0 && newLevel < levels.length) {
+ // stopping live reloading timer if any
+ if (this.timer) {
+ clearTimeout(this.timer);
+ this.timer = null;
+ }
+ if (this._level !== newLevel) {
+ _logger.logger.log('switching to level ' + newLevel);
+ this._level = newLevel;
+ }
+ this.hls.trigger(_events2.default.LEVEL_SWITCH, { level: newLevel });
+ var level = levels[newLevel],
+ levelDetails = level.details;
+ // check if we need to load playlist for this level
+ if (!levelDetails || levelDetails.live === true) {
+ // level not retrieved yet, or live playlist we need to (re)load it
+ var urlId = level.urlId;
+ this.hls.trigger(_events2.default.LEVEL_LOADING, { url: level.url[urlId], level: newLevel, id: urlId });
+ }
+ } else {
+ // invalid level id given, trigger error
+ this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.OTHER_ERROR, details: _errors.ErrorDetails.LEVEL_SWITCH_ERROR, level: newLevel, fatal: false, reason: 'invalid level idx' });
+ }
+ }
+ }, {
+ key: 'onError',
+ value: function onError(data) {
+ if (data.fatal) {
+ return;
+ }
+
+ var details = data.details,
+ hls = this.hls,
+ levelId = void 0,
+ level = void 0,
+ levelError = false;
+ // try to recover not fatal errors
+ switch (details) {
+ case _errors.ErrorDetails.FRAG_LOAD_ERROR:
+ case _errors.ErrorDetails.FRAG_LOAD_TIMEOUT:
+ case _errors.ErrorDetails.FRAG_LOOP_LOADING_ERROR:
+ case _errors.ErrorDetails.KEY_LOAD_ERROR:
+ case _errors.ErrorDetails.KEY_LOAD_TIMEOUT:
+ levelId = data.frag.level;
+ break;
+ case _errors.ErrorDetails.LEVEL_LOAD_ERROR:
+ case _errors.ErrorDetails.LEVEL_LOAD_TIMEOUT:
+ levelId = data.context.level;
+ levelError = true;
+ break;
+ default:
+ break;
+ }
+ /* try to switch to a redundant stream if any available.
+ * if no redundant stream available, emergency switch down (if in auto mode and current level not 0)
+ * otherwise, we cannot recover this network error ...
+ */
+ if (levelId !== undefined) {
+ level = this._levels[levelId];
+ if (level.urlId < level.url.length - 1) {
+ level.urlId++;
+ level.details = undefined;
+ _logger.logger.warn('level controller,' + details + ' for level ' + levelId + ': switching to redundant stream id ' + level.urlId);
+ } else {
+ // we could try to recover if in auto mode and current level not lowest level (0)
+ var recoverable = this._manualLevel === -1 && levelId;
+ if (recoverable) {
+ _logger.logger.warn('level controller,' + details + ': emergency switch-down for next fragment');
+ hls.abrController.nextAutoLevel = 0;
+ } else if (level && level.details && level.details.live) {
+ _logger.logger.warn('level controller,' + details + ' on live stream, discard');
+ if (levelError) {
+ // reset this._level so that another call to set level() will retrigger a frag load
+ this._level = undefined;
+ }
+ // other errors are handled by stream controller
+ } else if (details === _errors.ErrorDetails.LEVEL_LOAD_ERROR || details === _errors.ErrorDetails.LEVEL_LOAD_TIMEOUT) {
+ var _hls = this.hls,
+ media = _hls.media,
+
+ // 0.5 : tolerance needed as some browsers stalls playback before reaching buffered end
+ mediaBuffered = media && _bufferHelper2.default.isBuffered(media, media.currentTime) && _bufferHelper2.default.isBuffered(media, media.currentTime + 0.5);
+ if (mediaBuffered) {
+ var retryDelay = _hls.config.levelLoadingRetryDelay;
+ _logger.logger.warn('level controller,' + details + ', but media buffered, retry in ' + retryDelay + 'ms');
+ this.timer = setTimeout(this.ontick, retryDelay);
+ } else {
+ _logger.logger.error('cannot recover ' + details + ' error');
+ this._level = undefined;
+ // stopping live reloading timer if any
+ if (this.timer) {
+ clearTimeout(this.timer);
+ this.timer = null;
+ }
+ // redispatch same error but with fatal set to true
+ data.fatal = true;
+ _hls.trigger(_events2.default.ERROR, data);
+ }
+ }
+ }
+ }
+ }
+ }, {
+ key: 'onLevelLoaded',
+ value: function onLevelLoaded(data) {
+ // only process level loaded events matching with expected level
+ if (data.level === this._level) {
+ var newDetails = data.details;
+ // if current playlist is a live playlist, arm a timer to reload it
+ if (newDetails.live) {
+ var reloadInterval = 1000 * (newDetails.averagetargetduration ? newDetails.averagetargetduration : newDetails.targetduration),
+ curLevel = this._levels[data.level],
+ curDetails = curLevel.details;
+ if (curDetails && newDetails.endSN === curDetails.endSN) {
+ // follow HLS Spec, If the client reloads a Playlist file and finds that it has not
+ // changed then it MUST wait for a period of one-half the target
+ // duration before retrying.
+ reloadInterval /= 2;
+ _logger.logger.log('same live playlist, reload twice faster');
+ }
+ // decrement reloadInterval with level loading delay
+ reloadInterval -= performance.now() - data.stats.trequest;
+ // in any case, don't reload more than every second
+ reloadInterval = Math.max(1000, Math.round(reloadInterval));
+ _logger.logger.log('live playlist, reload in ' + reloadInterval + ' ms');
+ this.timer = setTimeout(this.ontick, reloadInterval);
+ } else {
+ this.timer = null;
+ }
+ }
+ }
+ }, {
+ key: 'tick',
+ value: function tick() {
+ var levelId = this._level;
+ if (levelId !== undefined && this.canload) {
+ var level = this._levels[levelId],
+ urlId = level.urlId;
+ this.hls.trigger(_events2.default.LEVEL_LOADING, { url: level.url[urlId], level: levelId, id: urlId });
+ }
+ }
+ }, {
+ key: 'levels',
+ get: function get() {
+ return this._levels;
+ }
+ }, {
+ key: 'level',
+ get: function get() {
+ return this._level;
+ },
+ set: function set(newLevel) {
+ var levels = this._levels;
+ if (levels && levels.length > newLevel) {
+ if (this._level !== newLevel || levels[newLevel].details === undefined) {
+ this.setLevelInternal(newLevel);
+ }
+ }
+ }
+ }, {
+ key: 'manualLevel',
+ get: function get() {
+ return this._manualLevel;
+ },
+ set: function set(newLevel) {
+ this._manualLevel = newLevel;
+ if (this._startLevel === undefined) {
+ this._startLevel = newLevel;
+ }
+ if (newLevel !== -1) {
+ this.level = newLevel;
+ }
+ }
+ }, {
+ key: 'firstLevel',
+ get: function get() {
+ return this._firstLevel;
+ },
+ set: function set(newLevel) {
+ this._firstLevel = newLevel;
+ }
+ }, {
+ key: 'startLevel',
+ get: function get() {
+ // hls.startLevel takes precedence over config.startLevel
+ // if none of these values are defined, fallback on this._firstLevel (first quality level appearing in variant manifest)
+ if (this._startLevel === undefined) {
+ var configStartLevel = this.hls.config.startLevel;
+ if (configStartLevel !== undefined) {
+ return configStartLevel;
+ } else {
+ return this._firstLevel;
+ }
+ } else {
+ return this._startLevel;
+ }
+ },
+ set: function set(newLevel) {
+ this._startLevel = newLevel;
+ }
+ }, {
+ key: 'nextLoadLevel',
+ get: function get() {
+ if (this._manualLevel !== -1) {
+ return this._manualLevel;
+ } else {
+ return this.hls.abrController.nextAutoLevel;
+ }
+ },
+ set: function set(nextLevel) {
+ this.level = nextLevel;
+ if (this._manualLevel === -1) {
+ this.hls.abrController.nextAutoLevel = nextLevel;
+ }
+ }
+ }]);
+
+ return LevelController;
+ }(_eventHandler2.default);
+
+ exports.default = LevelController;
+
+ },{"24":24,"25":25,"26":26,"28":28,"43":43}],11:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _binarySearch = _dereq_(39);
+
+ var _binarySearch2 = _interopRequireDefault(_binarySearch);
+
+ var _bufferHelper = _dereq_(28);
+
+ var _bufferHelper2 = _interopRequireDefault(_bufferHelper);
+
+ var _demuxer = _dereq_(20);
+
+ var _demuxer2 = _interopRequireDefault(_demuxer);
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _eventHandler = _dereq_(25);
+
+ var _eventHandler2 = _interopRequireDefault(_eventHandler);
+
+ var _levelHelper = _dereq_(29);
+
+ var _levelHelper2 = _interopRequireDefault(_levelHelper);
+
+ var _timeRanges = _dereq_(45);
+
+ var _timeRanges2 = _interopRequireDefault(_timeRanges);
+
+ var _errors = _dereq_(24);
+
+ var _logger = _dereq_(43);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
+ * Stream Controller
+ */
+
+ var State = {
+ STOPPED: 'STOPPED',
+ IDLE: 'IDLE',
+ PAUSED: 'PAUSED',
+ KEY_LOADING: 'KEY_LOADING',
+ FRAG_LOADING: 'FRAG_LOADING',
+ FRAG_LOADING_WAITING_RETRY: 'FRAG_LOADING_WAITING_RETRY',
+ WAITING_LEVEL: 'WAITING_LEVEL',
+ PARSING: 'PARSING',
+ PARSED: 'PARSED',
+ ENDED: 'ENDED',
+ ERROR: 'ERROR'
+ };
+
+ var StreamController = function (_EventHandler) {
+ _inherits(StreamController, _EventHandler);
+
+ function StreamController(hls) {
+ _classCallCheck(this, StreamController);
+
+ var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(StreamController).call(this, hls, _events2.default.MEDIA_ATTACHED, _events2.default.MEDIA_DETACHING, _events2.default.MANIFEST_LOADING, _events2.default.MANIFEST_PARSED, _events2.default.LEVEL_LOADED, _events2.default.KEY_LOADED, _events2.default.FRAG_LOADED, _events2.default.FRAG_LOAD_EMERGENCY_ABORTED, _events2.default.FRAG_PARSING_INIT_SEGMENT, _events2.default.FRAG_PARSING_DATA, _events2.default.FRAG_PARSED, _events2.default.ERROR, _events2.default.AUDIO_TRACK_SWITCH, _events2.default.BUFFER_CREATED, _events2.default.BUFFER_APPENDED, _events2.default.BUFFER_FLUSHED));
+
+ _this.config = hls.config;
+ _this.audioCodecSwap = false;
+ _this.ticks = 0;
+ _this.ontick = _this.tick.bind(_this);
+ return _this;
+ }
+
+ _createClass(StreamController, [{
+ key: 'destroy',
+ value: function destroy() {
+ this.stopLoad();
+ if (this.timer) {
+ clearInterval(this.timer);
+ this.timer = null;
+ }
+ _eventHandler2.default.prototype.destroy.call(this);
+ this.state = State.STOPPED;
+ }
+ }, {
+ key: 'startLoad',
+ value: function startLoad(startPosition) {
+ if (this.levels) {
+ var media = this.media,
+ lastCurrentTime = this.lastCurrentTime,
+ hls = this.hls;
+ this.stopLoad();
+ if (!this.timer) {
+ this.timer = setInterval(this.ontick, 100);
+ }
+ this.level = -1;
+ this.fragLoadError = 0;
+ if (media && lastCurrentTime > 0) {
+ _logger.logger.log('configure startPosition @' + lastCurrentTime.toFixed(3));
+ if (!this.lastPaused) {
+ _logger.logger.log('resuming video');
+ media.play();
+ }
+ } else {
+ this.lastCurrentTime = this.startPosition ? this.startPosition : startPosition;
+ }
+ if (!this.startFragRequested) {
+ // determine load level
+ var startLevel = hls.startLevel;
+ if (startLevel === -1) {
+ // -1 : guess start Level by doing a bitrate test by loading first fragment of lowest quality level
+ startLevel = 0;
+ this.bitrateTest = true;
+ }
+ // set new level to playlist loader : this will trigger start level load
+ // hls.nextLoadLevel remains until it is set to a new value or until a new frag is successfully loaded
+ this.level = hls.nextLoadLevel = startLevel;
+ this.loadedmetadata = false;
+ }
+ this.state = State.IDLE;
+ this.nextLoadPosition = this.startPosition = this.lastCurrentTime;
+ this.tick();
+ } else {
+ _logger.logger.warn('cannot start loading as manifest not parsed yet');
+ this.state = State.STOPPED;
+ }
+ }
+ }, {
+ key: 'stopLoad',
+ value: function stopLoad() {
+ var frag = this.fragCurrent;
+ if (frag) {
+ if (frag.loader) {
+ frag.loader.abort();
+ }
+ this.fragCurrent = null;
+ }
+ this.fragPrevious = null;
+ if (this.demuxer) {
+ this.demuxer.destroy();
+ this.demuxer = null;
+ }
+ this.state = State.STOPPED;
+ }
+ }, {
+ key: 'tick',
+ value: function tick() {
+ this.ticks++;
+ if (this.ticks === 1) {
+ this.doTick();
+ if (this.ticks > 1) {
+ setTimeout(this.tick, 1);
+ }
+ this.ticks = 0;
+ }
+ }
+ }, {
+ key: 'doTick',
+ value: function doTick() {
+ switch (this.state) {
+ case State.ERROR:
+ //don't do anything in error state to avoid breaking further ...
+ case State.PAUSED:
+ //don't do anything in paused state either ...
+ break;
+ case State.IDLE:
+ // when this returns false there was an error and we shall return immediatly
+ // from current tick
+ if (!this._doTickIdle()) {
+ return;
+ }
+ break;
+ case State.WAITING_LEVEL:
+ var level = this.levels[this.level];
+ // check if playlist is already loaded
+ if (level && level.details) {
+ this.state = State.IDLE;
+ }
+ break;
+ case State.FRAG_LOADING_WAITING_RETRY:
+ var now = performance.now();
+ var retryDate = this.retryDate;
+ // if current time is gt than retryDate, or if media seeking let's switch to IDLE state to retry loading
+ if (!retryDate || now >= retryDate || this.media && this.media.seeking) {
+ _logger.logger.log('mediaController: retryDate reached, switch back to IDLE state');
+ this.state = State.IDLE;
+ }
+ break;
+ case State.ERROR:
+ case State.PAUSED:
+ case State.STOPPED:
+ case State.FRAG_LOADING:
+ case State.PARSING:
+ case State.PARSED:
+ case State.ENDED:
+ break;
+ default:
+ break;
+ }
+ // check buffer
+ this._checkBuffer();
+ // check/update current fragment
+ this._checkFragmentChanged();
+ }
+
+ // Ironically the "idle" state is the on we do the most logic in it seems ....
+ // NOTE: Maybe we could rather schedule a check for buffer length after half of the currently
+ // played segment, or on pause/play/seek instead of naively checking every 100ms?
+
+ }, {
+ key: '_doTickIdle',
+ value: function _doTickIdle() {
+ var hls = this.hls,
+ config = hls.config,
+ media = this.media;
+
+ // if video not attached AND
+ // start fragment already requested OR start frag prefetch disable
+ // exit loop
+ // => if media not attached but start frag prefetch is enabled and start frag not requested yet, we will not exit loop
+ if (!media && (this.startFragRequested || !config.startFragPrefetch)) {
+ return true;
+ }
+
+ // if we have not yet loaded any fragment, start loading from start position
+ var pos = void 0;
+ if (this.loadedmetadata) {
+ pos = media.currentTime;
+ } else {
+ pos = this.nextLoadPosition;
+ }
+ // determine next load level
+ var level = hls.nextLoadLevel;
+
+ // compute max Buffer Length that we could get from this load level, based on level bitrate. don't buffer more than 60 MB and more than 30s
+ var maxBufLen = void 0;
+ if (this.levels[level].hasOwnProperty('bitrate')) {
+ maxBufLen = Math.max(8 * config.maxBufferSize / this.levels[level].bitrate, config.maxBufferLength);
+ } else {
+ maxBufLen = config.maxBufferLength;
+ }
+ maxBufLen = Math.min(maxBufLen, config.maxMaxBufferLength);
+
+ // determine next candidate fragment to be loaded, based on current position and end of buffer position
+ // ensure up to `config.maxMaxBufferLength` of buffer upfront
+
+ var bufferInfo = _bufferHelper2.default.bufferInfo(this.mediaBuffer ? this.mediaBuffer : media, pos, config.maxBufferHole),
+ bufferLen = bufferInfo.len;
+ // Stay idle if we are still with buffer margins
+ if (bufferLen >= maxBufLen) {
+ return true;
+ }
+
+ // if buffer length is less than maxBufLen try to load a new fragment ...
+ _logger.logger.trace('buffer length of ' + bufferLen.toFixed(3) + ' is below max of ' + maxBufLen.toFixed(3) + '. checking for more payload ...');
+
+ // set next load level : this will trigger a playlist load if needed
+ hls.nextLoadLevel = level;
+ this.level = level;
+
+ var levelDetails = this.levels[level].details;
+ // if level info not retrieved yet, switch state and wait for level retrieval
+ // if live playlist, ensure that new playlist has been refreshed to avoid loading/try to load
+ // a useless and outdated fragment (that might even introduce load error if it is already out of the live playlist)
+ if (typeof levelDetails === 'undefined' || levelDetails.live && this.levelLastLoaded !== level) {
+ this.state = State.WAITING_LEVEL;
+ return true;
+ }
+
+ // we just got done loading the final fragment, check if we need to finalize media stream
+ var fragPrevious = this.fragPrevious;
+ if (!levelDetails.live && fragPrevious && fragPrevious.sn === levelDetails.endSN) {
+ // if (we are not seeking AND current position is buffered) OR (if we are seeking but everything (almost) til the end is buffered), let's signal eos
+ // we don't compare exactly media.duration === bufferInfo.end as there could be some subtle media duration difference when switching
+ // between different renditions. using half frag duration should help cope with these cases.
+ if (!media.seeking && bufferInfo.len || media.duration - bufferInfo.end <= fragPrevious.duration / 2) {
+ // Finalize the media stream
+ var data = {};
+ if (this.altAudio) {
+ data.type = 'video';
+ }
+ this.hls.trigger(_events2.default.BUFFER_EOS, data);
+ this.state = State.ENDED;
+ return true;
+ }
+ }
+
+ // if we have the levelDetails for the selected variant, lets continue enrichen our stream (load keys/fragments or trigger EOS, etc..)
+ return this._fetchPayloadOrEos({ pos: pos, bufferInfo: bufferInfo, levelDetails: levelDetails });
+ }
+ }, {
+ key: '_fetchPayloadOrEos',
+ value: function _fetchPayloadOrEos(_ref) {
+ var pos = _ref.pos;
+ var bufferInfo = _ref.bufferInfo;
+ var levelDetails = _ref.levelDetails;
+
+ var fragPrevious = this.fragPrevious,
+ level = this.level,
+ fragments = levelDetails.fragments,
+ fragLen = fragments.length;
+
+ // empty playlist
+ if (fragLen === 0) {
+ return false;
+ }
+
+ // find fragment index, contiguous with end of buffer position
+ var start = fragments[0].start,
+ end = fragments[fragLen - 1].start + fragments[fragLen - 1].duration,
+ bufferEnd = bufferInfo.end,
+ frag = void 0;
+
+ // in case of live playlist we need to ensure that requested position is not located before playlist start
+ if (levelDetails.live) {
+ frag = this._ensureFragmentAtLivePoint({ levelDetails: levelDetails, bufferEnd: bufferEnd, start: start, end: end, fragPrevious: fragPrevious, fragments: fragments, fragLen: fragLen });
+ // if it explicitely returns null don't load any fragment and exit function now
+ if (frag === null) {
+ return false;
+ }
+ } else {
+ // VoD playlist: if bufferEnd before start of playlist, load first fragment
+ if (bufferEnd < start) {
+ frag = fragments[0];
+ }
+ }
+ if (!frag) {
+ frag = this._findFragment({ start: start, fragPrevious: fragPrevious, fragLen: fragLen, fragments: fragments, bufferEnd: bufferEnd, end: end, levelDetails: levelDetails });
+ }
+ if (frag) {
+ return this._loadFragmentOrKey({ frag: frag, level: level, levelDetails: levelDetails, pos: pos, bufferEnd: bufferEnd });
+ }
+ return true;
+ }
+ }, {
+ key: '_ensureFragmentAtLivePoint',
+ value: function _ensureFragmentAtLivePoint(_ref2) {
+ var levelDetails = _ref2.levelDetails;
+ var bufferEnd = _ref2.bufferEnd;
+ var start = _ref2.start;
+ var end = _ref2.end;
+ var fragPrevious = _ref2.fragPrevious;
+ var fragments = _ref2.fragments;
+ var fragLen = _ref2.fragLen;
+
+ var config = this.hls.config,
+ media = this.media;
+
+ var frag = void 0;
+
+ // check if requested position is within seekable boundaries :
+ //logger.log(`start/pos/bufEnd/seeking:${start.toFixed(3)}/${pos.toFixed(3)}/${bufferEnd.toFixed(3)}/${this.media.seeking}`);
+ var maxLatency = config.liveMaxLatencyDuration !== undefined ? config.liveMaxLatencyDuration : config.liveMaxLatencyDurationCount * levelDetails.targetduration;
+
+ if (bufferEnd < Math.max(start, end - maxLatency)) {
+ var liveSyncPosition = this.liveSyncPosition = this.computeLivePosition(start, levelDetails);
+ _logger.logger.log('buffer end: ' + bufferEnd.toFixed(3) + ' is located too far from the end of live sliding playlist, reset currentTime to : ' + liveSyncPosition.toFixed(3));
+ bufferEnd = liveSyncPosition;
+ if (media && media.readyState && media.duration > liveSyncPosition) {
+ media.currentTime = liveSyncPosition;
+ }
+ }
+
+ // if end of buffer greater than live edge, don't load any fragment
+ // this could happen if live playlist intermittently slides in the past.
+ // level 1 loaded [182580161,182580167]
+ // level 1 loaded [182580162,182580169]
+ // Loading 182580168 of [182580162 ,182580169],level 1 ..
+ // Loading 182580169 of [182580162 ,182580169],level 1 ..
+ // level 1 loaded [182580162,182580168] <============= here we should have bufferEnd > end. in that case break to avoid reloading 182580168
+ // level 1 loaded [182580164,182580171]
+ //
+ // don't return null in case media not loaded yet (readystate === 0)
+ if (levelDetails.PTSKnown && bufferEnd > end && media && media.readyState) {
+ return null;
+ }
+
+ if (this.startFragRequested && !levelDetails.PTSKnown) {
+ /* we are switching level on live playlist, but we don't have any PTS info for that quality level ...
+ try to load frag matching with next SN.
+ even if SN are not synchronized between playlists, loading this frag will help us
+ compute playlist sliding and find the right one after in case it was not the right consecutive one */
+ if (fragPrevious) {
+ var targetSN = fragPrevious.sn + 1;
+ if (targetSN >= levelDetails.startSN && targetSN <= levelDetails.endSN) {
+ frag = fragments[targetSN - levelDetails.startSN];
+ _logger.logger.log('live playlist, switching playlist, load frag with next SN: ' + frag.sn);
+ }
+ }
+ if (!frag) {
+ /* we have no idea about which fragment should be loaded.
+ so let's load mid fragment. it will help computing playlist sliding and find the right one
+ */
+ frag = fragments[Math.min(fragLen - 1, Math.round(fragLen / 2))];
+ _logger.logger.log('live playlist, switching playlist, unknown, load middle frag : ' + frag.sn);
+ }
+ }
+ return frag;
+ }
+ }, {
+ key: '_findFragment',
+ value: function _findFragment(_ref3) {
+ var start = _ref3.start;
+ var fragPrevious = _ref3.fragPrevious;
+ var fragLen = _ref3.fragLen;
+ var fragments = _ref3.fragments;
+ var bufferEnd = _ref3.bufferEnd;
+ var end = _ref3.end;
+ var levelDetails = _ref3.levelDetails;
+
+ var config = this.hls.config;
+
+ var frag = void 0,
+ foundFrag = void 0,
+ maxFragLookUpTolerance = config.maxFragLookUpTolerance;
+
+ if (bufferEnd < end) {
+ if (bufferEnd > end - maxFragLookUpTolerance) {
+ maxFragLookUpTolerance = 0;
+ }
+ foundFrag = _binarySearch2.default.search(fragments, function (candidate) {
+ // offset should be within fragment boundary - config.maxFragLookUpTolerance
+ // this is to cope with situations like
+ // bufferEnd = 9.991
+ // frag[Ø] : [0,10]
+ // frag[1] : [10,20]
+ // bufferEnd is within frag[0] range ... although what we are expecting is to return frag[1] here
+ // frag start frag start+duration
+ // |-----------------------------|
+ // <---> <--->
+ // ...--------><-----------------------------><---------....
+ // previous frag matching fragment next frag
+ // return -1 return 0 return 1
+ //logger.log(`level/sn/start/end/bufEnd:${level}/${candidate.sn}/${candidate.start}/${(candidate.start+candidate.duration)}/${bufferEnd}`);
+ if (candidate.start + candidate.duration - maxFragLookUpTolerance <= bufferEnd) {
+ return 1;
+ } // if maxFragLookUpTolerance will have negative value then don't return -1 for first element
+ else if (candidate.start - maxFragLookUpTolerance > bufferEnd && candidate.start) {
+ return -1;
+ }
+ return 0;
+ });
+ } else {
+ // reach end of playlist
+ foundFrag = fragments[fragLen - 1];
+ }
+ if (foundFrag) {
+ frag = foundFrag;
+ start = foundFrag.start;
+ //logger.log('find SN matching with pos:' + bufferEnd + ':' + frag.sn);
+ if (fragPrevious && frag.level === fragPrevious.level && frag.sn === fragPrevious.sn) {
+ if (frag.sn < levelDetails.endSN) {
+ var deltaPTS = fragPrevious.deltaPTS,
+ curSNIdx = frag.sn - levelDetails.startSN;
+ // if there is a significant delta between audio and video, larger than max allowed hole,
+ // and if previous remuxed fragment did not start with a keyframe. (fragPrevious.dropped)
+ // let's try to load previous fragment again to get last keyframe
+ // then we will reload again current fragment (that way we should be able to fill the buffer hole ...)
+ if (deltaPTS && deltaPTS > config.maxBufferHole && fragPrevious.dropped && curSNIdx) {
+ frag = fragments[curSNIdx - 1];
+ _logger.logger.warn('SN just loaded, with large PTS gap between audio and video, maybe frag is not starting with a keyframe ? load previous one to try to overcome this');
+ // decrement previous frag load counter to avoid frag loop loading error when next fragment will get reloaded
+ fragPrevious.loadCounter--;
+ } else {
+ frag = fragments[curSNIdx + 1];
+ _logger.logger.log('SN just loaded, load next one: ' + frag.sn);
+ }
+ } else {
+ frag = null;
+ }
+ }
+ }
+ return frag;
+ }
+ }, {
+ key: '_loadFragmentOrKey',
+ value: function _loadFragmentOrKey(_ref4) {
+ var frag = _ref4.frag;
+ var level = _ref4.level;
+ var levelDetails = _ref4.levelDetails;
+ var pos = _ref4.pos;
+ var bufferEnd = _ref4.bufferEnd;
+
+ var hls = this.hls,
+ config = hls.config;
+
+ //logger.log('loading frag ' + i +',pos/bufEnd:' + pos.toFixed(3) + '/' + bufferEnd.toFixed(3));
+ if (frag.decryptdata.uri != null && frag.decryptdata.key == null) {
+ _logger.logger.log('Loading key for ' + frag.sn + ' of [' + levelDetails.startSN + ' ,' + levelDetails.endSN + '],level ' + level);
+ this.state = State.KEY_LOADING;
+ hls.trigger(_events2.default.KEY_LOADING, { frag: frag });
+ } else {
+ _logger.logger.log('Loading ' + frag.sn + ' of [' + levelDetails.startSN + ' ,' + levelDetails.endSN + '],level ' + level + ', currentTime:' + pos.toFixed(3) + ',bufferEnd:' + bufferEnd.toFixed(3));
+ // ensure that we are not reloading the same fragments in loop ...
+ if (this.fragLoadIdx !== undefined) {
+ this.fragLoadIdx++;
+ } else {
+ this.fragLoadIdx = 0;
+ }
+ if (frag.loadCounter) {
+ frag.loadCounter++;
+ var maxThreshold = config.fragLoadingLoopThreshold;
+ // if this frag has already been loaded 3 times, and if it has been reloaded recently
+ if (frag.loadCounter > maxThreshold && Math.abs(this.fragLoadIdx - frag.loadIdx) < maxThreshold) {
+ hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, details: _errors.ErrorDetails.FRAG_LOOP_LOADING_ERROR, fatal: false, frag: frag });
+ return false;
+ }
+ } else {
+ frag.loadCounter = 1;
+ }
+ frag.loadIdx = this.fragLoadIdx;
+ this.fragCurrent = frag;
+ this.startFragRequested = true;
+ frag.autoLevel = hls.autoLevelEnabled;
+ frag.bitrateTest = this.bitrateTest;
+ hls.trigger(_events2.default.FRAG_LOADING, { frag: frag });
+ this.state = State.FRAG_LOADING;
+ return true;
+ }
+ }
+ }, {
+ key: 'getBufferRange',
+ value: function getBufferRange(position) {
+ var i,
+ range,
+ bufferRange = this.bufferRange;
+ if (bufferRange) {
+ for (i = bufferRange.length - 1; i >= 0; i--) {
+ range = bufferRange[i];
+ if (position >= range.start && position <= range.end) {
+ return range;
+ }
+ }
+ }
+ return null;
+ }
+ }, {
+ key: 'followingBufferRange',
+ value: function followingBufferRange(range) {
+ if (range) {
+ // try to get range of next fragment (500ms after this range)
+ return this.getBufferRange(range.end + 0.5);
+ }
+ return null;
+ }
+ }, {
+ key: '_checkFragmentChanged',
+ value: function _checkFragmentChanged() {
+ var rangeCurrent,
+ currentTime,
+ video = this.media;
+ if (video && video.readyState && video.seeking === false) {
+ currentTime = video.currentTime;
+ /* if video element is in seeked state, currentTime can only increase.
+ (assuming that playback rate is positive ...)
+ As sometimes currentTime jumps back to zero after a
+ media decode error, check this, to avoid seeking back to
+ wrong position after a media decode error
+ */
+ if (currentTime > video.playbackRate * this.lastCurrentTime) {
+ this.lastCurrentTime = currentTime;
+ }
+ if (_bufferHelper2.default.isBuffered(video, currentTime)) {
+ rangeCurrent = this.getBufferRange(currentTime);
+ } else if (_bufferHelper2.default.isBuffered(video, currentTime + 0.1)) {
+ /* ensure that FRAG_CHANGED event is triggered at startup,
+ when first video frame is displayed and playback is paused.
+ add a tolerance of 100ms, in case current position is not buffered,
+ check if current pos+100ms is buffered and use that buffer range
+ for FRAG_CHANGED event reporting */
+ rangeCurrent = this.getBufferRange(currentTime + 0.1);
+ }
+ if (rangeCurrent) {
+ var fragPlaying = rangeCurrent.frag;
+ if (fragPlaying !== this.fragPlaying) {
+ this.fragPlaying = fragPlaying;
+ this.hls.trigger(_events2.default.FRAG_CHANGED, { frag: fragPlaying });
+ }
+ }
+ }
+ }
+
+ /*
+ on immediate level switch :
+ - pause playback if playing
+ - cancel any pending load request
+ - and trigger a buffer flush
+ */
+
+ }, {
+ key: 'immediateLevelSwitch',
+ value: function immediateLevelSwitch() {
+ _logger.logger.log('immediateLevelSwitch');
+ if (!this.immediateSwitch) {
+ this.immediateSwitch = true;
+ var media = this.media,
+ previouslyPaused = void 0;
+ if (media) {
+ previouslyPaused = media.paused;
+ media.pause();
+ } else {
+ // don't restart playback after instant level switch in case media not attached
+ previouslyPaused = true;
+ }
+ this.previouslyPaused = previouslyPaused;
+ }
+ var fragCurrent = this.fragCurrent;
+ if (fragCurrent && fragCurrent.loader) {
+ fragCurrent.loader.abort();
+ }
+ this.fragCurrent = null;
+ this.state = State.PAUSED;
+ // flush everything
+ this.hls.trigger(_events2.default.BUFFER_FLUSHING, { startOffset: 0, endOffset: Number.POSITIVE_INFINITY });
+ }
+
+ /*
+ on immediate level switch end, after new fragment has been buffered :
+ - nudge video decoder by slightly adjusting video currentTime (if currentTime buffered)
+ - resume the playback if needed
+ */
+
+ }, {
+ key: 'immediateLevelSwitchEnd',
+ value: function immediateLevelSwitchEnd() {
+ var media = this.media;
+ if (media && media.buffered.length) {
+ this.immediateSwitch = false;
+ if (_bufferHelper2.default.isBuffered(media, media.currentTime)) {
+ // only nudge if currentTime is buffered
+ media.currentTime -= 0.0001;
+ }
+ if (!this.previouslyPaused) {
+ media.play();
+ }
+ }
+ }
+ }, {
+ key: 'nextLevelSwitch',
+ value: function nextLevelSwitch() {
+ /* try to switch ASAP without breaking video playback :
+ in order to ensure smooth but quick level switching,
+ we need to find the next flushable buffer range
+ we should take into account new segment fetch time
+ */
+ var media = this.media;
+ // ensure that media is defined and that metadata are available (to retrieve currentTime)
+ if (media && media.readyState) {
+ var fetchdelay = void 0,
+ currentRange = void 0,
+ nextRange = void 0;
+ // increase fragment load Index to avoid frag loop loading error after buffer flush
+ this.fragLoadIdx += 2 * this.config.fragLoadingLoopThreshold;
+ currentRange = this.getBufferRange(media.currentTime);
+ if (currentRange && currentRange.start > 1) {
+ // flush buffer preceding current fragment (flush until current fragment start offset)
+ // minus 1s to avoid video freezing, that could happen if we flush keyframe of current video ...
+ this.state = State.PAUSED;
+ this.hls.trigger(_events2.default.BUFFER_FLUSHING, { startOffset: 0, endOffset: currentRange.start - 1 });
+ }
+ if (!media.paused) {
+ // add a safety delay of 1s
+ var nextLevelId = this.hls.nextLoadLevel,
+ nextLevel = this.levels[nextLevelId],
+ fragLastKbps = this.fragLastKbps;
+ if (fragLastKbps && this.fragCurrent) {
+ fetchdelay = this.fragCurrent.duration * nextLevel.bitrate / (1000 * fragLastKbps) + 1;
+ } else {
+ fetchdelay = 0;
+ }
+ } else {
+ fetchdelay = 0;
+ }
+ //logger.log('fetchdelay:'+fetchdelay);
+ // find buffer range that will be reached once new fragment will be fetched
+ nextRange = this.getBufferRange(media.currentTime + fetchdelay);
+ if (nextRange) {
+ // we can flush buffer range following this one without stalling playback
+ nextRange = this.followingBufferRange(nextRange);
+ if (nextRange) {
+ // if we are here, we can also cancel any loading/demuxing in progress, as they are useless
+ var fragCurrent = this.fragCurrent;
+ if (fragCurrent && fragCurrent.loader) {
+ fragCurrent.loader.abort();
+ }
+ this.fragCurrent = null;
+ // flush position is the start position of this new buffer
+ this.state = State.PAUSED;
+ this.hls.trigger(_events2.default.BUFFER_FLUSHING, { startOffset: nextRange.start, endOffset: Number.POSITIVE_INFINITY });
+ }
+ }
+ }
+ }
+ }, {
+ key: 'onMediaAttached',
+ value: function onMediaAttached(data) {
+ var media = this.media = this.mediaBuffer = data.media;
+ this.onvseeking = this.onMediaSeeking.bind(this);
+ this.onvseeked = this.onMediaSeeked.bind(this);
+ this.onvended = this.onMediaEnded.bind(this);
+ media.addEventListener('seeking', this.onvseeking);
+ media.addEventListener('seeked', this.onvseeked);
+ media.addEventListener('ended', this.onvended);
+ var config = this.config;
+ if (this.levels && config.autoStartLoad) {
+ this.hls.startLoad(config.startPosition);
+ }
+ }
+ }, {
+ key: 'onMediaDetaching',
+ value: function onMediaDetaching() {
+ var media = this.media;
+ if (media && media.ended) {
+ _logger.logger.log('MSE detaching and video ended, reset startPosition');
+ this.startPosition = this.lastCurrentTime = 0;
+ }
+
+ // reset fragment loading counter on MSE detaching to avoid reporting FRAG_LOOP_LOADING_ERROR after error recovery
+ var levels = this.levels;
+ if (levels) {
+ // reset fragment load counter
+ levels.forEach(function (level) {
+ if (level.details) {
+ level.details.fragments.forEach(function (fragment) {
+ fragment.loadCounter = undefined;
+ });
+ }
+ });
+ }
+ // remove video listeners
+ if (media) {
+ media.removeEventListener('seeking', this.onvseeking);
+ media.removeEventListener('seeked', this.onvseeked);
+ media.removeEventListener('ended', this.onvended);
+ this.onvseeking = this.onvseeked = this.onvended = null;
+ }
+ this.media = null;
+ this.loadedmetadata = false;
+ this.stopLoad();
+ }
+ }, {
+ key: 'onMediaSeeking',
+ value: function onMediaSeeking() {
+ var media = this.media,
+ currentTime = media ? media.currentTime : undefined,
+ config = this.config;
+ _logger.logger.log('media seeking to ' + currentTime.toFixed(3));
+ if (this.state === State.FRAG_LOADING) {
+ var bufferInfo = _bufferHelper2.default.bufferInfo(media, currentTime, this.config.maxBufferHole),
+ fragCurrent = this.fragCurrent;
+ // check if we are seeking to a unbuffered area AND if frag loading is in progress
+ if (bufferInfo.len === 0 && fragCurrent) {
+ var tolerance = config.maxFragLookUpTolerance,
+ fragStartOffset = fragCurrent.start - tolerance,
+ fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
+ // check if we seek position will be out of currently loaded frag range : if out cancel frag load, if in, don't do anything
+ if (currentTime < fragStartOffset || currentTime > fragEndOffset) {
+ if (fragCurrent.loader) {
+ _logger.logger.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
+ fragCurrent.loader.abort();
+ }
+ this.fragCurrent = null;
+ this.fragPrevious = null;
+ // switch to IDLE state to load new fragment
+ this.state = State.IDLE;
+ } else {
+ _logger.logger.log('seeking outside of buffer but within currently loaded fragment range');
+ }
+ }
+ } else if (this.state === State.ENDED) {
+ // switch to IDLE state to check for potential new fragment
+ this.state = State.IDLE;
+ }
+ if (media) {
+ this.lastCurrentTime = currentTime;
+ }
+ // avoid reporting fragment loop loading error in case user is seeking several times on same position
+ if (this.state !== State.FRAG_LOADING && this.fragLoadIdx !== undefined) {
+ this.fragLoadIdx += 2 * config.fragLoadingLoopThreshold;
+ }
+ // tick to speed up processing
+ this.tick();
+ }
+ }, {
+ key: 'onMediaSeeked',
+ value: function onMediaSeeked() {
+ _logger.logger.log('media seeked to ' + this.media.currentTime.toFixed(3));
+ // tick to speed up FRAGMENT_PLAYING triggering
+ this.tick();
+ }
+ }, {
+ key: 'onMediaEnded',
+ value: function onMediaEnded() {
+ _logger.logger.log('media ended');
+ // reset startPosition and lastCurrentTime to restart playback @ stream beginning
+ this.startPosition = this.lastCurrentTime = 0;
+ }
+ }, {
+ key: 'onManifestLoading',
+ value: function onManifestLoading() {
+ // reset buffer on manifest loading
+ _logger.logger.log('trigger BUFFER_RESET');
+ this.hls.trigger(_events2.default.BUFFER_RESET);
+ this.bufferRange = [];
+ this.stalled = false;
+ this.startPosition = this.lastCurrentTime = 0;
+ }
+ }, {
+ key: 'onManifestParsed',
+ value: function onManifestParsed(data) {
+ var aac = false,
+ heaac = false,
+ codec;
+ data.levels.forEach(function (level) {
+ // detect if we have different kind of audio codecs used amongst playlists
+ codec = level.audioCodec;
+ if (codec) {
+ if (codec.indexOf('mp4a.40.2') !== -1) {
+ aac = true;
+ }
+ if (codec.indexOf('mp4a.40.5') !== -1) {
+ heaac = true;
+ }
+ }
+ });
+ this.audioCodecSwitch = aac && heaac;
+ if (this.audioCodecSwitch) {
+ _logger.logger.log('both AAC/HE-AAC audio found in levels; declaring level codec as HE-AAC');
+ }
+ this.levels = data.levels;
+ this.startLevelLoaded = false;
+ this.startFragRequested = false;
+ var config = this.config;
+ if (config.autoStartLoad) {
+ this.hls.startLoad(config.startPosition);
+ }
+ }
+ }, {
+ key: 'onLevelLoaded',
+ value: function onLevelLoaded(data) {
+ var newDetails = data.details,
+ newLevelId = data.level,
+ curLevel = this.levels[newLevelId],
+ duration = newDetails.totalduration,
+ sliding = 0;
+
+ _logger.logger.log('level ' + newLevelId + ' loaded [' + newDetails.startSN + ',' + newDetails.endSN + '],duration:' + duration);
+ this.levelLastLoaded = newLevelId;
+
+ if (newDetails.live) {
+ var curDetails = curLevel.details;
+ if (curDetails && newDetails.fragments.length > 0) {
+ // we already have details for that level, merge them
+ _levelHelper2.default.mergeDetails(curDetails, newDetails);
+ sliding = newDetails.fragments[0].start;
+ this.liveSyncPosition = this.computeLivePosition(sliding, curDetails);
+ if (newDetails.PTSKnown) {
+ _logger.logger.log('live playlist sliding:' + sliding.toFixed(3));
+ } else {
+ _logger.logger.log('live playlist - outdated PTS, unknown sliding');
+ }
+ } else {
+ newDetails.PTSKnown = false;
+ _logger.logger.log('live playlist - first load, unknown sliding');
+ }
+ } else {
+ newDetails.PTSKnown = false;
+ }
+ // override level info
+ curLevel.details = newDetails;
+ this.hls.trigger(_events2.default.LEVEL_UPDATED, { details: newDetails, level: newLevelId });
+
+ if (this.startFragRequested === false) {
+ // compute start position if set to -1. use it straight away if value is defined
+ if (this.startPosition === -1 || this.lastCurrentTime === -1) {
+ // first, check if start time offset has been set in playlist, if yes, use this value
+ var startTimeOffset = newDetails.startTimeOffset;
+ if (!isNaN(startTimeOffset)) {
+ if (startTimeOffset < 0) {
+ _logger.logger.log('negative start time offset ' + startTimeOffset + ', count from end of last fragment');
+ startTimeOffset = sliding + duration + startTimeOffset;
+ }
+ _logger.logger.log('start time offset found in playlist, adjust startPosition to ' + startTimeOffset);
+ this.startPosition = startTimeOffset;
+ } else {
+ // if live playlist, set start position to be fragment N-this.config.liveSyncDurationCount (usually 3)
+ if (newDetails.live) {
+ this.startPosition = this.computeLivePosition(sliding, newDetails);
+ _logger.logger.log('configure startPosition to ' + this.startPosition);
+ } else {
+ this.startPosition = 0;
+ }
+ }
+ }
+ this.nextLoadPosition = this.startPosition;
+ }
+ // only switch batck to IDLE state if we were waiting for level to start downloading a new fragment
+ if (this.state === State.WAITING_LEVEL) {
+ this.state = State.IDLE;
+ }
+ //trigger handler right now
+ this.tick();
+ }
+ }, {
+ key: 'onKeyLoaded',
+ value: function onKeyLoaded() {
+ if (this.state === State.KEY_LOADING) {
+ this.state = State.IDLE;
+ this.tick();
+ }
+ }
+ }, {
+ key: 'onFragLoaded',
+ value: function onFragLoaded(data) {
+ var fragCurrent = this.fragCurrent,
+ fragLoaded = data.frag;
+ if (this.state === State.FRAG_LOADING && fragCurrent && fragLoaded.type === 'main' && fragLoaded.level === fragCurrent.level && fragLoaded.sn === fragCurrent.sn) {
+ var stats = data.stats,
+ currentLevel = this.levels[fragCurrent.level],
+ details = currentLevel.details;
+ _logger.logger.log('Loaded ' + fragCurrent.sn + ' of [' + details.startSN + ' ,' + details.endSN + '],level ' + fragCurrent.level);
+ // reset frag bitrate test in any case after frag loaded event
+ this.bitrateTest = false;
+ // if this frag was loaded to perform a bitrate test AND if hls.nextLoadLevel is greater than 0
+ // then this means that we should be able to load a fragment at a higher quality level
+ if (fragLoaded.bitrateTest === true && this.hls.nextLoadLevel) {
+ // switch back to IDLE state ... we just loaded a fragment to determine adequate start bitrate and initialize autoswitch algo
+ this.state = State.IDLE;
+ this.startFragRequested = false;
+ stats.tparsed = stats.tbuffered = performance.now();
+ this.hls.trigger(_events2.default.FRAG_BUFFERED, { stats: stats, frag: fragCurrent, id: 'main' });
+ this.tick();
+ } else {
+ this.state = State.PARSING;
+ // transmux the MPEG-TS data to ISO-BMFF segments
+ this.stats = stats;
+ var duration = details.totalduration,
+ start = !isNaN(fragCurrent.startDTS) ? fragCurrent.startDTS : fragCurrent.start,
+ level = fragCurrent.level,
+ sn = fragCurrent.sn,
+ audioCodec = this.config.defaultAudioCodec || currentLevel.audioCodec;
+ if (this.audioCodecSwap) {
+ _logger.logger.log('swapping playlist audio codec');
+ if (audioCodec === undefined) {
+ audioCodec = this.lastAudioCodec;
+ }
+ if (audioCodec) {
+ if (audioCodec.indexOf('mp4a.40.5') !== -1) {
+ audioCodec = 'mp4a.40.2';
+ } else {
+ audioCodec = 'mp4a.40.5';
+ }
+ }
+ }
+ this.pendingAppending = 0;
+ _logger.logger.log('Parsing ' + sn + ' of [' + details.startSN + ' ,' + details.endSN + '],level ' + level + ', cc ' + fragCurrent.cc);
+ var demuxer = this.demuxer;
+ if (!demuxer) {
+ demuxer = this.demuxer = new _demuxer2.default(this.hls, 'main');
+ }
+ // time Offset is accurate if level PTS is known, or if playlist is not sliding (not live)
+ var accurateTimeOffset = details.PTSKnown || !details.live;
+ demuxer.push(data.payload, audioCodec, currentLevel.videoCodec, start, fragCurrent.cc, level, sn, duration, fragCurrent.decryptdata, accurateTimeOffset);
+ }
+ }
+ this.fragLoadError = 0;
+ }
+ }, {
+ key: 'onFragParsingInitSegment',
+ value: function onFragParsingInitSegment(data) {
+ var fragCurrent = this.fragCurrent;
+ if (fragCurrent && data.id === 'main' && data.sn === fragCurrent.sn && data.level === fragCurrent.level && this.state === State.PARSING) {
+ var tracks = data.tracks,
+ trackName,
+ track;
+
+ // if audio track is expected to come from audio stream controller, discard any coming from main
+ if (tracks.audio && this.altAudio) {
+ delete tracks.audio;
+ }
+ // include levelCodec in audio and video tracks
+ track = tracks.audio;
+ if (track) {
+ var audioCodec = this.levels[this.level].audioCodec,
+ ua = navigator.userAgent.toLowerCase();
+ if (audioCodec && this.audioCodecSwap) {
+ _logger.logger.log('swapping playlist audio codec');
+ if (audioCodec.indexOf('mp4a.40.5') !== -1) {
+ audioCodec = 'mp4a.40.2';
+ } else {
+ audioCodec = 'mp4a.40.5';
+ }
+ }
+ // in case AAC and HE-AAC audio codecs are signalled in manifest
+ // force HE-AAC , as it seems that most browsers prefers that way,
+ // except for mono streams OR on FF
+ // these conditions might need to be reviewed ...
+ if (this.audioCodecSwitch) {
+ // don't force HE-AAC if mono stream
+ if (track.metadata.channelCount !== 1 &&
+ // don't force HE-AAC if firefox
+ ua.indexOf('firefox') === -1) {
+ audioCodec = 'mp4a.40.5';
+ }
+ }
+ // HE-AAC is broken on Android, always signal audio codec as AAC even if variant manifest states otherwise
+ if (ua.indexOf('android') !== -1) {
+ audioCodec = 'mp4a.40.2';
+ _logger.logger.log('Android: force audio codec to' + audioCodec);
+ }
+ track.levelCodec = audioCodec;
+ track.id = data.id;
+ }
+ track = tracks.video;
+ if (track) {
+ track.levelCodec = this.levels[this.level].videoCodec;
+ track.id = data.id;
+ }
+
+ // if remuxer specify that a unique track needs to generated,
+ // let's merge all tracks together
+ if (data.unique) {
+ var mergedTrack = {
+ codec: '',
+ levelCodec: ''
+ };
+ for (trackName in data.tracks) {
+ track = tracks[trackName];
+ mergedTrack.container = track.container;
+ if (mergedTrack.codec) {
+ mergedTrack.codec += ',';
+ mergedTrack.levelCodec += ',';
+ }
+ if (track.codec) {
+ mergedTrack.codec += track.codec;
+ }
+ if (track.levelCodec) {
+ mergedTrack.levelCodec += track.levelCodec;
+ }
+ }
+ tracks = { audiovideo: mergedTrack };
+ }
+ this.hls.trigger(_events2.default.BUFFER_CODECS, tracks);
+ // loop through tracks that are going to be provided to bufferController
+ for (trackName in tracks) {
+ track = tracks[trackName];
+ _logger.logger.log('main track:' + trackName + ',container:' + track.container + ',codecs[level/parsed]=[' + track.levelCodec + '/' + track.codec + ']');
+ var initSegment = track.initSegment;
+ if (initSegment) {
+ this.pendingAppending++;
+ this.hls.trigger(_events2.default.BUFFER_APPENDING, { type: trackName, data: initSegment, parent: 'main', content: 'initSegment' });
+ }
+ }
+ //trigger handler right now
+ this.tick();
+ }
+ }
+ }, {
+ key: 'onFragParsingData',
+ value: function onFragParsingData(data) {
+ var _this2 = this;
+
+ var fragCurrent = this.fragCurrent;
+ if (fragCurrent && data.id === 'main' && data.sn === fragCurrent.sn && data.level === fragCurrent.level && !(data.type === 'audio' && this.altAudio) && // filter out main audio if audio track is loaded through audio stream controller
+ this.state === State.PARSING) {
+ var level = this.levels[this.level],
+ frag = this.fragCurrent;
+
+ _logger.logger.log('Parsed ' + data.type + ',PTS:[' + data.startPTS.toFixed(3) + ',' + data.endPTS.toFixed(3) + '],DTS:[' + data.startDTS.toFixed(3) + '/' + data.endDTS.toFixed(3) + '],nb:' + data.nb + ',dropped:' + (data.dropped || 0));
+
+ var drift = _levelHelper2.default.updateFragPTSDTS(level.details, frag.sn, data.startPTS, data.endPTS, data.startDTS, data.endDTS),
+ hls = this.hls;
+ hls.trigger(_events2.default.LEVEL_PTS_UPDATED, { details: level.details, level: this.level, drift: drift });
+
+ // has remuxer dropped video frames located before first keyframe ?
+ if (data.type === 'video') {
+ frag.dropped = data.dropped;
+ }
+
+ [data.data1, data.data2].forEach(function (buffer) {
+ if (buffer) {
+ _this2.pendingAppending++;
+ hls.trigger(_events2.default.BUFFER_APPENDING, { type: data.type, data: buffer, parent: 'main', content: 'data' });
+ }
+ });
+
+ this.nextLoadPosition = data.endPTS;
+ this.bufferRange.push({ type: data.type, start: data.startPTS, end: data.endPTS, frag: frag });
+
+ //trigger handler right now
+ this.tick();
+ }
+ }
+ }, {
+ key: 'onFragParsed',
+ value: function onFragParsed(data) {
+ var fragCurrent = this.fragCurrent;
+ if (fragCurrent && data.id === 'main' && data.sn === fragCurrent.sn && data.level === fragCurrent.level && this.state === State.PARSING) {
+ this.stats.tparsed = performance.now();
+ this.state = State.PARSED;
+ this._checkAppendedParsed();
+ }
+ }
+ }, {
+ key: 'onAudioTrackSwitch',
+ value: function onAudioTrackSwitch(data) {
+ // if any URL found on new audio track, it is an alternate audio track
+ var altAudio = !!data.url;
+ // if we switch on main audio, ensure that main fragment scheduling is synced with media.buffered
+ if (!altAudio) {
+ if (this.mediaBuffer !== this.media) {
+ _logger.logger.log('switching on main audio, use media.buffered to schedule main fragment loading');
+ this.mediaBuffer = this.media;
+ var fragCurrent = this.fragCurrent;
+ // we need to refill audio buffer from main: cancel any frag loading to speed up audio switch
+ if (fragCurrent.loader) {
+ _logger.logger.log('switching to main audio track, cancel main fragment load');
+ fragCurrent.loader.abort();
+ }
+ this.fragCurrent = null;
+ this.fragPrevious = null;
+ // destroy demuxer to force init segment generation (following audio switch)
+ if (this.demuxer) {
+ this.demuxer.destroy();
+ this.demuxer = null;
+ }
+ // switch to IDLE state to load new fragment
+ this.state = State.IDLE;
+ }
+ } else {
+ // if we switch on alternate audio, ensure that main fragment scheduling is synced with video sourcebuffer buffered
+ if (this.videoBuffer && this.mediaBuffer !== this.videoBuffer) {
+ _logger.logger.log('switching on alternate audio, use video.buffered to schedule main fragment loading');
+ this.mediaBuffer = this.videoBuffer;
+ }
+ }
+ this.altAudio = altAudio;
+ }
+ }, {
+ key: 'onBufferCreated',
+ value: function onBufferCreated(data) {
+ var tracks = data.tracks,
+ mediaTrack = void 0,
+ name = void 0,
+ alternate = false;
+ for (var type in tracks) {
+ var track = tracks[type];
+ if (track.id === 'main') {
+ name = type;
+ mediaTrack = track;
+ // keep video source buffer reference
+ if (type === 'video') {
+ this.videoBuffer = tracks[type].buffer;
+ }
+ } else {
+ alternate = true;
+ }
+ }
+ if (alternate && mediaTrack) {
+ _logger.logger.log('alternate track found, use ' + name + '.buffered to schedule main fragment loading');
+ this.mediaBuffer = mediaTrack.buffer;
+ } else {
+ this.mediaBuffer = this.media;
+ }
+ }
+ }, {
+ key: 'onBufferAppended',
+ value: function onBufferAppended(data) {
+ if (data.parent === 'main') {
+ switch (this.state) {
+ case State.PARSING:
+ case State.PARSED:
+ this.pendingAppending--;
+ this._checkAppendedParsed();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }, {
+ key: '_checkAppendedParsed',
+ value: function _checkAppendedParsed() {
+ //trigger handler right now
+ if (this.state === State.PARSED && this.pendingAppending === 0) {
+ var frag = this.fragCurrent,
+ stats = this.stats;
+ if (frag) {
+ this.fragPrevious = frag;
+ stats.tbuffered = performance.now();
+ // we should get rid of this.fragLastKbps
+ this.fragLastKbps = Math.round(8 * stats.total / (stats.tbuffered - stats.tfirst));
+ this.hls.trigger(_events2.default.FRAG_BUFFERED, { stats: stats, frag: frag, id: 'main' });
+ var media = this.mediaBuffer ? this.mediaBuffer : this.media;
+ _logger.logger.log('main buffered : ' + _timeRanges2.default.toString(media.buffered));
+ this.state = State.IDLE;
+ }
+ this.tick();
+ }
+ }
+ }, {
+ key: 'onError',
+ value: function onError(data) {
+ var frag = data.frag || this.fragCurrent;
+ // don't handle frag error not related to main fragment
+ if (frag && frag.type !== 'main') {
+ return;
+ }
+ var media = this.media,
+
+ // 0.5 : tolerance needed as some browsers stalls playback before reaching buffered end
+ mediaBuffered = media && _bufferHelper2.default.isBuffered(media, media.currentTime) && _bufferHelper2.default.isBuffered(media, media.currentTime + 0.5);
+ switch (data.details) {
+ case _errors.ErrorDetails.FRAG_LOAD_ERROR:
+ case _errors.ErrorDetails.FRAG_LOAD_TIMEOUT:
+ if (!data.fatal) {
+ var loadError = this.fragLoadError;
+ if (loadError) {
+ loadError++;
+ } else {
+ loadError = 1;
+ }
+ var config = this.config;
+ // keep retrying / don't raise fatal network error if current position is buffered
+ if (loadError <= config.fragLoadingMaxRetry || mediaBuffered) {
+ this.fragLoadError = loadError;
+ // reset load counter to avoid frag loop loading error
+ frag.loadCounter = 0;
+ // exponential backoff capped to config.fragLoadingMaxRetryTimeout
+ var delay = Math.min(Math.pow(2, loadError - 1) * config.fragLoadingRetryDelay, config.fragLoadingMaxRetryTimeout);
+ _logger.logger.warn('mediaController: frag loading failed, retry in ' + delay + ' ms');
+ this.retryDate = performance.now() + delay;
+ // retry loading state
+ this.state = State.FRAG_LOADING_WAITING_RETRY;
+ } else {
+ _logger.logger.error('mediaController: ' + data.details + ' reaches max retry, redispatch as fatal ...');
+ // redispatch same error but with fatal set to true
+ data.fatal = true;
+ this.hls.trigger(_events2.default.ERROR, data);
+ this.state = State.ERROR;
+ }
+ }
+ break;
+ case _errors.ErrorDetails.FRAG_LOOP_LOADING_ERROR:
+ if (!data.fatal) {
+ // if buffer is not empty
+ if (mediaBuffered) {
+ // try to reduce max buffer length : rationale is that we could get
+ // frag loop loading error because of buffer eviction
+ this._reduceMaxBufferLength(frag.duration);
+ this.state = State.IDLE;
+ } else {
+ // buffer empty. report as fatal if in manual mode or if lowest level.
+ // level controller takes care of emergency switch down logic
+ if (!frag.autoLevel || frag.level === 0) {
+ // redispatch same error but with fatal set to true
+ data.fatal = true;
+ this.hls.trigger(_events2.default.ERROR, data);
+ this.state = State.ERROR;
+ }
+ }
+ }
+ break;
+ case _errors.ErrorDetails.LEVEL_LOAD_ERROR:
+ case _errors.ErrorDetails.LEVEL_LOAD_TIMEOUT:
+ case _errors.ErrorDetails.KEY_LOAD_ERROR:
+ case _errors.ErrorDetails.KEY_LOAD_TIMEOUT:
+ // when in ERROR state, don't switch back to IDLE state in case a non-fatal error is received
+ if (this.state !== State.ERROR) {
+ // if fatal error, stop processing, otherwise move to IDLE to retry loading
+ this.state = data.fatal ? State.ERROR : State.IDLE;
+ _logger.logger.warn('mediaController: ' + data.details + ' while loading frag,switch to ' + this.state + ' state ...');
+ }
+ break;
+ case _errors.ErrorDetails.BUFFER_FULL_ERROR:
+ // if in appending state
+ if (this.state === State.PARSING || this.state === State.PARSED) {
+ // reduce max buf len if current position is buffered
+ if (mediaBuffered) {
+ this._reduceMaxBufferLength(frag.duration);
+ this.state = State.IDLE;
+ } else {
+ // current position is not buffered, but browser is still complaining about buffer full error
+ // this happens on IE/Edge, refer to https://github.com/dailymotion/hls.js/pull/708
+ // in that case flush the whole buffer to recover
+ _logger.logger.warn('buffer full error also media.currentTime is not buffered, flush everything');
+ this.fragCurrent = null;
+ this.state = State.PAUSED;
+ // flush everything
+ this.hls.trigger(_events2.default.BUFFER_FLUSHING, { startOffset: 0, endOffset: Number.POSITIVE_INFINITY });
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }, {
+ key: '_reduceMaxBufferLength',
+ value: function _reduceMaxBufferLength(minLength) {
+ var config = this.config;
+ if (config.maxMaxBufferLength >= minLength) {
+ // reduce max buffer length as it might be too high. we do this to avoid loop flushing ...
+ config.maxMaxBufferLength /= 2;
+ _logger.logger.warn('reduce max buffer length to ' + config.maxMaxBufferLength + 's and switch to IDLE state');
+ // increase fragment load Index to avoid frag loop loading error after buffer flush
+ this.fragLoadIdx += 2 * config.fragLoadingLoopThreshold;
+ }
+ }
+ }, {
+ key: '_checkBuffer',
+ value: function _checkBuffer() {
+ var media = this.media;
+ // if ready state different from HAVE_NOTHING (numeric value 0), we are allowed to seek
+ if (media && media.readyState) {
+ var currentTime = media.currentTime,
+ buffered = media.buffered;
+ // adjust currentTime to start position on loaded metadata
+ if (!this.loadedmetadata && buffered.length) {
+ this.loadedmetadata = true;
+ // only adjust currentTime if different from startPosition or if startPosition not buffered
+ // at that stage, there should be only one buffered range, as we reach that code after first fragment has been buffered
+ var startPosition = this.startPosition,
+ startPositionBuffered = _bufferHelper2.default.isBuffered(media, startPosition);
+ // if currentTime not matching with expected startPosition or startPosition not buffered
+ if (currentTime !== startPosition || !startPositionBuffered) {
+ _logger.logger.log('target start position:' + startPosition);
+ // if startPosition not buffered, let's seek to buffered.start(0)
+ if (!startPositionBuffered) {
+ startPosition = buffered.start(0);
+ _logger.logger.log('target start position not buffered, seek to buffered.start(0) ' + startPosition);
+ }
+ _logger.logger.log('adjust currentTime from ' + currentTime + ' to ' + startPosition);
+ media.currentTime = startPosition;
+ }
+ } else if (this.immediateSwitch) {
+ this.immediateLevelSwitchEnd();
+ } else {
+ var bufferInfo = _bufferHelper2.default.bufferInfo(media, currentTime, 0),
+ expectedPlaying = !(media.paused || // not playing when media is paused
+ media.ended || // not playing when media is ended
+ media.buffered.length === 0),
+ // not playing if nothing buffered
+ jumpThreshold = 0.5,
+ // tolerance needed as some browsers stalls playback before reaching buffered range end
+ playheadMoving = currentTime > media.playbackRate * this.lastCurrentTime,
+ config = this.config;
+
+ if (this.stalled && playheadMoving) {
+ this.stalled = false;
+ _logger.logger.log('playback not stuck anymore @' + currentTime);
+ }
+ // check buffer upfront
+ // if less than jumpThreshold second is buffered, let's check in more details
+ if (expectedPlaying && bufferInfo.len <= jumpThreshold) {
+ if (playheadMoving) {
+ // playhead moving
+ jumpThreshold = 0;
+ this.seekHoleNudgeDuration = 0;
+ } else {
+ // playhead not moving AND media expected to play
+ if (!this.stalled) {
+ this.seekHoleNudgeDuration = 0;
+ _logger.logger.log('playback seems stuck @' + currentTime);
+ this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, details: _errors.ErrorDetails.BUFFER_STALLED_ERROR, fatal: false });
+ this.stalled = true;
+ } else {
+ this.seekHoleNudgeDuration += config.seekHoleNudgeDuration;
+ }
+ }
+ // if we are below threshold, try to jump to start of next buffer range if close
+ if (bufferInfo.len <= jumpThreshold) {
+ // no buffer available @ currentTime, check if next buffer is close (within a config.maxSeekHole second range)
+ var nextBufferStart = bufferInfo.nextStart,
+ delta = nextBufferStart - currentTime;
+ if (nextBufferStart && delta < config.maxSeekHole && delta > 0) {
+ // next buffer is close ! adjust currentTime to nextBufferStart
+ // this will ensure effective video decoding
+ _logger.logger.log('adjust currentTime from ' + media.currentTime + ' to next buffered @ ' + nextBufferStart + ' + nudge ' + this.seekHoleNudgeDuration);
+ var hole = nextBufferStart + this.seekHoleNudgeDuration - media.currentTime;
+ media.currentTime = nextBufferStart + this.seekHoleNudgeDuration;
+ this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, details: _errors.ErrorDetails.BUFFER_SEEK_OVER_HOLE, fatal: false, hole: hole });
+ }
+ }
+ }
+ }
+ }
+ }
+ }, {
+ key: 'onFragLoadEmergencyAborted',
+ value: function onFragLoadEmergencyAborted() {
+ this.state = State.IDLE;
+ // if loadedmetadata is not set, it means that we are emergency switch down on first frag
+ // in that case, reset startFragRequested flag
+ if (!this.loadedmetadata) {
+ this.startFragRequested = false;
+ }
+ this.tick();
+ }
+ }, {
+ key: 'onBufferFlushed',
+ value: function onBufferFlushed() {
+ /* after successful buffer flushing, rebuild buffer Range array
+ loop through existing buffer range and check if
+ corresponding range is still buffered. only push to new array already buffered range
+ use mediaBuffered instead of media (so that we will check against video.buffered ranges in case of alt audio track)
+ */
+ var media = this.mediaBuffer ? this.mediaBuffer : this.media,
+ bufferRange = this.bufferRange,
+ newRange = [],
+ range = void 0,
+ i = void 0;
+ for (i = 0; i < bufferRange.length; i++) {
+ range = bufferRange[i];
+ if (_bufferHelper2.default.isBuffered(media, (range.start + range.end) / 2)) {
+ newRange.push(range);
+ }
+ }
+ this.bufferRange = newRange;
+
+ // increase fragment load Index to avoid frag loop loading error after buffer flush
+ this.fragLoadIdx += 2 * this.config.fragLoadingLoopThreshold;
+ // move to IDLE once flush complete. this should trigger new fragment loading
+ this.state = State.IDLE;
+ // reset reference to frag
+ this.fragPrevious = null;
+ }
+ }, {
+ key: 'swapAudioCodec',
+ value: function swapAudioCodec() {
+ this.audioCodecSwap = !this.audioCodecSwap;
+ }
+ }, {
+ key: 'computeLivePosition',
+ value: function computeLivePosition(sliding, levelDetails) {
+ var targetLatency = this.config.liveSyncDuration !== undefined ? this.config.liveSyncDuration : this.config.liveSyncDurationCount * levelDetails.targetduration;
+ return sliding + Math.max(0, levelDetails.totalduration - targetLatency);
+ }
+ }, {
+ key: 'state',
+ set: function set(nextState) {
+ if (this.state !== nextState) {
+ var previousState = this.state;
+ this._state = nextState;
+ _logger.logger.log('engine state transition from ' + previousState + ' to ' + nextState);
+ this.hls.trigger(_events2.default.STREAM_STATE_TRANSITION, { previousState: previousState, nextState: nextState });
+ }
+ },
+ get: function get() {
+ return this._state;
+ }
+ }, {
+ key: 'currentLevel',
+ get: function get() {
+ var media = this.media;
+ if (media) {
+ var range = this.getBufferRange(media.currentTime);
+ if (range) {
+ return range.frag.level;
+ }
+ }
+ return -1;
+ }
+ }, {
+ key: 'nextBufferRange',
+ get: function get() {
+ var media = this.media;
+ if (media) {
+ // first get end range of current fragment
+ return this.followingBufferRange(this.getBufferRange(media.currentTime));
+ } else {
+ return null;
+ }
+ }
+ }, {
+ key: 'nextLevel',
+ get: function get() {
+ var range = this.nextBufferRange;
+ if (range) {
+ return range.frag.level;
+ } else {
+ return -1;
+ }
+ }
+ }, {
+ key: 'liveSyncPosition',
+ get: function get() {
+ return this._liveSyncPosition;
+ },
+ set: function set(value) {
+ this._liveSyncPosition = value;
+ }
+ }]);
+
+ return StreamController;
+ }(_eventHandler2.default);
+
+ exports.default = StreamController;
+
+ },{"20":20,"24":24,"25":25,"26":26,"28":28,"29":29,"39":39,"43":43,"45":45}],12:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _eventHandler = _dereq_(25);
+
+ var _eventHandler2 = _interopRequireDefault(_eventHandler);
+
+ var _cea608Parser = _dereq_(40);
+
+ var _cea608Parser2 = _interopRequireDefault(_cea608Parser);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
+ * Timeline Controller
+ */
+
+ var TimelineController = function (_EventHandler) {
+ _inherits(TimelineController, _EventHandler);
+
+ function TimelineController(hls) {
+ _classCallCheck(this, TimelineController);
+
+ var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(TimelineController).call(this, hls, _events2.default.MEDIA_ATTACHING, _events2.default.MEDIA_DETACHING, _events2.default.FRAG_PARSING_USERDATA, _events2.default.MANIFEST_LOADING, _events2.default.FRAG_LOADED, _events2.default.LEVEL_SWITCH));
+
+ _this.hls = hls;
+ _this.config = hls.config;
+ _this.enabled = true;
+ _this.Cues = hls.config.cueHandler;
+
+ if (_this.config.enableCEA708Captions) {
+ var self = _this;
+
+ var channel1 = {
+ 'newCue': function newCue(startTime, endTime, screen) {
+ if (!self.textTrack1) {
+ //Enable reuse of existing text track.
+ var existingTrack1 = self.getExistingTrack('1');
+ if (!existingTrack1) {
+ self.textTrack1 = self.createTextTrack('captions', 'English', 'en');
+ self.textTrack1.textTrack1 = true;
+ } else {
+ self.textTrack1 = existingTrack1;
+ self.clearCurrentCues(self.textTrack1);
+
+ var e = new window.Event('addtrack');
+ e.track = self.textTrack1;
+ self.media.dispatchEvent(e);
+ }
+ }
+
+ self.Cues.newCue(self.textTrack1, startTime, endTime, screen);
+ }
+ };
+
+ var channel2 = {
+ 'newCue': function newCue(startTime, endTime, screen) {
+ if (!self.textTrack2) {
+ //Enable reuse of existing text track.
+ var existingTrack2 = self.getExistingTrack('2');
+ if (!existingTrack2) {
+ self.textTrack2 = self.createTextTrack('captions', 'Spanish', 'es');
+ self.textTrack2.textTrack2 = true;
+ } else {
+ self.textTrack2 = existingTrack2;
+ self.clearCurrentCues(self.textTrack2);
+
+ var e = new window.Event('addtrack');
+ e.track = self.textTrack2;
+ self.media.dispatchEvent(e);
+ }
+ }
+
+ self.Cues.newCue(self.textTrack2, startTime, endTime, screen);
+ }
+ };
+
+ _this.cea608Parser = new _cea608Parser2.default(0, channel1, channel2);
+ }
+ return _this;
+ }
+
+ _createClass(TimelineController, [{
+ key: 'clearCurrentCues',
+ value: function clearCurrentCues(track) {
+ if (track && track.cues) {
+ while (track.cues.length > 0) {
+ track.removeCue(track.cues[0]);
+ }
+ }
+ }
+ }, {
+ key: 'getExistingTrack',
+ value: function getExistingTrack(channelNumber) {
+ var media = this.media;
+ if (media) {
+ for (var i = 0; i < media.textTracks.length; i++) {
+ var textTrack = media.textTracks[i];
+ var propName = 'textTrack' + channelNumber;
+ if (textTrack[propName] === true) {
+ return textTrack;
+ }
+ }
+ }
+ return null;
+ }
+ }, {
+ key: 'createTextTrack',
+ value: function createTextTrack(kind, label, lang) {
+ if (this.media) {
+ return this.media.addTextTrack(kind, label, lang);
+ }
+ }
+ }, {
+ key: 'destroy',
+ value: function destroy() {
+ _eventHandler2.default.prototype.destroy.call(this);
+ }
+ }, {
+ key: 'onMediaAttaching',
+ value: function onMediaAttaching(data) {
+ this.media = data.media;
+ }
+ }, {
+ key: 'onMediaDetaching',
+ value: function onMediaDetaching() {}
+ }, {
+ key: 'onManifestLoading',
+ value: function onManifestLoading() {
+ this.lastPts = Number.NEGATIVE_INFINITY;
+ }
+ }, {
+ key: 'onLevelSwitch',
+ value: function onLevelSwitch() {
+ if (this.hls.currentLevel.closedCaptions === 'NONE') {
+ this.enabled = false;
+ } else {
+ this.enabled = true;
+ }
+ }
+ }, {
+ key: 'onFragLoaded',
+ value: function onFragLoaded(data) {
+ if (data.frag.type === 'main') {
+ var pts = data.frag.start; //Number.POSITIVE_INFINITY;
+ // if this is a frag for a previously loaded timerange, remove all captions
+ // TODO: consider just removing captions for the timerange
+ if (pts <= this.lastPts) {
+ this.clearCurrentCues(this.textTrack1);
+ this.clearCurrentCues(this.textTrack2);
+ }
+ this.lastPts = pts;
+ }
+ }
+ }, {
+ key: 'onFragParsingUserdata',
+ value: function onFragParsingUserdata(data) {
+ // push all of the CEA-708 messages into the interpreter
+ // immediately. It will create the proper timestamps based on our PTS value
+ if (this.enabled) {
+ for (var i = 0; i < data.samples.length; i++) {
+ var ccdatas = this.extractCea608Data(data.samples[i].bytes);
+ this.cea608Parser.addData(data.samples[i].pts, ccdatas);
+ }
+ }
+ }
+ }, {
+ key: 'extractCea608Data',
+ value: function extractCea608Data(byteArray) {
+ var count = byteArray[0] & 31;
+ var position = 2;
+ var tmpByte, ccbyte1, ccbyte2, ccValid, ccType;
+ var actualCCBytes = [];
+
+ for (var j = 0; j < count; j++) {
+ tmpByte = byteArray[position++];
+ ccbyte1 = 0x7F & byteArray[position++];
+ ccbyte2 = 0x7F & byteArray[position++];
+ ccValid = (4 & tmpByte) === 0 ? false : true;
+ ccType = 3 & tmpByte;
+
+ if (ccbyte1 === 0 && ccbyte2 === 0) {
+ continue;
+ }
+
+ if (ccValid) {
+ if (ccType === 0) // || ccType === 1
+ {
+ actualCCBytes.push(ccbyte1);
+ actualCCBytes.push(ccbyte2);
+ }
+ }
+ }
+ return actualCCBytes;
+ }
+ }]);
+
+ return TimelineController;
+ }(_eventHandler2.default);
+
+ exports.default = TimelineController;
+
+ },{"25":25,"26":26,"40":40}],13:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ /*
+ *
+ * This file contains an adaptation of the AES decryption algorithm
+ * from the Standford Javascript Cryptography Library. That work is
+ * covered by the following copyright and permissions notice:
+ *
+ * Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the authors.
+ */
+
+ var AES = function () {
+
+ /**
+ * Schedule out an AES key for both encryption and decryption. This
+ * is a low-level class. Use a cipher mode to do bulk encryption.
+ *
+ * @constructor
+ * @param key {Array} The key as an array of 4, 6 or 8 words.
+ */
+
+ function AES(key) {
+ _classCallCheck(this, AES);
+
+ /**
+ * The expanded S-box and inverse S-box tables. These will be computed
+ * on the client so that we don't have to send them down the wire.
+ *
+ * There are two tables, _tables[0] is for encryption and
+ * _tables[1] is for decryption.
+ *
+ * The first 4 sub-tables are the expanded S-box with MixColumns. The
+ * last (_tables[01][4]) is the S-box itself.
+ *
+ * @private
+ */
+ this._tables = [[[], [], [], [], []], [[], [], [], [], []]];
+
+ this._precompute();
+
+ var i,
+ j,
+ tmp,
+ encKey,
+ decKey,
+ sbox = this._tables[0][4],
+ decTable = this._tables[1],
+ keyLen = key.length,
+ rcon = 1;
+
+ if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
+ throw new Error('Invalid aes key size=' + keyLen);
+ }
+
+ encKey = key.slice(0);
+ decKey = [];
+ this._key = [encKey, decKey];
+
+ // schedule encryption keys
+ for (i = keyLen; i < 4 * keyLen + 28; i++) {
+ tmp = encKey[i - 1];
+
+ // apply sbox
+ if (i % keyLen === 0 || keyLen === 8 && i % keyLen === 4) {
+ tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255];
+
+ // shift rows and add rcon
+ if (i % keyLen === 0) {
+ tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24;
+ rcon = rcon << 1 ^ (rcon >> 7) * 283;
+ }
+ }
+
+ encKey[i] = encKey[i - keyLen] ^ tmp;
+ }
+
+ // schedule decryption keys
+ for (j = 0; i; j++, i--) {
+ tmp = encKey[j & 3 ? i : i - 4];
+ if (i <= 4 || j < 4) {
+ decKey[j] = tmp;
+ } else {
+ decKey[j] = decTable[0][sbox[tmp >>> 24]] ^ decTable[1][sbox[tmp >> 16 & 255]] ^ decTable[2][sbox[tmp >> 8 & 255]] ^ decTable[3][sbox[tmp & 255]];
+ }
+ }
+ }
+
+ /**
+ * Expand the S-box tables.
+ *
+ * @private
+ */
+
+
+ _createClass(AES, [{
+ key: '_precompute',
+ value: function _precompute() {
+ var encTable = this._tables[0],
+ decTable = this._tables[1],
+ sbox = encTable[4],
+ sboxInv = decTable[4],
+ i,
+ x,
+ xInv,
+ d = [],
+ th = [],
+ x2,
+ x4,
+ x8,
+ s,
+ tEnc,
+ tDec;
+
+ // Compute double and third tables
+ for (i = 0; i < 256; i++) {
+ th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i;
+ }
+
+ for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
+ // Compute sbox
+ s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4;
+ s = s >> 8 ^ s & 255 ^ 99;
+ sbox[x] = s;
+ sboxInv[s] = x;
+
+ // Compute MixColumns
+ x8 = d[x4 = d[x2 = d[x]]];
+ tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;
+ tEnc = d[s] * 0x101 ^ s * 0x1010100;
+
+ for (i = 0; i < 4; i++) {
+ encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8;
+ decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8;
+ }
+ }
+
+ // Compactify. Considerable speedup on Firefox.
+ for (i = 0; i < 5; i++) {
+ encTable[i] = encTable[i].slice(0);
+ decTable[i] = decTable[i].slice(0);
+ }
+ }
+
+ /**
+ * Decrypt 16 bytes, specified as four 32-bit words.
+ * @param encrypted0 {number} the first word to decrypt
+ * @param encrypted1 {number} the second word to decrypt
+ * @param encrypted2 {number} the third word to decrypt
+ * @param encrypted3 {number} the fourth word to decrypt
+ * @param out {Int32Array} the array to write the decrypted words
+ * into
+ * @param offset {number} the offset into the output array to start
+ * writing results
+ * @return {Array} The plaintext.
+ */
+
+ }, {
+ key: 'decrypt',
+ value: function decrypt(encrypted0, encrypted1, encrypted2, encrypted3, out, offset) {
+ var key = this._key[1],
+
+ // state variables a,b,c,d are loaded with pre-whitened data
+ a = encrypted0 ^ key[0],
+ b = encrypted3 ^ key[1],
+ c = encrypted2 ^ key[2],
+ d = encrypted1 ^ key[3],
+ a2,
+ b2,
+ c2,
+ nInnerRounds = key.length / 4 - 2,
+ // key.length === 2 ?
+ i,
+ kIndex = 4,
+ table = this._tables[1],
+
+
+ // load up the tables
+ table0 = table[0],
+ table1 = table[1],
+ table2 = table[2],
+ table3 = table[3],
+ sbox = table[4];
+
+ // Inner rounds. Cribbed from OpenSSL.
+ for (i = 0; i < nInnerRounds; i++) {
+ a2 = table0[a >>> 24] ^ table1[b >> 16 & 255] ^ table2[c >> 8 & 255] ^ table3[d & 255] ^ key[kIndex];
+ b2 = table0[b >>> 24] ^ table1[c >> 16 & 255] ^ table2[d >> 8 & 255] ^ table3[a & 255] ^ key[kIndex + 1];
+ c2 = table0[c >>> 24] ^ table1[d >> 16 & 255] ^ table2[a >> 8 & 255] ^ table3[b & 255] ^ key[kIndex + 2];
+ d = table0[d >>> 24] ^ table1[a >> 16 & 255] ^ table2[b >> 8 & 255] ^ table3[c & 255] ^ key[kIndex + 3];
+ kIndex += 4;
+ a = a2;b = b2;c = c2;
+ }
+
+ // Last round.
+ for (i = 0; i < 4; i++) {
+ out[(3 & -i) + offset] = sbox[a >>> 24] << 24 ^ sbox[b >> 16 & 255] << 16 ^ sbox[c >> 8 & 255] << 8 ^ sbox[d & 255] ^ key[kIndex++];
+ a2 = a;a = b;b = c;c = d;d = a2;
+ }
+ }
+ }]);
+
+ return AES;
+ }();
+
+ exports.default = AES;
+
+ },{}],14:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
+ *
+ * This file contains an adaptation of the AES decryption algorithm
+ * from the Standford Javascript Cryptography Library. That work is
+ * covered by the following copyright and permissions notice:
+ *
+ * Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the authors.
+ */
+
+ var _aes = _dereq_(13);
+
+ var _aes2 = _interopRequireDefault(_aes);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var AES128Decrypter = function () {
+ function AES128Decrypter(key, initVector) {
+ _classCallCheck(this, AES128Decrypter);
+
+ this.key = key;
+ this.iv = initVector;
+ }
+
+ /**
+ * Convert network-order (big-endian) bytes into their little-endian
+ * representation.
+ */
+
+
+ _createClass(AES128Decrypter, [{
+ key: 'ntoh',
+ value: function ntoh(word) {
+ return word << 24 | (word & 0xff00) << 8 | (word & 0xff0000) >> 8 | word >>> 24;
+ }
+
+ /**
+ * Decrypt bytes using AES-128 with CBC and PKCS#7 padding.
+ * @param encrypted {Uint8Array} the encrypted bytes
+ * @param key {Uint32Array} the bytes of the decryption key
+ * @param initVector {Uint32Array} the initialization vector (IV) to
+ * use for the first round of CBC.
+ * @return {Uint8Array} the decrypted bytes
+ *
+ * @see http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
+ * @see http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29
+ * @see https://tools.ietf.org/html/rfc2315
+ */
+
+ }, {
+ key: 'doDecrypt',
+ value: function doDecrypt(encrypted, key, initVector) {
+ var
+ // word-level access to the encrypted bytes
+ encrypted32 = new Int32Array(encrypted.buffer, encrypted.byteOffset, encrypted.byteLength >> 2),
+ decipher = new _aes2.default(Array.prototype.slice.call(key)),
+
+
+ // byte and word-level access for the decrypted output
+ decrypted = new Uint8Array(encrypted.byteLength),
+ decrypted32 = new Int32Array(decrypted.buffer),
+
+
+ // temporary variables for working with the IV, encrypted, and
+ // decrypted data
+ init0,
+ init1,
+ init2,
+ init3,
+ encrypted0,
+ encrypted1,
+ encrypted2,
+ encrypted3,
+
+
+ // iteration variable
+ wordIx;
+
+ // pull out the words of the IV to ensure we don't modify the
+ // passed-in reference and easier access
+ init0 = ~ ~initVector[0];
+ init1 = ~ ~initVector[1];
+ init2 = ~ ~initVector[2];
+ init3 = ~ ~initVector[3];
+
+ // decrypt four word sequences, applying cipher-block chaining (CBC)
+ // to each decrypted block
+ for (wordIx = 0; wordIx < encrypted32.length; wordIx += 4) {
+ // convert big-endian (network order) words into little-endian
+ // (javascript order)
+ encrypted0 = ~ ~this.ntoh(encrypted32[wordIx]);
+ encrypted1 = ~ ~this.ntoh(encrypted32[wordIx + 1]);
+ encrypted2 = ~ ~this.ntoh(encrypted32[wordIx + 2]);
+ encrypted3 = ~ ~this.ntoh(encrypted32[wordIx + 3]);
+
+ // decrypt the block
+ decipher.decrypt(encrypted0, encrypted1, encrypted2, encrypted3, decrypted32, wordIx);
+
+ // XOR with the IV, and restore network byte-order to obtain the
+ // plaintext
+ decrypted32[wordIx] = this.ntoh(decrypted32[wordIx] ^ init0);
+ decrypted32[wordIx + 1] = this.ntoh(decrypted32[wordIx + 1] ^ init1);
+ decrypted32[wordIx + 2] = this.ntoh(decrypted32[wordIx + 2] ^ init2);
+ decrypted32[wordIx + 3] = this.ntoh(decrypted32[wordIx + 3] ^ init3);
+
+ // setup the IV for the next round
+ init0 = encrypted0;
+ init1 = encrypted1;
+ init2 = encrypted2;
+ init3 = encrypted3;
+ }
+
+ return decrypted;
+ }
+ }, {
+ key: 'localDecrypt',
+ value: function localDecrypt(encrypted, key, initVector, decrypted) {
+ var bytes = this.doDecrypt(encrypted, key, initVector);
+ decrypted.set(bytes, encrypted.byteOffset);
+ }
+ }, {
+ key: 'decrypt',
+ value: function decrypt(encrypted) {
+ var step = 4 * 8000,
+
+ //encrypted32 = new Int32Array(encrypted.buffer),
+ encrypted32 = new Int32Array(encrypted),
+ decrypted = new Uint8Array(encrypted.byteLength),
+ i = 0;
+
+ // split up the encryption job and do the individual chunks asynchronously
+ var key = this.key;
+ var initVector = this.iv;
+ this.localDecrypt(encrypted32.subarray(i, i + step), key, initVector, decrypted);
+
+ for (i = step; i < encrypted32.length; i += step) {
+ initVector = new Uint32Array([this.ntoh(encrypted32[i - 4]), this.ntoh(encrypted32[i - 3]), this.ntoh(encrypted32[i - 2]), this.ntoh(encrypted32[i - 1])]);
+ this.localDecrypt(encrypted32.subarray(i, i + step), key, initVector, decrypted);
+ }
+
+ return decrypted;
+ }
+ }]);
+
+ return AES128Decrypter;
+ }();
+
+ exports.default = AES128Decrypter;
+
+ },{"13":13}],15:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
+ * AES128 decryption.
+ */
+
+ var _aes128Decrypter = _dereq_(14);
+
+ var _aes128Decrypter2 = _interopRequireDefault(_aes128Decrypter);
+
+ var _errors = _dereq_(24);
+
+ var _logger = _dereq_(43);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Decrypter = function () {
+ function Decrypter(hls) {
+ _classCallCheck(this, Decrypter);
+
+ this.hls = hls;
+ try {
+ var browserCrypto = window ? window.crypto : crypto;
+ this.subtle = browserCrypto.subtle || browserCrypto.webkitSubtle;
+ this.disableWebCrypto = !this.subtle;
+ } catch (e) {
+ this.disableWebCrypto = true;
+ }
+ }
+
+ _createClass(Decrypter, [{
+ key: 'destroy',
+ value: function destroy() {}
+ }, {
+ key: 'decrypt',
+ value: function decrypt(data, key, iv, callback) {
+ if (this.disableWebCrypto && this.hls.config.enableSoftwareAES) {
+ this.decryptBySoftware(data, key, iv, callback);
+ } else {
+ this.decryptByWebCrypto(data, key, iv, callback);
+ }
+ }
+ }, {
+ key: 'decryptByWebCrypto',
+ value: function decryptByWebCrypto(data, key, iv, callback) {
+ var _this = this;
+
+ _logger.logger.log('decrypting by WebCrypto API');
+
+ this.subtle.importKey('raw', key, { name: 'AES-CBC', length: 128 }, false, ['decrypt']).then(function (importedKey) {
+ _this.subtle.decrypt({ name: 'AES-CBC', iv: iv.buffer }, importedKey, data).then(callback).catch(function (err) {
+ _this.onWebCryptoError(err, data, key, iv, callback);
+ });
+ }).catch(function (err) {
+ _this.onWebCryptoError(err, data, key, iv, callback);
+ });
+ }
+ }, {
+ key: 'decryptBySoftware',
+ value: function decryptBySoftware(data, key8, iv8, callback) {
+ _logger.logger.log('decrypting by JavaScript Implementation');
+
+ var view = new DataView(key8.buffer);
+ var key = new Uint32Array([view.getUint32(0), view.getUint32(4), view.getUint32(8), view.getUint32(12)]);
+
+ view = new DataView(iv8.buffer);
+ var iv = new Uint32Array([view.getUint32(0), view.getUint32(4), view.getUint32(8), view.getUint32(12)]);
+
+ var decrypter = new _aes128Decrypter2.default(key, iv);
+ callback(decrypter.decrypt(data).buffer);
+ }
+ }, {
+ key: 'onWebCryptoError',
+ value: function onWebCryptoError(err, data, key, iv, callback) {
+ if (this.hls.config.enableSoftwareAES) {
+ _logger.logger.log('disabling to use WebCrypto API');
+ this.disableWebCrypto = true;
+ this.decryptBySoftware(data, key, iv, callback);
+ } else {
+ _logger.logger.error('decrypting error : ' + err.message);
+ this.hls.trigger(Event.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, details: _errors.ErrorDetails.FRAG_DECRYPT_ERROR, fatal: true, reason: err.message });
+ }
+ }
+ }]);
+
+ return Decrypter;
+ }();
+
+ exports.default = Decrypter;
+
+ },{"14":14,"24":24,"43":43}],16:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
+ * AAC demuxer
+ */
+
+
+ var _adts = _dereq_(17);
+
+ var _adts2 = _interopRequireDefault(_adts);
+
+ var _logger = _dereq_(43);
+
+ var _id = _dereq_(22);
+
+ var _id2 = _interopRequireDefault(_id);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var AACDemuxer = function () {
+ function AACDemuxer(observer, id, remuxerClass, config) {
+ _classCallCheck(this, AACDemuxer);
+
+ this.observer = observer;
+ this.id = id;
+ this.remuxerClass = remuxerClass;
+ this.config = config;
+ this.remuxer = new this.remuxerClass(observer, id, config);
+ this.insertDiscontinuity();
+ }
+
+ _createClass(AACDemuxer, [{
+ key: 'insertDiscontinuity',
+ value: function insertDiscontinuity() {
+ this._aacTrack = { container: 'audio/adts', type: 'audio', id: -1, sequenceNumber: 0, samples: [], len: 0 };
+ }
+ }, {
+ key: 'push',
+
+
+ // feed incoming data to the front of the parsing pipeline
+ value: function push(data, audioCodec, videoCodec, timeOffset, cc, level, sn, duration, accurateTimeOffset) {
+ var track,
+ id3 = new _id2.default(data),
+ pts = 90 * id3.timeStamp,
+ config,
+ frameLength,
+ frameDuration,
+ frameIndex,
+ offset,
+ headerLength,
+ stamp,
+ len,
+ aacSample;
+
+ var contiguous = false;
+ if (cc !== this.lastCC) {
+ _logger.logger.log(this.id + ' discontinuity detected');
+ this.lastCC = cc;
+ this.insertDiscontinuity();
+ this.remuxer.switchLevel();
+ this.remuxer.insertDiscontinuity();
+ } else if (level !== this.lastLevel) {
+ _logger.logger.log('audio track switch detected');
+ this.lastLevel = level;
+ this.remuxer.switchLevel();
+ this.insertDiscontinuity();
+ } else if (sn === this.lastSN + 1) {
+ contiguous = true;
+ }
+ track = this._aacTrack;
+ this.lastSN = sn;
+ this.lastLevel = level;
+
+ // look for ADTS header (0xFFFx)
+ for (offset = id3.length, len = data.length; offset < len - 1; offset++) {
+ if (data[offset] === 0xff && (data[offset + 1] & 0xf0) === 0xf0) {
+ break;
+ }
+ }
+
+ if (!track.audiosamplerate) {
+ config = _adts2.default.getAudioConfig(this.observer, data, offset, audioCodec);
+ track.config = config.config;
+ track.audiosamplerate = config.samplerate;
+ track.channelCount = config.channelCount;
+ track.codec = config.codec;
+ track.duration = duration;
+ _logger.logger.log('parsed codec:' + track.codec + ',rate:' + config.samplerate + ',nb channel:' + config.channelCount);
+ }
+ frameIndex = 0;
+ frameDuration = 1024 * 90000 / track.audiosamplerate;
+ while (offset + 5 < len) {
+ // The protection skip bit tells us if we have 2 bytes of CRC data at the end of the ADTS header
+ headerLength = !!(data[offset + 1] & 0x01) ? 7 : 9;
+ // retrieve frame size
+ frameLength = (data[offset + 3] & 0x03) << 11 | data[offset + 4] << 3 | (data[offset + 5] & 0xE0) >>> 5;
+ frameLength -= headerLength;
+ //stamp = pes.pts;
+
+ if (frameLength > 0 && offset + headerLength + frameLength <= len) {
+ stamp = pts + frameIndex * frameDuration;
+ //logger.log(`AAC frame, offset/length/total/pts:${offset+headerLength}/${frameLength}/${data.byteLength}/${(stamp/90).toFixed(0)}`);
+ aacSample = { unit: data.subarray(offset + headerLength, offset + headerLength + frameLength), pts: stamp, dts: stamp };
+ track.samples.push(aacSample);
+ track.len += frameLength;
+ offset += frameLength + headerLength;
+ frameIndex++;
+ // look for ADTS header (0xFFFx)
+ for (; offset < len - 1; offset++) {
+ if (data[offset] === 0xff && (data[offset + 1] & 0xf0) === 0xf0) {
+ break;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+ this.remuxer.remux(level, sn, this._aacTrack, { samples: [] }, { samples: [{ pts: pts, dts: pts, unit: id3.payload }] }, { samples: [] }, timeOffset, contiguous, accurateTimeOffset);
+ }
+ }, {
+ key: 'destroy',
+ value: function destroy() {}
+ }], [{
+ key: 'probe',
+ value: function probe(data) {
+ // check if data contains ID3 timestamp and ADTS sync worc
+ var id3 = new _id2.default(data),
+ offset,
+ len;
+ if (id3.hasTimeStamp) {
+ // look for ADTS header (0xFFFx)
+ for (offset = id3.length, len = data.length; offset < len - 1; offset++) {
+ if (data[offset] === 0xff && (data[offset + 1] & 0xf0) === 0xf0) {
+ //logger.log('ADTS sync word found !');
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }]);
+
+ return AACDemuxer;
+ }();
+
+ exports.default = AACDemuxer;
+
+ },{"17":17,"22":22,"43":43}],17:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
+ * ADTS parser helper
+ */
+
+
+ var _logger = _dereq_(43);
+
+ var _errors = _dereq_(24);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var ADTS = function () {
+ function ADTS() {
+ _classCallCheck(this, ADTS);
+ }
+
+ _createClass(ADTS, null, [{
+ key: 'getAudioConfig',
+ value: function getAudioConfig(observer, data, offset, audioCodec) {
+ var adtsObjectType,
+ // :int
+ adtsSampleingIndex,
+ // :int
+ adtsExtensionSampleingIndex,
+ // :int
+ adtsChanelConfig,
+ // :int
+ config,
+ userAgent = navigator.userAgent.toLowerCase(),
+ adtsSampleingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
+ // byte 2
+ adtsObjectType = ((data[offset + 2] & 0xC0) >>> 6) + 1;
+ adtsSampleingIndex = (data[offset + 2] & 0x3C) >>> 2;
+ if (adtsSampleingIndex > adtsSampleingRates.length - 1) {
+ observer.trigger(Event.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, details: _errors.ErrorDetails.FRAG_PARSING_ERROR, fatal: true, reason: 'invalid ADTS sampling index:' + adtsSampleingIndex });
+ return;
+ }
+ adtsChanelConfig = (data[offset + 2] & 0x01) << 2;
+ // byte 3
+ adtsChanelConfig |= (data[offset + 3] & 0xC0) >>> 6;
+ _logger.logger.log('manifest codec:' + audioCodec + ',ADTS data:type:' + adtsObjectType + ',sampleingIndex:' + adtsSampleingIndex + '[' + adtsSampleingRates[adtsSampleingIndex] + 'Hz],channelConfig:' + adtsChanelConfig);
+ // firefox/Opera: freq less than 24kHz = AAC SBR (HE-AAC)
+ if (/firefox|OPR/i.test(userAgent)) {
+ if (adtsSampleingIndex >= 6) {
+ adtsObjectType = 5;
+ config = new Array(4);
+ // HE-AAC uses SBR (Spectral Band Replication) , high frequencies are constructed from low frequencies
+ // there is a factor 2 between frame sample rate and output sample rate
+ // multiply frequency by 2 (see table below, equivalent to substract 3)
+ adtsExtensionSampleingIndex = adtsSampleingIndex - 3;
+ } else {
+ adtsObjectType = 2;
+ config = new Array(2);
+ adtsExtensionSampleingIndex = adtsSampleingIndex;
+ }
+ // Android : always use AAC
+ } else if (userAgent.indexOf('android') !== -1) {
+ adtsObjectType = 2;
+ config = new Array(2);
+ adtsExtensionSampleingIndex = adtsSampleingIndex;
+ } else {
+ /* for other browsers (Chrome/Vivaldi ...)
+ always force audio type to be HE-AAC SBR, as some browsers do not support audio codec switch properly (like Chrome ...)
+ */
+ adtsObjectType = 5;
+ config = new Array(4);
+ // if (manifest codec is HE-AAC or HE-AACv2) OR (manifest codec not specified AND frequency less than 24kHz)
+ if (audioCodec && (audioCodec.indexOf('mp4a.40.29') !== -1 || audioCodec.indexOf('mp4a.40.5') !== -1) || !audioCodec && adtsSampleingIndex >= 6) {
+ // HE-AAC uses SBR (Spectral Band Replication) , high frequencies are constructed from low frequencies
+ // there is a factor 2 between frame sample rate and output sample rate
+ // multiply frequency by 2 (see table below, equivalent to substract 3)
+ adtsExtensionSampleingIndex = adtsSampleingIndex - 3;
+ } else {
+ // if (manifest codec is AAC) AND (frequency less than 24kHz AND nb channel is 1) OR (manifest codec not specified and mono audio)
+ // Chrome fails to play back with low frequency AAC LC mono when initialized with HE-AAC. This is not a problem with stereo.
+ if (audioCodec && audioCodec.indexOf('mp4a.40.2') !== -1 && adtsSampleingIndex >= 6 && adtsChanelConfig === 1 || !audioCodec && adtsChanelConfig === 1) {
+ adtsObjectType = 2;
+ config = new Array(2);
+ }
+ adtsExtensionSampleingIndex = adtsSampleingIndex;
+ }
+ }
+ /* refer to http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio#Audio_Specific_Config
+ ISO 14496-3 (AAC).pdf - Table 1.13 — Syntax of AudioSpecificConfig()
+ Audio Profile / Audio Object Type
+ 0: Null
+ 1: AAC Main
+ 2: AAC LC (Low Complexity)
+ 3: AAC SSR (Scalable Sample Rate)
+ 4: AAC LTP (Long Term Prediction)
+ 5: SBR (Spectral Band Replication)
+ 6: AAC Scalable
+ sampling freq
+ 0: 96000 Hz
+ 1: 88200 Hz
+ 2: 64000 Hz
+ 3: 48000 Hz
+ 4: 44100 Hz
+ 5: 32000 Hz
+ 6: 24000 Hz
+ 7: 22050 Hz
+ 8: 16000 Hz
+ 9: 12000 Hz
+ 10: 11025 Hz
+ 11: 8000 Hz
+ 12: 7350 Hz
+ 13: Reserved
+ 14: Reserved
+ 15: frequency is written explictly
+ Channel Configurations
+ These are the channel configurations:
+ 0: Defined in AOT Specifc Config
+ 1: 1 channel: front-center
+ 2: 2 channels: front-left, front-right
+ */
+ // audioObjectType = profile => profile, the MPEG-4 Audio Object Type minus 1
+ config[0] = adtsObjectType << 3;
+ // samplingFrequencyIndex
+ config[0] |= (adtsSampleingIndex & 0x0E) >> 1;
+ config[1] |= (adtsSampleingIndex & 0x01) << 7;
+ // channelConfiguration
+ config[1] |= adtsChanelConfig << 3;
+ if (adtsObjectType === 5) {
+ // adtsExtensionSampleingIndex
+ config[1] |= (adtsExtensionSampleingIndex & 0x0E) >> 1;
+ config[2] = (adtsExtensionSampleingIndex & 0x01) << 7;
+ // adtsObjectType (force to 2, chrome is checking that object type is less than 5 ???
+ // https://chromium.googlesource.com/chromium/src.git/+/master/media/formats/mp4/aac.cc
+ config[2] |= 2 << 2;
+ config[3] = 0;
+ }
+ return { config: config, samplerate: adtsSampleingRates[adtsSampleingIndex], channelCount: adtsChanelConfig, codec: 'mp4a.40.' + adtsObjectType };
+ }
+ }]);
+
+ return ADTS;
+ }();
+
+ exports.default = ADTS;
+
+ },{"24":24,"43":43}],18:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /* inline demuxer.
+ * probe fragments and instantiate appropriate demuxer depending on content type (TSDemuxer, AACDemuxer, ...)
+ */
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _errors = _dereq_(24);
+
+ var _aacdemuxer = _dereq_(16);
+
+ var _aacdemuxer2 = _interopRequireDefault(_aacdemuxer);
+
+ var _tsdemuxer = _dereq_(23);
+
+ var _tsdemuxer2 = _interopRequireDefault(_tsdemuxer);
+
+ var _mp4Remuxer = _dereq_(36);
+
+ var _mp4Remuxer2 = _interopRequireDefault(_mp4Remuxer);
+
+ var _passthroughRemuxer = _dereq_(37);
+
+ var _passthroughRemuxer2 = _interopRequireDefault(_passthroughRemuxer);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var DemuxerInline = function () {
+ function DemuxerInline(hls, id, typeSupported) {
+ var config = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3];
+
+ _classCallCheck(this, DemuxerInline);
+
+ this.hls = hls;
+ this.id = id;
+ this.config = this.hls.config || config;
+ this.typeSupported = typeSupported;
+ }
+
+ _createClass(DemuxerInline, [{
+ key: 'destroy',
+ value: function destroy() {
+ var demuxer = this.demuxer;
+ if (demuxer) {
+ demuxer.destroy();
+ }
+ }
+ }, {
+ key: 'push',
+ value: function push(data, audioCodec, videoCodec, timeOffset, cc, level, sn, duration, accurateTimeOffset) {
+ var demuxer = this.demuxer;
+ if (!demuxer) {
+ var hls = this.hls,
+ id = this.id;
+ // probe for content type
+ if (_tsdemuxer2.default.probe(data)) {
+ if (this.typeSupported.mp2t === true) {
+ demuxer = new _tsdemuxer2.default(hls, id, _passthroughRemuxer2.default, this.config);
+ } else {
+ demuxer = new _tsdemuxer2.default(hls, id, _mp4Remuxer2.default, this.config);
+ }
+ } else if (_aacdemuxer2.default.probe(data)) {
+ demuxer = new _aacdemuxer2.default(hls, id, _mp4Remuxer2.default, this.config);
+ } else {
+ hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, id: id, details: _errors.ErrorDetails.FRAG_PARSING_ERROR, fatal: true, reason: 'no demux matching with content found' });
+ return;
+ }
+ this.demuxer = demuxer;
+ }
+ demuxer.push(data, audioCodec, videoCodec, timeOffset, cc, level, sn, duration, accurateTimeOffset);
+ }
+ }]);
+
+ return DemuxerInline;
+ }();
+
+ exports.default = DemuxerInline;
+
+ },{"16":16,"23":23,"24":24,"26":26,"36":36,"37":37}],19:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _demuxerInline = _dereq_(18);
+
+ var _demuxerInline2 = _interopRequireDefault(_demuxerInline);
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _logger = _dereq_(43);
+
+ var _events3 = _dereq_(1);
+
+ var _events4 = _interopRequireDefault(_events3);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ /* demuxer web worker.
+ * - listen to worker message, and trigger DemuxerInline upon reception of Fragments.
+ * - provides MP4 Boxes back to main thread using [transferable objects](https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast) in order to minimize message passing overhead.
+ */
+
+ var DemuxerWorker = function DemuxerWorker(self) {
+ // observer setup
+ var observer = new _events4.default();
+ observer.trigger = function trigger(event) {
+ for (var _len = arguments.length, data = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ data[_key - 1] = arguments[_key];
+ }
+
+ observer.emit.apply(observer, [event, event].concat(data));
+ };
+
+ observer.off = function off(event) {
+ for (var _len2 = arguments.length, data = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
+ data[_key2 - 1] = arguments[_key2];
+ }
+
+ observer.removeListener.apply(observer, [event].concat(data));
+ };
+
+ var forwardMessage = function forwardMessage(ev, data) {
+ self.postMessage({ event: ev, data: data });
+ };
+
+ self.addEventListener('message', function (ev) {
+ var data = ev.data;
+ //console.log('demuxer cmd:' + data.cmd);
+ switch (data.cmd) {
+ case 'init':
+ var config = JSON.parse(data.config);
+ self.demuxer = new _demuxerInline2.default(observer, data.id, data.typeSupported, config);
+ try {
+ (0, _logger.enableLogs)(config.debug);
+ } catch (err) {
+ console.warn('demuxerWorker: unable to enable logs');
+ }
+ // signal end of worker init
+ forwardMessage('init', null);
+ break;
+ case 'demux':
+ self.demuxer.push(new Uint8Array(data.data), data.audioCodec, data.videoCodec, data.timeOffset, data.cc, data.level, data.sn, data.duration, data.accurateTimeOffset);
+ break;
+ default:
+ break;
+ }
+ });
+
+ // forward events to main thread
+ observer.on(_events2.default.FRAG_PARSING_INIT_SEGMENT, forwardMessage);
+ observer.on(_events2.default.FRAG_PARSED, forwardMessage);
+ observer.on(_events2.default.ERROR, forwardMessage);
+ observer.on(_events2.default.FRAG_PARSING_METADATA, forwardMessage);
+ observer.on(_events2.default.FRAG_PARSING_USERDATA, forwardMessage);
+
+ // special case for FRAG_PARSING_DATA: pass data1/data2 as transferable object (no copy)
+ observer.on(_events2.default.FRAG_PARSING_DATA, function (ev, data) {
+ var data1 = data.data1.buffer,
+ data2 = data.data2.buffer;
+ // remove data1 and data2 reference from data to avoid copying them ...
+ delete data.data1;
+ delete data.data2;
+ self.postMessage({ event: ev, data: data, data1: data1, data2: data2 }, [data1, data2]);
+ });
+ };
+
+ exports.default = DemuxerWorker;
+
+ },{"1":1,"18":18,"26":26,"43":43}],20:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _demuxerInline = _dereq_(18);
+
+ var _demuxerInline2 = _interopRequireDefault(_demuxerInline);
+
+ var _demuxerWorker = _dereq_(19);
+
+ var _demuxerWorker2 = _interopRequireDefault(_demuxerWorker);
+
+ var _logger = _dereq_(43);
+
+ var _decrypter = _dereq_(15);
+
+ var _decrypter2 = _interopRequireDefault(_decrypter);
+
+ var _errors = _dereq_(24);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Demuxer = function () {
+ function Demuxer(hls, id) {
+ _classCallCheck(this, Demuxer);
+
+ this.hls = hls;
+ this.id = id;
+ var typeSupported = {
+ mp4: MediaSource.isTypeSupported('video/mp4'),
+ mp2t: hls.config.enableMP2TPassThrough && MediaSource.isTypeSupported('video/mp2t')
+ };
+ if (hls.config.enableWorker && typeof Worker !== 'undefined') {
+ _logger.logger.log('demuxing in webworker');
+ var w = void 0;
+ try {
+ var work = _dereq_(2);
+ w = this.w = work(_demuxerWorker2.default);
+ this.onwmsg = this.onWorkerMessage.bind(this);
+ w.addEventListener('message', this.onwmsg);
+ w.onerror = function (event) {
+ hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.OTHER_ERROR, details: _errors.ErrorDetails.INTERNAL_EXCEPTION, fatal: true, event: 'demuxerWorker', err: { message: event.message + ' (' + event.filename + ':' + event.lineno + ')' } });
+ };
+ w.postMessage({ cmd: 'init', typeSupported: typeSupported, id: id, config: JSON.stringify(hls.config) });
+ } catch (err) {
+ _logger.logger.error('error while initializing DemuxerWorker, fallback on DemuxerInline');
+ if (w) {
+ // revoke the Object URL that was used to create demuxer worker, so as not to leak it
+ URL.revokeObjectURL(w.objectURL);
+ }
+ this.demuxer = new _demuxerInline2.default(hls, id, typeSupported);
+ }
+ } else {
+ this.demuxer = new _demuxerInline2.default(hls, id, typeSupported);
+ }
+ this.demuxInitialized = true;
+ }
+
+ _createClass(Demuxer, [{
+ key: 'destroy',
+ value: function destroy() {
+ var w = this.w;
+ if (w) {
+ w.removeEventListener('message', this.onwmsg);
+ w.terminate();
+ this.w = null;
+ } else {
+ var demuxer = this.demuxer;
+ if (demuxer) {
+ demuxer.destroy();
+ this.demuxer = null;
+ }
+ }
+ var decrypter = this.decrypter;
+ if (decrypter) {
+ decrypter.destroy();
+ this.decrypter = null;
+ }
+ }
+ }, {
+ key: 'pushDecrypted',
+ value: function pushDecrypted(data, audioCodec, videoCodec, timeOffset, cc, level, sn, duration, accurateTimeOffset) {
+ var w = this.w;
+ if (w) {
+ // post fragment payload as transferable objects (no copy)
+ w.postMessage({ cmd: 'demux', data: data, audioCodec: audioCodec, videoCodec: videoCodec, timeOffset: timeOffset, cc: cc, level: level, sn: sn, duration: duration, accurateTimeOffset: accurateTimeOffset }, [data]);
+ } else {
+ var demuxer = this.demuxer;
+ if (demuxer) {
+ demuxer.push(new Uint8Array(data), audioCodec, videoCodec, timeOffset, cc, level, sn, duration, accurateTimeOffset);
+ }
+ }
+ }
+ }, {
+ key: 'push',
+ value: function push(data, audioCodec, videoCodec, timeOffset, cc, level, sn, duration, decryptdata, accurateTimeOffset) {
+ if (data.byteLength > 0 && decryptdata != null && decryptdata.key != null && decryptdata.method === 'AES-128') {
+ if (this.decrypter == null) {
+ this.decrypter = new _decrypter2.default(this.hls);
+ }
+
+ var localthis = this;
+ this.decrypter.decrypt(data, decryptdata.key, decryptdata.iv, function (decryptedData) {
+ localthis.pushDecrypted(decryptedData, audioCodec, videoCodec, timeOffset, cc, level, sn, duration, accurateTimeOffset);
+ });
+ } else {
+ this.pushDecrypted(data, audioCodec, videoCodec, timeOffset, cc, level, sn, duration, accurateTimeOffset);
+ }
+ }
+ }, {
+ key: 'onWorkerMessage',
+ value: function onWorkerMessage(ev) {
+ var data = ev.data,
+ hls = this.hls;
+ //console.log('onWorkerMessage:' + data.event);
+ switch (data.event) {
+ case 'init':
+ // revoke the Object URL that was used to create demuxer worker, so as not to leak it
+ URL.revokeObjectURL(this.w.objectURL);
+ break;
+ // special case for FRAG_PARSING_DATA: data1 and data2 are transferable objects
+ case _events2.default.FRAG_PARSING_DATA:
+ data.data.data1 = new Uint8Array(data.data1);
+ data.data.data2 = new Uint8Array(data.data2);
+ /* falls through */
+ default:
+ hls.trigger(data.event, data.data);
+ break;
+ }
+ }
+ }]);
+
+ return Demuxer;
+ }();
+
+ exports.default = Demuxer;
+
+ },{"15":15,"18":18,"19":19,"2":2,"24":24,"26":26,"43":43}],21:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
+ * Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.
+ */
+
+ var _logger = _dereq_(43);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var ExpGolomb = function () {
+ function ExpGolomb(data) {
+ _classCallCheck(this, ExpGolomb);
+
+ this.data = data;
+ // the number of bytes left to examine in this.data
+ this.bytesAvailable = this.data.byteLength;
+ // the current word being examined
+ this.word = 0; // :uint
+ // the number of bits left to examine in the current word
+ this.bitsAvailable = 0; // :uint
+ }
+
+ // ():void
+
+
+ _createClass(ExpGolomb, [{
+ key: 'loadWord',
+ value: function loadWord() {
+ var position = this.data.byteLength - this.bytesAvailable,
+ workingBytes = new Uint8Array(4),
+ availableBytes = Math.min(4, this.bytesAvailable);
+ if (availableBytes === 0) {
+ throw new Error('no bytes available');
+ }
+ workingBytes.set(this.data.subarray(position, position + availableBytes));
+ this.word = new DataView(workingBytes.buffer).getUint32(0);
+ // track the amount of this.data that has been processed
+ this.bitsAvailable = availableBytes * 8;
+ this.bytesAvailable -= availableBytes;
+ }
+
+ // (count:int):void
+
+ }, {
+ key: 'skipBits',
+ value: function skipBits(count) {
+ var skipBytes; // :int
+ if (this.bitsAvailable > count) {
+ this.word <<= count;
+ this.bitsAvailable -= count;
+ } else {
+ count -= this.bitsAvailable;
+ skipBytes = count >> 3;
+ count -= skipBytes >> 3;
+ this.bytesAvailable -= skipBytes;
+ this.loadWord();
+ this.word <<= count;
+ this.bitsAvailable -= count;
+ }
+ }
+
+ // (size:int):uint
+
+ }, {
+ key: 'readBits',
+ value: function readBits(size) {
+ var bits = Math.min(this.bitsAvailable, size),
+ // :uint
+ valu = this.word >>> 32 - bits; // :uint
+ if (size > 32) {
+ _logger.logger.error('Cannot read more than 32 bits at a time');
+ }
+ this.bitsAvailable -= bits;
+ if (this.bitsAvailable > 0) {
+ this.word <<= bits;
+ } else if (this.bytesAvailable > 0) {
+ this.loadWord();
+ }
+ bits = size - bits;
+ if (bits > 0 && this.bitsAvailable) {
+ return valu << bits | this.readBits(bits);
+ } else {
+ return valu;
+ }
+ }
+
+ // ():uint
+
+ }, {
+ key: 'skipLZ',
+ value: function skipLZ() {
+ var leadingZeroCount; // :uint
+ for (leadingZeroCount = 0; leadingZeroCount < this.bitsAvailable; ++leadingZeroCount) {
+ if (0 !== (this.word & 0x80000000 >>> leadingZeroCount)) {
+ // the first bit of working word is 1
+ this.word <<= leadingZeroCount;
+ this.bitsAvailable -= leadingZeroCount;
+ return leadingZeroCount;
+ }
+ }
+ // we exhausted word and still have not found a 1
+ this.loadWord();
+ return leadingZeroCount + this.skipLZ();
+ }
+
+ // ():void
+
+ }, {
+ key: 'skipUEG',
+ value: function skipUEG() {
+ this.skipBits(1 + this.skipLZ());
+ }
+
+ // ():void
+
+ }, {
+ key: 'skipEG',
+ value: function skipEG() {
+ this.skipBits(1 + this.skipLZ());
+ }
+
+ // ():uint
+
+ }, {
+ key: 'readUEG',
+ value: function readUEG() {
+ var clz = this.skipLZ(); // :uint
+ return this.readBits(clz + 1) - 1;
+ }
+
+ // ():int
+
+ }, {
+ key: 'readEG',
+ value: function readEG() {
+ var valu = this.readUEG(); // :int
+ if (0x01 & valu) {
+ // the number is odd if the low order bit is set
+ return 1 + valu >>> 1; // add 1 to make it even, and divide by 2
+ } else {
+ return -1 * (valu >>> 1); // divide by two then make it negative
+ }
+ }
+
+ // Some convenience functions
+ // :Boolean
+
+ }, {
+ key: 'readBoolean',
+ value: function readBoolean() {
+ return 1 === this.readBits(1);
+ }
+
+ // ():int
+
+ }, {
+ key: 'readUByte',
+ value: function readUByte() {
+ return this.readBits(8);
+ }
+
+ // ():int
+
+ }, {
+ key: 'readUShort',
+ value: function readUShort() {
+ return this.readBits(16);
+ }
+ // ():int
+
+ }, {
+ key: 'readUInt',
+ value: function readUInt() {
+ return this.readBits(32);
+ }
+
+ /**
+ * Advance the ExpGolomb decoder past a scaling list. The scaling
+ * list is optionally transmitted as part of a sequence parameter
+ * set and is not relevant to transmuxing.
+ * @param count {number} the number of entries in this scaling list
+ * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
+ */
+
+ }, {
+ key: 'skipScalingList',
+ value: function skipScalingList(count) {
+ var lastScale = 8,
+ nextScale = 8,
+ j,
+ deltaScale;
+ for (j = 0; j < count; j++) {
+ if (nextScale !== 0) {
+ deltaScale = this.readEG();
+ nextScale = (lastScale + deltaScale + 256) % 256;
+ }
+ lastScale = nextScale === 0 ? lastScale : nextScale;
+ }
+ }
+
+ /**
+ * Read a sequence parameter set and return some interesting video
+ * properties. A sequence parameter set is the H264 metadata that
+ * describes the properties of upcoming video frames.
+ * @param data {Uint8Array} the bytes of a sequence parameter set
+ * @return {object} an object with configuration parsed from the
+ * sequence parameter set, including the dimensions of the
+ * associated video frames.
+ */
+
+ }, {
+ key: 'readSPS',
+ value: function readSPS() {
+ var frameCropLeftOffset = 0,
+ frameCropRightOffset = 0,
+ frameCropTopOffset = 0,
+ frameCropBottomOffset = 0,
+ sarScale = 1,
+ profileIdc,
+ profileCompat,
+ levelIdc,
+ numRefFramesInPicOrderCntCycle,
+ picWidthInMbsMinus1,
+ picHeightInMapUnitsMinus1,
+ frameMbsOnlyFlag,
+ scalingListCount,
+ i;
+ this.readUByte();
+ profileIdc = this.readUByte(); // profile_idc
+ profileCompat = this.readBits(5); // constraint_set[0-4]_flag, u(5)
+ this.skipBits(3); // reserved_zero_3bits u(3),
+ levelIdc = this.readUByte(); //level_idc u(8)
+ this.skipUEG(); // seq_parameter_set_id
+ // some profiles have more optional data we don't need
+ if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) {
+ var chromaFormatIdc = this.readUEG();
+ if (chromaFormatIdc === 3) {
+ this.skipBits(1); // separate_colour_plane_flag
+ }
+ this.skipUEG(); // bit_depth_luma_minus8
+ this.skipUEG(); // bit_depth_chroma_minus8
+ this.skipBits(1); // qpprime_y_zero_transform_bypass_flag
+ if (this.readBoolean()) {
+ // seq_scaling_matrix_present_flag
+ scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
+ for (i = 0; i < scalingListCount; i++) {
+ if (this.readBoolean()) {
+ // seq_scaling_list_present_flag[ i ]
+ if (i < 6) {
+ this.skipScalingList(16);
+ } else {
+ this.skipScalingList(64);
+ }
+ }
+ }
+ }
+ }
+ this.skipUEG(); // log2_max_frame_num_minus4
+ var picOrderCntType = this.readUEG();
+ if (picOrderCntType === 0) {
+ this.readUEG(); //log2_max_pic_order_cnt_lsb_minus4
+ } else if (picOrderCntType === 1) {
+ this.skipBits(1); // delta_pic_order_always_zero_flag
+ this.skipEG(); // offset_for_non_ref_pic
+ this.skipEG(); // offset_for_top_to_bottom_field
+ numRefFramesInPicOrderCntCycle = this.readUEG();
+ for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
+ this.skipEG(); // offset_for_ref_frame[ i ]
+ }
+ }
+ this.skipUEG(); // max_num_ref_frames
+ this.skipBits(1); // gaps_in_frame_num_value_allowed_flag
+ picWidthInMbsMinus1 = this.readUEG();
+ picHeightInMapUnitsMinus1 = this.readUEG();
+ frameMbsOnlyFlag = this.readBits(1);
+ if (frameMbsOnlyFlag === 0) {
+ this.skipBits(1); // mb_adaptive_frame_field_flag
+ }
+ this.skipBits(1); // direct_8x8_inference_flag
+ if (this.readBoolean()) {
+ // frame_cropping_flag
+ frameCropLeftOffset = this.readUEG();
+ frameCropRightOffset = this.readUEG();
+ frameCropTopOffset = this.readUEG();
+ frameCropBottomOffset = this.readUEG();
+ }
+ if (this.readBoolean()) {
+ // vui_parameters_present_flag
+ if (this.readBoolean()) {
+ // aspect_ratio_info_present_flag
+ var sarRatio = void 0;
+ var aspectRatioIdc = this.readUByte();
+ switch (aspectRatioIdc) {
+ case 1:
+ sarRatio = [1, 1];break;
+ case 2:
+ sarRatio = [12, 11];break;
+ case 3:
+ sarRatio = [10, 11];break;
+ case 4:
+ sarRatio = [16, 11];break;
+ case 5:
+ sarRatio = [40, 33];break;
+ case 6:
+ sarRatio = [24, 11];break;
+ case 7:
+ sarRatio = [20, 11];break;
+ case 8:
+ sarRatio = [32, 11];break;
+ case 9:
+ sarRatio = [80, 33];break;
+ case 10:
+ sarRatio = [18, 11];break;
+ case 11:
+ sarRatio = [15, 11];break;
+ case 12:
+ sarRatio = [64, 33];break;
+ case 13:
+ sarRatio = [160, 99];break;
+ case 14:
+ sarRatio = [4, 3];break;
+ case 15:
+ sarRatio = [3, 2];break;
+ case 16:
+ sarRatio = [2, 1];break;
+ case 255:
+ {
+ sarRatio = [this.readUByte() << 8 | this.readUByte(), this.readUByte() << 8 | this.readUByte()];
+ break;
+ }
+ }
+ if (sarRatio) {
+ sarScale = sarRatio[0] / sarRatio[1];
+ }
+ }
+ }
+ return {
+ width: Math.ceil(((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2) * sarScale),
+ height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset)
+ };
+ }
+ }, {
+ key: 'readSliceType',
+ value: function readSliceType() {
+ // skip NALu type
+ this.readUByte();
+ // discard first_mb_in_slice
+ this.readUEG();
+ // return slice_type
+ return this.readUEG();
+ }
+ }]);
+
+ return ExpGolomb;
+ }();
+
+ exports.default = ExpGolomb;
+
+ },{"43":43}],22:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
+ * ID3 parser
+ */
+
+
+ var _logger = _dereq_(43);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ //import Hex from '../utils/hex';
+
+ var ID3 = function () {
+ function ID3(data) {
+ _classCallCheck(this, ID3);
+
+ this._hasTimeStamp = false;
+ var offset = 0,
+ byte1,
+ byte2,
+ byte3,
+ byte4,
+ tagSize,
+ endPos,
+ header,
+ len;
+ do {
+ header = this.readUTF(data, offset, 3);
+ offset += 3;
+ // first check for ID3 header
+ if (header === 'ID3') {
+ // skip 24 bits
+ offset += 3;
+ // retrieve tag(s) length
+ byte1 = data[offset++] & 0x7f;
+ byte2 = data[offset++] & 0x7f;
+ byte3 = data[offset++] & 0x7f;
+ byte4 = data[offset++] & 0x7f;
+ tagSize = (byte1 << 21) + (byte2 << 14) + (byte3 << 7) + byte4;
+ endPos = offset + tagSize;
+ //logger.log(`ID3 tag found, size/end: ${tagSize}/${endPos}`);
+
+ // read ID3 tags
+ this._parseID3Frames(data, offset, endPos);
+ offset = endPos;
+ } else if (header === '3DI') {
+ // http://id3.org/id3v2.4.0-structure chapter 3.4. ID3v2 footer
+ offset += 7;
+ _logger.logger.log('3DI footer found, end: ' + offset);
+ } else {
+ offset -= 3;
+ len = offset;
+ if (len) {
+ //logger.log(`ID3 len: ${len}`);
+ if (!this.hasTimeStamp) {
+ _logger.logger.warn('ID3 tag found, but no timestamp');
+ }
+ this._length = len;
+ this._payload = data.subarray(0, len);
+ }
+ return;
+ }
+ } while (true);
+ }
+
+ _createClass(ID3, [{
+ key: 'readUTF',
+ value: function readUTF(data, start, len) {
+
+ var result = '',
+ offset = start,
+ end = start + len;
+ do {
+ result += String.fromCharCode(data[offset++]);
+ } while (offset < end);
+ return result;
+ }
+ }, {
+ key: '_parseID3Frames',
+ value: function _parseID3Frames(data, offset, endPos) {
+ var tagId, tagLen, tagStart, tagFlags, timestamp;
+ while (offset + 8 <= endPos) {
+ tagId = this.readUTF(data, offset, 4);
+ offset += 4;
+
+ tagLen = data[offset++] << 24 + data[offset++] << 16 + data[offset++] << 8 + data[offset++];
+
+ tagFlags = data[offset++] << 8 + data[offset++];
+
+ tagStart = offset;
+ //logger.log("ID3 tag id:" + tagId);
+ switch (tagId) {
+ case 'PRIV':
+ //logger.log('parse frame:' + Hex.hexDump(data.subarray(offset,endPos)));
+ // owner should be "com.apple.streaming.transportStreamTimestamp"
+ if (this.readUTF(data, offset, 44) === 'com.apple.streaming.transportStreamTimestamp') {
+ offset += 44;
+ // smelling even better ! we found the right descriptor
+ // skip null character (string end) + 3 first bytes
+ offset += 4;
+
+ // timestamp is 33 bit expressed as a big-endian eight-octet number, with the upper 31 bits set to zero.
+ var pts33Bit = data[offset++] & 0x1;
+ this._hasTimeStamp = true;
+
+ timestamp = ((data[offset++] << 23) + (data[offset++] << 15) + (data[offset++] << 7) + data[offset++]) / 45;
+
+ if (pts33Bit) {
+ timestamp += 47721858.84; // 2^32 / 90
+ }
+ timestamp = Math.round(timestamp);
+ _logger.logger.trace('ID3 timestamp found: ' + timestamp);
+ this._timeStamp = timestamp;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }, {
+ key: 'hasTimeStamp',
+ get: function get() {
+ return this._hasTimeStamp;
+ }
+ }, {
+ key: 'timeStamp',
+ get: function get() {
+ return this._timeStamp;
+ }
+ }, {
+ key: 'length',
+ get: function get() {
+ return this._length;
+ }
+ }, {
+ key: 'payload',
+ get: function get() {
+ return this._payload;
+ }
+ }]);
+
+ return ID3;
+ }();
+
+ exports.default = ID3;
+
+ },{"43":43}],23:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
+ * highly optimized TS demuxer:
+ * parse PAT, PMT
+ * extract PES packet from audio and video PIDs
+ * extract AVC/H264 NAL units and AAC/ADTS samples from PES packet
+ * trigger the remuxer upon parsing completion
+ * it also tries to workaround as best as it can audio codec switch (HE-AAC to AAC and vice versa), without having to restart the MediaSource.
+ * it also controls the remuxing process :
+ * upon discontinuity or level switch detection, it will also notifies the remuxer so that it can reset its state.
+ */
+
+ // import Hex from '../utils/hex';
+
+
+ var _adts = _dereq_(17);
+
+ var _adts2 = _interopRequireDefault(_adts);
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _expGolomb = _dereq_(21);
+
+ var _expGolomb2 = _interopRequireDefault(_expGolomb);
+
+ var _logger = _dereq_(43);
+
+ var _errors = _dereq_(24);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var TSDemuxer = function () {
+ function TSDemuxer(observer, id, remuxerClass, config) {
+ _classCallCheck(this, TSDemuxer);
+
+ this.observer = observer;
+ this.id = id;
+ this.remuxerClass = remuxerClass;
+ this.config = config;
+ this.lastCC = 0;
+ this.remuxer = new this.remuxerClass(observer, id, config);
+ }
+
+ _createClass(TSDemuxer, [{
+ key: 'switchLevel',
+ value: function switchLevel() {
+ this.pmtParsed = false;
+ this._pmtId = -1;
+ this._avcTrack = { container: 'video/mp2t', type: 'video', id: -1, sequenceNumber: 0, samples: [], len: 0, dropped: 0 };
+ this._aacTrack = { container: 'video/mp2t', type: 'audio', id: -1, sequenceNumber: 0, samples: [], len: 0 };
+ this._id3Track = { type: 'id3', id: -1, sequenceNumber: 0, samples: [], len: 0 };
+ this._txtTrack = { type: 'text', id: -1, sequenceNumber: 0, samples: [], len: 0 };
+ // flush any partial content
+ this.aacOverFlow = null;
+ this.aacLastPTS = null;
+ this.avcSample = null;
+ this.remuxer.switchLevel();
+ }
+ }, {
+ key: 'insertDiscontinuity',
+ value: function insertDiscontinuity() {
+ this.switchLevel();
+ this.remuxer.insertDiscontinuity();
+ }
+
+ // feed incoming data to the front of the parsing pipeline
+
+ }, {
+ key: 'push',
+ value: function push(data, audioCodec, videoCodec, timeOffset, cc, level, sn, duration, accurateTimeOffset) {
+ var start,
+ len = data.length,
+ stt,
+ pid,
+ atf,
+ offset,
+ pes,
+ codecsOnly = this.remuxer.passthrough,
+ unknownPIDs = false;
+
+ this.audioCodec = audioCodec;
+ this.videoCodec = videoCodec;
+ this._duration = duration;
+ this.contiguous = false;
+ this.accurateTimeOffset = accurateTimeOffset;
+ if (cc !== this.lastCC) {
+ _logger.logger.log('discontinuity detected');
+ this.insertDiscontinuity();
+ this.lastCC = cc;
+ }
+ if (level !== this.lastLevel) {
+ _logger.logger.log('level switch detected');
+ this.switchLevel();
+ this.lastLevel = level;
+ } else if (sn === this.lastSN + 1) {
+ this.contiguous = true;
+ }
+ this.lastSN = sn;
+
+ var pmtParsed = this.pmtParsed,
+ avcTrack = this._avcTrack,
+ aacTrack = this._aacTrack,
+ id3Track = this._id3Track,
+ avcId = avcTrack.id,
+ aacId = aacTrack.id,
+ id3Id = id3Track.id,
+ pmtId = this._pmtId,
+ avcData = avcTrack.pesData,
+ aacData = aacTrack.pesData,
+ id3Data = id3Track.pesData,
+ parsePAT = this._parsePAT,
+ parsePMT = this._parsePMT,
+ parsePES = this._parsePES,
+ parseAVCPES = this._parseAVCPES.bind(this),
+ parseAACPES = this._parseAACPES.bind(this),
+ parseID3PES = this._parseID3PES.bind(this);
+
+ // don't parse last TS packet if incomplete
+ len -= len % 188;
+ // loop through TS packets
+ for (start = 0; start < len; start += 188) {
+ if (data[start] === 0x47) {
+ stt = !!(data[start + 1] & 0x40);
+ // pid is a 13-bit field starting at the last bit of TS[1]
+ pid = ((data[start + 1] & 0x1f) << 8) + data[start + 2];
+ atf = (data[start + 3] & 0x30) >> 4;
+ // if an adaption field is present, its length is specified by the fifth byte of the TS packet header.
+ if (atf > 1) {
+ offset = start + 5 + data[start + 4];
+ // continue if there is only adaptation field
+ if (offset === start + 188) {
+ continue;
+ }
+ } else {
+ offset = start + 4;
+ }
+ switch (pid) {
+ case avcId:
+ if (stt) {
+ if (avcData && (pes = parsePES(avcData))) {
+ parseAVCPES(pes, false);
+ if (codecsOnly) {
+ // if we have video codec info AND
+ // if audio PID is undefined OR if we have audio codec info,
+ // we have all codec info !
+ if (avcTrack.codec && (aacId === -1 || aacTrack.codec)) {
+ this.remux(level, sn, data, timeOffset);
+ return;
+ }
+ }
+ }
+ avcData = { data: [], size: 0 };
+ }
+ if (avcData) {
+ avcData.data.push(data.subarray(offset, start + 188));
+ avcData.size += start + 188 - offset;
+ }
+ break;
+ case aacId:
+ if (stt) {
+ if (aacData && (pes = parsePES(aacData))) {
+ parseAACPES(pes);
+ if (codecsOnly) {
+ // here we now that we have audio codec info
+ // if video PID is undefined OR if we have video codec info,
+ // we have all codec infos !
+ if (aacTrack.codec && (avcId === -1 || avcTrack.codec)) {
+ this.remux(level, sn, data, timeOffset);
+ return;
+ }
+ }
+ }
+ aacData = { data: [], size: 0 };
+ }
+ if (aacData) {
+ aacData.data.push(data.subarray(offset, start + 188));
+ aacData.size += start + 188 - offset;
+ }
+ break;
+ case id3Id:
+ if (stt) {
+ if (id3Data && (pes = parsePES(id3Data))) {
+ parseID3PES(pes);
+ }
+ id3Data = { data: [], size: 0 };
+ }
+ if (id3Data) {
+ id3Data.data.push(data.subarray(offset, start + 188));
+ id3Data.size += start + 188 - offset;
+ }
+ break;
+ case 0:
+ if (stt) {
+ offset += data[offset] + 1;
+ }
+ pmtId = this._pmtId = parsePAT(data, offset);
+ break;
+ case pmtId:
+ if (stt) {
+ offset += data[offset] + 1;
+ }
+ var parsedPIDs = parsePMT(data, offset);
+ avcId = avcTrack.id = parsedPIDs.avc;
+ aacId = aacTrack.id = parsedPIDs.aac;
+ id3Id = id3Track.id = parsedPIDs.id3;
+ if (unknownPIDs && !pmtParsed) {
+ _logger.logger.log('reparse from beginning');
+ unknownPIDs = false;
+ // we set it to -188, the += 188 in the for loop will reset start to 0
+ start = -188;
+ }
+ pmtParsed = this.pmtParsed = true;
+ break;
+ case 17:
+ case 0x1fff:
+ break;
+ default:
+ unknownPIDs = true;
+ break;
+ }
+ } else {
+ this.observer.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, id: this.id, details: _errors.ErrorDetails.FRAG_PARSING_ERROR, fatal: false, reason: 'TS packet did not start with 0x47' });
+ }
+ }
+ // try to parse last PES packets
+ if (avcData && (pes = parsePES(avcData))) {
+ parseAVCPES(pes, true);
+ avcTrack.pesData = null;
+ } else {
+ // either avcData null or PES truncated, keep it for next frag parsing
+ avcTrack.pesData = avcData;
+ }
+
+ if (aacData && (pes = parsePES(aacData))) {
+ parseAACPES(pes);
+ aacTrack.pesData = null;
+ } else {
+ if (aacData && aacData.size) {
+ _logger.logger.log('last AAC PES packet truncated,might overlap between fragments');
+ }
+ // either aacData null or PES truncated, keep it for next frag parsing
+ aacTrack.pesData = aacData;
+ }
+
+ if (id3Data && (pes = parsePES(id3Data))) {
+ parseID3PES(pes);
+ id3Track.pesData = null;
+ } else {
+ // either id3Data null or PES truncated, keep it for next frag parsing
+ id3Track.pesData = id3Data;
+ }
+ this.remux(level, sn, null, timeOffset);
+ }
+ }, {
+ key: 'remux',
+ value: function remux(level, sn, data, timeOffset) {
+ var avcTrack = this._avcTrack,
+ samples = avcTrack.samples;
+
+ // compute total/avc sample length and nb of NAL units
+ var trackData = samples.reduce(function (prevSampleData, curSample) {
+ var sampleData = curSample.units.units.reduce(function (prevUnitData, curUnit) {
+ return {
+ len: prevUnitData.len + curUnit.data.length,
+ nbNalu: prevUnitData.nbNalu + 1
+ };
+ }, { len: 0, nbNalu: 0 });
+ curSample.length = sampleData.len;
+ return {
+ len: prevSampleData.len + sampleData.len,
+ nbNalu: prevSampleData.nbNalu + sampleData.nbNalu
+ };
+ }, { len: 0, nbNalu: 0 });
+ avcTrack.len = trackData.len;
+ avcTrack.nbNalu = trackData.nbNalu;
+ this.remuxer.remux(level, sn, this._aacTrack, this._avcTrack, this._id3Track, this._txtTrack, timeOffset, this.contiguous, this.accurateTimeOffset, data);
+ }
+ }, {
+ key: 'destroy',
+ value: function destroy() {
+ this.switchLevel();
+ this._initPTS = this._initDTS = undefined;
+ this._duration = 0;
+ }
+ }, {
+ key: '_parsePAT',
+ value: function _parsePAT(data, offset) {
+ // skip the PSI header and parse the first PMT entry
+ return (data[offset + 10] & 0x1F) << 8 | data[offset + 11];
+ //logger.log('PMT PID:' + this._pmtId);
+ }
+ }, {
+ key: '_parsePMT',
+ value: function _parsePMT(data, offset) {
+ var sectionLength,
+ tableEnd,
+ programInfoLength,
+ pid,
+ result = { aac: -1, avc: -1, id3: -1 };
+ sectionLength = (data[offset + 1] & 0x0f) << 8 | data[offset + 2];
+ tableEnd = offset + 3 + sectionLength - 4;
+ // to determine where the table is, we have to figure out how
+ // long the program info descriptors are
+ programInfoLength = (data[offset + 10] & 0x0f) << 8 | data[offset + 11];
+ // advance the offset to the first entry in the mapping table
+ offset += 12 + programInfoLength;
+ while (offset < tableEnd) {
+ pid = (data[offset + 1] & 0x1F) << 8 | data[offset + 2];
+ switch (data[offset]) {
+ // ISO/IEC 13818-7 ADTS AAC (MPEG-2 lower bit-rate audio)
+ case 0x0f:
+ //logger.log('AAC PID:' + pid);
+ if (result.aac === -1) {
+ result.aac = pid;
+ }
+ break;
+ // Packetized metadata (ID3)
+ case 0x15:
+ //logger.log('ID3 PID:' + pid);
+ if (result.id3 === -1) {
+ result.id3 = pid;
+ }
+ break;
+ // ITU-T Rec. H.264 and ISO/IEC 14496-10 (lower bit-rate video)
+ case 0x1b:
+ //logger.log('AVC PID:' + pid);
+ if (result.avc === -1) {
+ result.avc = pid;
+ }
+ break;
+ case 0x24:
+ _logger.logger.warn('HEVC stream type found, not supported for now');
+ break;
+ default:
+ _logger.logger.log('unkown stream type:' + data[offset]);
+ break;
+ }
+ // move to the next table entry
+ // skip past the elementary stream descriptors, if present
+ offset += ((data[offset + 3] & 0x0F) << 8 | data[offset + 4]) + 5;
+ }
+ return result;
+ }
+ }, {
+ key: '_parsePES',
+ value: function _parsePES(stream) {
+ var i = 0,
+ frag,
+ pesFlags,
+ pesPrefix,
+ pesLen,
+ pesHdrLen,
+ pesData,
+ pesPts,
+ pesDts,
+ payloadStartOffset,
+ data = stream.data;
+ // safety check
+ if (!stream || stream.size === 0) {
+ return null;
+ }
+
+ // we might need up to 19 bytes to read PES header
+ // if first chunk of data is less than 19 bytes, let's merge it with following ones until we get 19 bytes
+ // usually only one merge is needed (and this is rare ...)
+ while (data[0].length < 19 && data.length > 1) {
+ var newData = new Uint8Array(data[0].length + data[1].length);
+ newData.set(data[0]);
+ newData.set(data[1], data[0].length);
+ data[0] = newData;
+ data.splice(1, 1);
+ }
+ //retrieve PTS/DTS from first fragment
+ frag = data[0];
+ pesPrefix = (frag[0] << 16) + (frag[1] << 8) + frag[2];
+ if (pesPrefix === 1) {
+ pesLen = (frag[4] << 8) + frag[5];
+ // if PES len is not zero and not matching with total len, stop parsing. PES might be truncated
+ // minus 6 : PES header size
+ if (pesLen && pesLen !== stream.size - 6) {
+ return null;
+ }
+ pesFlags = frag[7];
+ if (pesFlags & 0xC0) {
+ /* PES header described here : http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
+ as PTS / DTS is 33 bit we cannot use bitwise operator in JS,
+ as Bitwise operators treat their operands as a sequence of 32 bits */
+ pesPts = (frag[9] & 0x0E) * 536870912 + // 1 << 29
+ (frag[10] & 0xFF) * 4194304 + // 1 << 22
+ (frag[11] & 0xFE) * 16384 + // 1 << 14
+ (frag[12] & 0xFF) * 128 + // 1 << 7
+ (frag[13] & 0xFE) / 2;
+ // check if greater than 2^32 -1
+ if (pesPts > 4294967295) {
+ // decrement 2^33
+ pesPts -= 8589934592;
+ }
+ if (pesFlags & 0x40) {
+ pesDts = (frag[14] & 0x0E) * 536870912 + // 1 << 29
+ (frag[15] & 0xFF) * 4194304 + // 1 << 22
+ (frag[16] & 0xFE) * 16384 + // 1 << 14
+ (frag[17] & 0xFF) * 128 + // 1 << 7
+ (frag[18] & 0xFE) / 2;
+ // check if greater than 2^32 -1
+ if (pesDts > 4294967295) {
+ // decrement 2^33
+ pesDts -= 8589934592;
+ }
+ } else {
+ pesDts = pesPts;
+ }
+ }
+ pesHdrLen = frag[8];
+ // 9 bytes : 6 bytes for PES header + 3 bytes for PES extension
+ payloadStartOffset = pesHdrLen + 9;
+
+ stream.size -= payloadStartOffset;
+ //reassemble PES packet
+ pesData = new Uint8Array(stream.size);
+ while (data.length) {
+ frag = data.shift();
+ var len = frag.byteLength;
+ if (payloadStartOffset) {
+ if (payloadStartOffset > len) {
+ // trim full frag if PES header bigger than frag
+ payloadStartOffset -= len;
+ continue;
+ } else {
+ // trim partial frag if PES header smaller than frag
+ frag = frag.subarray(payloadStartOffset);
+ len -= payloadStartOffset;
+ payloadStartOffset = 0;
+ }
+ }
+ pesData.set(frag, i);
+ i += len;
+ }
+ if (pesLen) {
+ // payload size : remove PES header + PES extension
+ pesLen -= pesHdrLen + 3;
+ }
+ return { data: pesData, pts: pesPts, dts: pesDts, len: pesLen };
+ } else {
+ return null;
+ }
+ }
+ }, {
+ key: 'pushAccesUnit',
+ value: function pushAccesUnit(avcSample, avcTrack) {
+ if (avcSample.units.units.length) {
+ // only push AVC sample if starting with a keyframe is not mandatory OR
+ // if keyframe already found in this fragment OR
+ // keyframe found in last fragment (track.sps) AND
+ // samples already appended (we already found a keyframe in this fragment) OR fragment is contiguous
+ if (!this.config.forceKeyFrameOnDiscontinuity || avcSample.key === true || avcTrack.sps && (avcTrack.samples.length || this.contiguous)) {
+ avcTrack.samples.push(avcSample);
+ } else {
+ // dropped samples, track it
+ avcTrack.dropped++;
+ }
+ }
+ if (avcSample.debug.length) {
+ _logger.logger.log(avcSample.pts + '/' + avcSample.dts + ':' + avcSample.debug + ',' + avcSample.units.length);
+ }
+ }
+ }, {
+ key: '_parseAVCPES',
+ value: function _parseAVCPES(pes, last) {
+ var _this = this;
+
+ //logger.log('parse new PES');
+ var track = this._avcTrack,
+ units = this._parseAVCNALu(pes.data),
+ debug = false,
+ expGolombDecoder,
+ avcSample = this.avcSample,
+ push,
+ i;
+ //free pes.data to save up some memory
+ pes.data = null;
+
+ units.forEach(function (unit) {
+ switch (unit.type) {
+ //NDR
+ case 1:
+ push = true;
+ if (debug && avcSample) {
+ avcSample.debug += 'NDR ';
+ }
+ break;
+ //IDR
+ case 5:
+ push = true;
+ // handle PES not starting with AUD
+ if (!avcSample) {
+ avcSample = _this.avcSample = _this._createAVCSample(true, pes.pts, pes.dts, '');
+ }
+ if (debug) {
+ avcSample.debug += 'IDR ';
+ }
+ avcSample.key = true;
+ break;
+ //SEI
+ case 6:
+ push = true;
+ if (debug && avcSample) {
+ avcSample.debug += 'SEI ';
+ }
+ expGolombDecoder = new _expGolomb2.default(_this.discardEPB(unit.data));
+
+ // skip frameType
+ expGolombDecoder.readUByte();
+
+ var payloadType = 0;
+ var payloadSize = 0;
+ var endOfCaptions = false;
+ var b = 0;
+
+ while (!endOfCaptions && expGolombDecoder.bytesAvailable > 1) {
+ payloadType = 0;
+ do {
+ b = expGolombDecoder.readUByte();
+ payloadType += b;
+ } while (b === 0xFF);
+
+ // Parse payload size.
+ payloadSize = 0;
+ do {
+ b = expGolombDecoder.readUByte();
+ payloadSize += b;
+ } while (b === 0xFF);
+
+ // TODO: there can be more than one payload in an SEI packet...
+ // TODO: need to read type and size in a while loop to get them all
+ if (payloadType === 4 && expGolombDecoder.bytesAvailable !== 0) {
+
+ endOfCaptions = true;
+
+ var countryCode = expGolombDecoder.readUByte();
+
+ if (countryCode === 181) {
+ var providerCode = expGolombDecoder.readUShort();
+
+ if (providerCode === 49) {
+ var userStructure = expGolombDecoder.readUInt();
+
+ if (userStructure === 0x47413934) {
+ var userDataType = expGolombDecoder.readUByte();
+
+ // Raw CEA-608 bytes wrapped in CEA-708 packet
+ if (userDataType === 3) {
+ var firstByte = expGolombDecoder.readUByte();
+ var secondByte = expGolombDecoder.readUByte();
+
+ var totalCCs = 31 & firstByte;
+ var byteArray = [firstByte, secondByte];
+
+ for (i = 0; i < totalCCs; i++) {
+ // 3 bytes per CC
+ byteArray.push(expGolombDecoder.readUByte());
+ byteArray.push(expGolombDecoder.readUByte());
+ byteArray.push(expGolombDecoder.readUByte());
+ }
+
+ _this._insertSampleInOrder(_this._txtTrack.samples, { type: 3, pts: pes.pts, bytes: byteArray });
+ }
+ }
+ }
+ }
+ } else if (payloadSize < expGolombDecoder.bytesAvailable) {
+ for (i = 0; i < payloadSize; i++) {
+ expGolombDecoder.readUByte();
+ }
+ }
+ }
+ break;
+ //SPS
+ case 7:
+ push = true;
+ if (debug && avcSample) {
+ avcSample.debug += 'SPS ';
+ }
+ if (!track.sps) {
+ expGolombDecoder = new _expGolomb2.default(unit.data);
+ var config = expGolombDecoder.readSPS();
+ track.width = config.width;
+ track.height = config.height;
+ track.sps = [unit.data];
+ track.duration = _this._duration;
+ var codecarray = unit.data.subarray(1, 4);
+ var codecstring = 'avc1.';
+ for (i = 0; i < 3; i++) {
+ var h = codecarray[i].toString(16);
+ if (h.length < 2) {
+ h = '0' + h;
+ }
+ codecstring += h;
+ }
+ track.codec = codecstring;
+ }
+ break;
+ //PPS
+ case 8:
+ push = true;
+ if (debug && avcSample) {
+ avcSample.debug += 'PPS ';
+ }
+ if (!track.pps) {
+ track.pps = [unit.data];
+ }
+ break;
+ // AUD
+ case 9:
+ push = false;
+ if (avcSample) {
+ _this.pushAccesUnit(avcSample, track);
+ }
+ avcSample = _this.avcSample = _this._createAVCSample(false, pes.pts, pes.dts, debug ? 'AUD ' : '');
+ break;
+ // Filler Data
+ case 12:
+ push = false;
+ break;
+ default:
+ push = false;
+ if (avcSample) {
+ avcSample.debug += 'unknown NAL ' + unit.type + ' ';
+ }
+ break;
+ }
+ if (avcSample && push) {
+ var _units = avcSample.units;
+ _units.units.push(unit);
+ }
+ });
+ // if last PES packet, push samples
+ if (last && avcSample) {
+ this.pushAccesUnit(avcSample, track);
+ this.avcSample = null;
+ }
+ }
+ }, {
+ key: '_createAVCSample',
+ value: function _createAVCSample(key, pts, dts, debug) {
+ return { key: key, pts: pts, dts: dts, units: { units: [], length: 0 }, debug: debug };
+ }
+ }, {
+ key: '_insertSampleInOrder',
+ value: function _insertSampleInOrder(arr, data) {
+ var len = arr.length;
+ if (len > 0) {
+ if (data.pts >= arr[len - 1].pts) {
+ arr.push(data);
+ } else {
+ for (var pos = len - 1; pos >= 0; pos--) {
+ if (data.pts < arr[pos].pts) {
+ arr.splice(pos, 0, data);
+ break;
+ }
+ }
+ }
+ } else {
+ arr.push(data);
+ }
+ }
+ }, {
+ key: '_getLastNalUnit',
+ value: function _getLastNalUnit() {
+ var avcSample = this.avcSample,
+ lastUnit = void 0;
+ // try to fallback to previous sample if current one is empty
+ if (!avcSample || avcSample.units.units.length === 0) {
+ var track = this._avcTrack,
+ samples = track.samples;
+ avcSample = samples[samples.length - 1];
+ }
+ if (avcSample) {
+ var units = avcSample.units.units;
+ lastUnit = units[units.length - 1];
+ }
+ return lastUnit;
+ }
+ }, {
+ key: '_parseAVCNALu',
+ value: function _parseAVCNALu(array) {
+ var i = 0,
+ len = array.byteLength,
+ value,
+ overflow,
+ track = this._avcTrack,
+ state = track.naluState || 0,
+ lastState = state;
+ var units = [],
+ unit,
+ unitType,
+ lastUnitStart = -1,
+ lastUnitType;
+ //logger.log('PES:' + Hex.hexDump(array));
+ while (i < len) {
+ value = array[i++];
+ // finding 3 or 4-byte start codes (00 00 01 OR 00 00 00 01)
+ switch (state) {
+ case 0:
+ if (value === 0) {
+ state = 1;
+ }
+ break;
+ case 1:
+ if (value === 0) {
+ state = 2;
+ } else {
+ state = 0;
+ }
+ break;
+ case 2:
+ case 3:
+ if (value === 0) {
+ state = 3;
+ } else if (value === 1) {
+ if (lastUnitStart >= 0) {
+ unit = { data: array.subarray(lastUnitStart, i - state - 1), type: lastUnitType };
+ //logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
+ units.push(unit);
+ } else {
+ // lastUnitStart is undefined => this is the first start code found in this PES packet
+ // first check if start code delimiter is overlapping between 2 PES packets,
+ // ie it started in last packet (lastState not zero)
+ // and ended at the beginning of this PES packet (i <= 4 - lastState)
+ var lastUnit = this._getLastNalUnit();
+ if (lastUnit) {
+ if (lastState && i <= 4 - lastState) {
+ // start delimiter overlapping between PES packets
+ // strip start delimiter bytes from the end of last NAL unit
+ // check if lastUnit had a state different from zero
+ if (lastUnit.state) {
+ // strip last bytes
+ lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
+ }
+ }
+ // If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
+ overflow = i - state - 1;
+ if (overflow > 0) {
+ //logger.log('first NALU found with overflow:' + overflow);
+ var tmp = new Uint8Array(lastUnit.data.byteLength + overflow);
+ tmp.set(lastUnit.data, 0);
+ tmp.set(array.subarray(0, overflow), lastUnit.data.byteLength);
+ lastUnit.data = tmp;
+ }
+ }
+ }
+ // check if we can read unit type
+ if (i < len) {
+ unitType = array[i] & 0x1f;
+ //logger.log('find NALU @ offset:' + i + ',type:' + unitType);
+ lastUnitStart = i;
+ lastUnitType = unitType;
+ state = 0;
+ } else {
+ // not enough byte to read unit type. let's read it on next PES parsing
+ state = -1;
+ }
+ } else {
+ state = 0;
+ }
+ break;
+ case -1:
+ // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
+ lastUnitStart = 0;
+ // NALu type is value read from offset 0
+ lastUnitType = value & 0x1f;
+ state = 0;
+ break;
+ default:
+ break;
+ }
+ }
+ if (lastUnitStart >= 0 && state >= 0) {
+ unit = { data: array.subarray(lastUnitStart, len), type: lastUnitType, state: state };
+ units.push(unit);
+ //logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
+ }
+ // no NALu found
+ if (units.length === 0) {
+ // append pes.data to previous NAL unit
+ var _lastUnit = this._getLastNalUnit();
+ if (_lastUnit) {
+ var _tmp = new Uint8Array(_lastUnit.data.byteLength + array.byteLength);
+ _tmp.set(_lastUnit.data, 0);
+ _tmp.set(array, _lastUnit.data.byteLength);
+ _lastUnit.data = _tmp;
+ }
+ }
+ track.naluState = state;
+ return units;
+ }
+
+ /**
+ * remove Emulation Prevention bytes from a RBSP
+ */
+
+ }, {
+ key: 'discardEPB',
+ value: function discardEPB(data) {
+ var length = data.byteLength,
+ EPBPositions = [],
+ i = 1,
+ newLength,
+ newData;
+
+ // Find all `Emulation Prevention Bytes`
+ while (i < length - 2) {
+ if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 0x03) {
+ EPBPositions.push(i + 2);
+ i += 2;
+ } else {
+ i++;
+ }
+ }
+
+ // If no Emulation Prevention Bytes were found just return the original
+ // array
+ if (EPBPositions.length === 0) {
+ return data;
+ }
+
+ // Create a new array to hold the NAL unit data
+ newLength = length - EPBPositions.length;
+ newData = new Uint8Array(newLength);
+ var sourceIndex = 0;
+
+ for (i = 0; i < newLength; sourceIndex++, i++) {
+ if (sourceIndex === EPBPositions[0]) {
+ // Skip this byte
+ sourceIndex++;
+ // Remove this position index
+ EPBPositions.shift();
+ }
+ newData[i] = data[sourceIndex];
+ }
+ return newData;
+ }
+ }, {
+ key: '_parseAACPES',
+ value: function _parseAACPES(pes) {
+ var track = this._aacTrack,
+ data = pes.data,
+ pts = pes.pts,
+ startOffset = 0,
+ aacOverFlow = this.aacOverFlow,
+ aacLastPTS = this.aacLastPTS,
+ config,
+ frameLength,
+ frameDuration,
+ frameIndex,
+ offset,
+ headerLength,
+ stamp,
+ len,
+ aacSample;
+ if (aacOverFlow) {
+ var tmp = new Uint8Array(aacOverFlow.byteLength + data.byteLength);
+ tmp.set(aacOverFlow, 0);
+ tmp.set(data, aacOverFlow.byteLength);
+ //logger.log(`AAC: append overflowing ${aacOverFlow.byteLength} bytes to beginning of new PES`);
+ data = tmp;
+ }
+ // look for ADTS header (0xFFFx)
+ for (offset = startOffset, len = data.length; offset < len - 1; offset++) {
+ if (data[offset] === 0xff && (data[offset + 1] & 0xf0) === 0xf0) {
+ break;
+ }
+ }
+ // if ADTS header does not start straight from the beginning of the PES payload, raise an error
+ if (offset) {
+ var reason, fatal;
+ if (offset < len - 1) {
+ reason = 'AAC PES did not start with ADTS header,offset:' + offset;
+ fatal = false;
+ } else {
+ reason = 'no ADTS header found in AAC PES';
+ fatal = true;
+ }
+ _logger.logger.warn('parsing error:' + reason);
+ this.observer.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, id: this.id, details: _errors.ErrorDetails.FRAG_PARSING_ERROR, fatal: fatal, reason: reason });
+ if (fatal) {
+ return;
+ }
+ }
+ if (!track.audiosamplerate) {
+ config = _adts2.default.getAudioConfig(this.observer, data, offset, this.audioCodec);
+ track.config = config.config;
+ track.audiosamplerate = config.samplerate;
+ track.channelCount = config.channelCount;
+ track.codec = config.codec;
+ track.duration = this._duration;
+ _logger.logger.log('parsed codec:' + track.codec + ',rate:' + config.samplerate + ',nb channel:' + config.channelCount);
+ }
+ frameIndex = 0;
+ frameDuration = 1024 * 90000 / track.audiosamplerate;
+
+ // if last AAC frame is overflowing, we should ensure timestamps are contiguous:
+ // first sample PTS should be equal to last sample PTS + frameDuration
+ if (aacOverFlow && aacLastPTS) {
+ var newPTS = aacLastPTS + frameDuration;
+ if (Math.abs(newPTS - pts) > 1) {
+ _logger.logger.log('AAC: align PTS for overlapping frames by ' + Math.round((newPTS - pts) / 90));
+ pts = newPTS;
+ }
+ }
+
+ while (offset + 5 < len) {
+ // The protection skip bit tells us if we have 2 bytes of CRC data at the end of the ADTS header
+ headerLength = !!(data[offset + 1] & 0x01) ? 7 : 9;
+ // retrieve frame size
+ frameLength = (data[offset + 3] & 0x03) << 11 | data[offset + 4] << 3 | (data[offset + 5] & 0xE0) >>> 5;
+ frameLength -= headerLength;
+ //stamp = pes.pts;
+
+ if (frameLength > 0 && offset + headerLength + frameLength <= len) {
+ stamp = pts + frameIndex * frameDuration;
+ //logger.log(`AAC frame, offset/length/total/pts:${offset+headerLength}/${frameLength}/${data.byteLength}/${(stamp/90).toFixed(0)}`);
+ aacSample = { unit: data.subarray(offset + headerLength, offset + headerLength + frameLength), pts: stamp, dts: stamp };
+ track.samples.push(aacSample);
+ track.len += frameLength;
+ offset += frameLength + headerLength;
+ frameIndex++;
+ // look for ADTS header (0xFFFx)
+ for (; offset < len - 1; offset++) {
+ if (data[offset] === 0xff && (data[offset + 1] & 0xf0) === 0xf0) {
+ break;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+ if (offset < len) {
+ aacOverFlow = data.subarray(offset, len);
+ //logger.log(`AAC: overflow detected:${len-offset}`);
+ } else {
+ aacOverFlow = null;
+ }
+ this.aacOverFlow = aacOverFlow;
+ this.aacLastPTS = stamp;
+ }
+ }, {
+ key: '_parseID3PES',
+ value: function _parseID3PES(pes) {
+ this._id3Track.samples.push(pes);
+ }
+ }], [{
+ key: 'probe',
+ value: function probe(data) {
+ // a TS fragment should contain at least 3 TS packets, a PAT, a PMT, and one PID, each starting with 0x47
+ if (data.length >= 3 * 188 && data[0] === 0x47 && data[188] === 0x47 && data[2 * 188] === 0x47) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }]);
+
+ return TSDemuxer;
+ }();
+
+ exports.default = TSDemuxer;
+
+ },{"17":17,"21":21,"24":24,"26":26,"43":43}],24:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+ var ErrorTypes = exports.ErrorTypes = {
+ // Identifier for a network error (loading error / timeout ...)
+ NETWORK_ERROR: 'networkError',
+ // Identifier for a media Error (video/parsing/mediasource error)
+ MEDIA_ERROR: 'mediaError',
+ // Identifier for all other errors
+ OTHER_ERROR: 'otherError'
+ };
+
+ var ErrorDetails = exports.ErrorDetails = {
+ // Identifier for a manifest load error - data: { url : faulty URL, response : { code: error code, text: error text }}
+ MANIFEST_LOAD_ERROR: 'manifestLoadError',
+ // Identifier for a manifest load timeout - data: { url : faulty URL, response : { code: error code, text: error text }}
+ MANIFEST_LOAD_TIMEOUT: 'manifestLoadTimeOut',
+ // Identifier for a manifest parsing error - data: { url : faulty URL, reason : error reason}
+ MANIFEST_PARSING_ERROR: 'manifestParsingError',
+ // Identifier for a manifest with only incompatible codecs error - data: { url : faulty URL, reason : error reason}
+ MANIFEST_INCOMPATIBLE_CODECS_ERROR: 'manifestIncompatibleCodecsError',
+ // Identifier for a level load error - data: { url : faulty URL, response : { code: error code, text: error text }}
+ LEVEL_LOAD_ERROR: 'levelLoadError',
+ // Identifier for a level load timeout - data: { url : faulty URL, response : { code: error code, text: error text }}
+ LEVEL_LOAD_TIMEOUT: 'levelLoadTimeOut',
+ // Identifier for a level switch error - data: { level : faulty level Id, event : error description}
+ LEVEL_SWITCH_ERROR: 'levelSwitchError',
+ // Identifier for an audio track load error - data: { url : faulty URL, response : { code: error code, text: error text }}
+ AUDIO_TRACK_LOAD_ERROR: 'audioTrackLoadError',
+ // Identifier for an audio track load timeout - data: { url : faulty URL, response : { code: error code, text: error text }}
+ AUDIO_TRACK_LOAD_TIMEOUT: 'audioTrackLoadTimeOut',
+ // Identifier for fragment load error - data: { frag : fragment object, response : { code: error code, text: error text }}
+ FRAG_LOAD_ERROR: 'fragLoadError',
+ // Identifier for fragment loop loading error - data: { frag : fragment object}
+ FRAG_LOOP_LOADING_ERROR: 'fragLoopLoadingError',
+ // Identifier for fragment load timeout error - data: { frag : fragment object}
+ FRAG_LOAD_TIMEOUT: 'fragLoadTimeOut',
+ // Identifier for a fragment decryption error event - data: parsing error description
+ FRAG_DECRYPT_ERROR: 'fragDecryptError',
+ // Identifier for a fragment parsing error event - data: parsing error description
+ FRAG_PARSING_ERROR: 'fragParsingError',
+ // Identifier for decrypt key load error - data: { frag : fragment object, response : { code: error code, text: error text }}
+ KEY_LOAD_ERROR: 'keyLoadError',
+ // Identifier for decrypt key load timeout error - data: { frag : fragment object}
+ KEY_LOAD_TIMEOUT: 'keyLoadTimeOut',
+ // Triggered when an exception occurs while adding a sourceBuffer to MediaSource - data : { err : exception , mimeType : mimeType }
+ BUFFER_ADD_CODEC_ERROR: 'bufferAddCodecError',
+ // Identifier for a buffer append error - data: append error description
+ BUFFER_APPEND_ERROR: 'bufferAppendError',
+ // Identifier for a buffer appending error event - data: appending error description
+ BUFFER_APPENDING_ERROR: 'bufferAppendingError',
+ // Identifier for a buffer stalled error event
+ BUFFER_STALLED_ERROR: 'bufferStalledError',
+ // Identifier for a buffer full event
+ BUFFER_FULL_ERROR: 'bufferFullError',
+ // Identifier for a buffer seek over hole event
+ BUFFER_SEEK_OVER_HOLE: 'bufferSeekOverHole',
+ // Identifier for an internal exception happening inside hls.js while handling an event
+ INTERNAL_EXCEPTION: 'internalException'
+ };
+
+ },{}],25:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /*
+ *
+ * All objects in the event handling chain should inherit from this class
+ *
+ */
+
+ var _logger = _dereq_(43);
+
+ var _errors = _dereq_(24);
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var EventHandler = function () {
+ function EventHandler(hls) {
+ _classCallCheck(this, EventHandler);
+
+ this.hls = hls;
+ this.onEvent = this.onEvent.bind(this);
+
+ for (var _len = arguments.length, events = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ events[_key - 1] = arguments[_key];
+ }
+
+ this.handledEvents = events;
+ this.useGenericHandler = true;
+
+ this.registerListeners();
+ }
+
+ _createClass(EventHandler, [{
+ key: 'destroy',
+ value: function destroy() {
+ this.unregisterListeners();
+ }
+ }, {
+ key: 'isEventHandler',
+ value: function isEventHandler() {
+ return _typeof(this.handledEvents) === 'object' && this.handledEvents.length && typeof this.onEvent === 'function';
+ }
+ }, {
+ key: 'registerListeners',
+ value: function registerListeners() {
+ if (this.isEventHandler()) {
+ this.handledEvents.forEach(function (event) {
+ if (event === 'hlsEventGeneric') {
+ throw new Error('Forbidden event name: ' + event);
+ }
+ this.hls.on(event, this.onEvent);
+ }.bind(this));
+ }
+ }
+ }, {
+ key: 'unregisterListeners',
+ value: function unregisterListeners() {
+ if (this.isEventHandler()) {
+ this.handledEvents.forEach(function (event) {
+ this.hls.off(event, this.onEvent);
+ }.bind(this));
+ }
+ }
+
+ /**
+ * arguments: event (string), data (any)
+ */
+
+ }, {
+ key: 'onEvent',
+ value: function onEvent(event, data) {
+ this.onEventGeneric(event, data);
+ }
+ }, {
+ key: 'onEventGeneric',
+ value: function onEventGeneric(event, data) {
+ var eventToFunction = function eventToFunction(event, data) {
+ var funcName = 'on' + event.replace('hls', '');
+ if (typeof this[funcName] !== 'function') {
+ throw new Error('Event ' + event + ' has no generic handler in this ' + this.constructor.name + ' class (tried ' + funcName + ')');
+ }
+ return this[funcName].bind(this, data);
+ };
+ try {
+ eventToFunction.call(this, event, data).call();
+ } catch (err) {
+ _logger.logger.error('internal error happened while processing ' + event + ':' + err.message);
+ this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.OTHER_ERROR, details: _errors.ErrorDetails.INTERNAL_EXCEPTION, fatal: false, event: event, err: err });
+ }
+ }
+ }]);
+
+ return EventHandler;
+ }();
+
+ exports.default = EventHandler;
+
+ },{"24":24,"26":26,"43":43}],26:[function(_dereq_,module,exports){
+ 'use strict';
+
+ module.exports = {
+ // fired before MediaSource is attaching to media element - data: { media }
+ MEDIA_ATTACHING: 'hlsMediaAttaching',
+ // fired when MediaSource has been succesfully attached to media element - data: { }
+ MEDIA_ATTACHED: 'hlsMediaAttached',
+ // fired before detaching MediaSource from media element - data: { }
+ MEDIA_DETACHING: 'hlsMediaDetaching',
+ // fired when MediaSource has been detached from media element - data: { }
+ MEDIA_DETACHED: 'hlsMediaDetached',
+ // fired when we buffer is going to be resetted
+ BUFFER_RESET: 'hlsBufferReset',
+ // fired when we know about the codecs that we need buffers for to push into - data: {tracks : { container, codec, levelCodec, initSegment, metadata }}
+ BUFFER_CODECS: 'hlsBufferCodecs',
+ // fired when sourcebuffers have been created data: { tracks : tracks}
+ BUFFER_CREATED: 'hlsBufferCreated',
+ // fired when we append a segment to the buffer - data: { segment: segment object }
+ BUFFER_APPENDING: 'hlsBufferAppending',
+ // fired when we are done with appending a media segment to the buffer data : { parent : segment parent that triggered BUFFER_APPENDING }
+ BUFFER_APPENDED: 'hlsBufferAppended',
+ // fired when the stream is finished and we want to notify the media buffer that there will be no more data
+ BUFFER_EOS: 'hlsBufferEos',
+ // fired when the media buffer should be flushed - data {startOffset, endOffset}
+ BUFFER_FLUSHING: 'hlsBufferFlushing',
+ // fired when the media has been flushed
+ BUFFER_FLUSHED: 'hlsBufferFlushed',
+ // fired to signal that a manifest loading starts - data: { url : manifestURL}
+ MANIFEST_LOADING: 'hlsManifestLoading',
+ // fired after manifest has been loaded - data: { levels : [available quality levels] , audioTracks : [ available audio tracks], url : manifestURL, stats : { trequest, tfirst, tload, mtime}}
+ MANIFEST_LOADED: 'hlsManifestLoaded',
+ // fired after manifest has been parsed - data: { levels : [available quality levels] , firstLevel : index of first quality level appearing in Manifest}
+ MANIFEST_PARSED: 'hlsManifestParsed',
+ // fired when a level playlist loading starts - data: { url : level URL level : id of level being loaded}
+ LEVEL_LOADING: 'hlsLevelLoading',
+ // fired when a level playlist loading finishes - data: { details : levelDetails object, level : id of loaded level, stats : { trequest, tfirst, tload, mtime} }
+ LEVEL_LOADED: 'hlsLevelLoaded',
+ // fired when a level's details have been updated based on previous details, after it has been loaded. - data: { details : levelDetails object, level : id of updated level }
+ LEVEL_UPDATED: 'hlsLevelUpdated',
+ // fired when a level's PTS information has been updated after parsing a fragment - data: { details : levelDetails object, level : id of updated level, drift: PTS drift observed when parsing last fragment }
+ LEVEL_PTS_UPDATED: 'hlsLevelPtsUpdated',
+ // fired when a level switch is requested - data: { level : id of new level }
+ LEVEL_SWITCH: 'hlsLevelSwitch',
+ // fired to notify that audio track lists has been updated data: { audioTracks : audioTracks}
+ AUDIO_TRACKS_UPDATED: 'hlsAudioTracksUpdated',
+ // fired when an audio track switch occurs - data: { id : audio track id}
+ AUDIO_TRACK_SWITCH: 'hlsAudioTrackSwitch',
+ // fired when an audio track loading starts - data: { url : audio track URL id : audio track id}
+ AUDIO_TRACK_LOADING: 'hlsAudioTrackLoading',
+ // fired when an audio track loading finishes - data: { details : levelDetails object, id : audio track id, stats : { trequest, tfirst, tload, mtime} }
+ AUDIO_TRACK_LOADED: 'hlsAudioTrackLoaded',
+ // fired when a fragment loading starts - data: { frag : fragment object}
+ FRAG_LOADING: 'hlsFragLoading',
+ // fired when a fragment loading is progressing - data: { frag : fragment object, { trequest, tfirst, loaded}}
+ FRAG_LOAD_PROGRESS: 'hlsFragLoadProgress',
+ // Identifier for fragment load aborting for emergency switch down - data: {frag : fragment object}
+ FRAG_LOAD_EMERGENCY_ABORTED: 'hlsFragLoadEmergencyAborted',
+ // fired when a fragment loading is completed - data: { frag : fragment object, payload : fragment payload, stats : { trequest, tfirst, tload, length}}
+ FRAG_LOADED: 'hlsFragLoaded',
+ // fired when Init Segment has been extracted from fragment - data: { id : demuxer id, level : levelId, sn : sequence number, moov : moov MP4 box, codecs : codecs found while parsing fragment}
+ FRAG_PARSING_INIT_SEGMENT: 'hlsFragParsingInitSegment',
+ // fired when parsing sei text is completed - data: { id : demuxer id, , level : levelId, sn : sequence number, samples : [ sei samples pes ] }
+ FRAG_PARSING_USERDATA: 'hlsFragParsingUserdata',
+ // fired when parsing id3 is completed - data: { id : demuxer id, , level : levelId, sn : sequence number, samples : [ id3 samples pes ] }
+ FRAG_PARSING_METADATA: 'hlsFragParsingMetadata',
+ // fired when data have been extracted from fragment - data: { id : demuxer id, level : levelId, sn : sequence number, data1 : moof MP4 box or TS fragments, data2 : mdat MP4 box or null}
+ FRAG_PARSING_DATA: 'hlsFragParsingData',
+ // fired when fragment parsing is completed - data: { id : demuxer id; level : levelId, sn : sequence number, }
+ FRAG_PARSED: 'hlsFragParsed',
+ // fired when fragment remuxed MP4 boxes have all been appended into SourceBuffer - data: { id : demuxer id,frag : fragment object, stats : { trequest, tfirst, tload, tparsed, tbuffered, length} }
+ FRAG_BUFFERED: 'hlsFragBuffered',
+ // fired when fragment matching with current media position is changing - data : { id : demuxer id, frag : fragment object }
+ FRAG_CHANGED: 'hlsFragChanged',
+ // Identifier for a FPS drop event - data: {curentDropped, currentDecoded, totalDroppedFrames}
+ FPS_DROP: 'hlsFpsDrop',
+ //triggered when FPS drop triggers auto level capping - data: {level, droppedlevel}
+ FPS_DROP_LEVEL_CAPPING: 'hlsFpsDropLevelCapping',
+ // Identifier for an error event - data: { type : error type, details : error details, fatal : if true, hls.js cannot/will not try to recover, if false, hls.js will try to recover,other error specific data}
+ ERROR: 'hlsError',
+ // fired when hls.js instance starts destroying. Different from MEDIA_DETACHED as one could want to detach and reattach a media to the instance of hls.js to handle mid-rolls for example
+ DESTROYING: 'hlsDestroying',
+ // fired when a decrypt key loading starts - data: { frag : fragment object}
+ KEY_LOADING: 'hlsKeyLoading',
+ // fired when a decrypt key loading is completed - data: { frag : fragment object, payload : key payload, stats : { trequest, tfirst, tload, length}}
+ KEY_LOADED: 'hlsKeyLoaded',
+ // fired upon stream controller state transitions - data: {previousState, nextState}
+ STREAM_STATE_TRANSITION: 'hlsStreamStateTransition'
+ };
+
+ },{}],27:[function(_dereq_,module,exports){
+ "use strict";
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ /**
+ * AAC helper
+ */
+
+ var AAC = function () {
+ function AAC() {
+ _classCallCheck(this, AAC);
+ }
+
+ _createClass(AAC, null, [{
+ key: "getSilentFrame",
+ value: function getSilentFrame(channelCount) {
+ if (channelCount === 1) {
+ return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x23, 0x80]);
+ } else if (channelCount === 2) {
+ return new Uint8Array([0x21, 0x00, 0x49, 0x90, 0x02, 0x19, 0x00, 0x23, 0x80]);
+ } else if (channelCount === 3) {
+ return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x8e]);
+ } else if (channelCount === 4) {
+ return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x80, 0x2c, 0x80, 0x08, 0x02, 0x38]);
+ } else if (channelCount === 5) {
+ return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x82, 0x30, 0x04, 0x99, 0x00, 0x21, 0x90, 0x02, 0x38]);
+ } else if (channelCount === 6) {
+ return new Uint8Array([0x00, 0xc8, 0x00, 0x80, 0x20, 0x84, 0x01, 0x26, 0x40, 0x08, 0x64, 0x00, 0x82, 0x30, 0x04, 0x99, 0x00, 0x21, 0x90, 0x02, 0x00, 0xb2, 0x00, 0x20, 0x08, 0xe0]);
+ }
+ return null;
+ }
+ }]);
+
+ return AAC;
+ }();
+
+ exports.default = AAC;
+
+ },{}],28:[function(_dereq_,module,exports){
+ "use strict";
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ /**
+ * Buffer Helper class, providing methods dealing buffer length retrieval
+ */
+
+ var BufferHelper = function () {
+ function BufferHelper() {
+ _classCallCheck(this, BufferHelper);
+ }
+
+ _createClass(BufferHelper, null, [{
+ key: "isBuffered",
+ value: function isBuffered(media, position) {
+ if (media) {
+ var buffered = media.buffered;
+ for (var i = 0; i < buffered.length; i++) {
+ if (position >= buffered.start(i) && position <= buffered.end(i)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ }, {
+ key: "bufferInfo",
+ value: function bufferInfo(media, pos, maxHoleDuration) {
+ if (media) {
+ var vbuffered = media.buffered,
+ buffered = [],
+ i;
+ for (i = 0; i < vbuffered.length; i++) {
+ buffered.push({ start: vbuffered.start(i), end: vbuffered.end(i) });
+ }
+ return this.bufferedInfo(buffered, pos, maxHoleDuration);
+ } else {
+ return { len: 0, start: 0, end: 0, nextStart: undefined };
+ }
+ }
+ }, {
+ key: "bufferedInfo",
+ value: function bufferedInfo(buffered, pos, maxHoleDuration) {
+ var buffered2 = [],
+
+ // bufferStart and bufferEnd are buffer boundaries around current video position
+ bufferLen,
+ bufferStart,
+ bufferEnd,
+ bufferStartNext,
+ i;
+ // sort on buffer.start/smaller end (IE does not always return sorted buffered range)
+ buffered.sort(function (a, b) {
+ var diff = a.start - b.start;
+ if (diff) {
+ return diff;
+ } else {
+ return b.end - a.end;
+ }
+ });
+ // there might be some small holes between buffer time range
+ // consider that holes smaller than maxHoleDuration are irrelevant and build another
+ // buffer time range representations that discards those holes
+ for (i = 0; i < buffered.length; i++) {
+ var buf2len = buffered2.length;
+ if (buf2len) {
+ var buf2end = buffered2[buf2len - 1].end;
+ // if small hole (value between 0 or maxHoleDuration ) or overlapping (negative)
+ if (buffered[i].start - buf2end < maxHoleDuration) {
+ // merge overlapping time ranges
+ // update lastRange.end only if smaller than item.end
+ // e.g. [ 1, 15] with [ 2,8] => [ 1,15] (no need to modify lastRange.end)
+ // whereas [ 1, 8] with [ 2,15] => [ 1,15] ( lastRange should switch from [1,8] to [1,15])
+ if (buffered[i].end > buf2end) {
+ buffered2[buf2len - 1].end = buffered[i].end;
+ }
+ } else {
+ // big hole
+ buffered2.push(buffered[i]);
+ }
+ } else {
+ // first value
+ buffered2.push(buffered[i]);
+ }
+ }
+ for (i = 0, bufferLen = 0, bufferStart = bufferEnd = pos; i < buffered2.length; i++) {
+ var start = buffered2[i].start,
+ end = buffered2[i].end;
+ //logger.log('buf start/end:' + buffered.start(i) + '/' + buffered.end(i));
+ if (pos + maxHoleDuration >= start && pos < end) {
+ // play position is inside this buffer TimeRange, retrieve end of buffer position and buffer length
+ bufferStart = start;
+ bufferEnd = end;
+ bufferLen = bufferEnd - pos;
+ } else if (pos + maxHoleDuration < start) {
+ bufferStartNext = start;
+ break;
+ }
+ }
+ return { len: bufferLen, start: bufferStart, end: bufferEnd, nextStart: bufferStartNext };
+ }
+ }]);
+
+ return BufferHelper;
+ }();
+
+ exports.default = BufferHelper;
+
+ },{}],29:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
+ * Level Helper class, providing methods dealing with playlist sliding and drift
+ */
+
+ var _logger = _dereq_(43);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var LevelHelper = function () {
+ function LevelHelper() {
+ _classCallCheck(this, LevelHelper);
+ }
+
+ _createClass(LevelHelper, null, [{
+ key: 'mergeDetails',
+ value: function mergeDetails(oldDetails, newDetails) {
+ var start = Math.max(oldDetails.startSN, newDetails.startSN) - newDetails.startSN,
+ end = Math.min(oldDetails.endSN, newDetails.endSN) - newDetails.startSN,
+ delta = newDetails.startSN - oldDetails.startSN,
+ oldfragments = oldDetails.fragments,
+ newfragments = newDetails.fragments,
+ ccOffset = 0,
+ PTSFrag;
+
+ // check if old/new playlists have fragments in common
+ if (end < start) {
+ newDetails.PTSKnown = false;
+ return;
+ }
+ // loop through overlapping SN and update startPTS , cc, and duration if any found
+ for (var i = start; i <= end; i++) {
+ var oldFrag = oldfragments[delta + i],
+ newFrag = newfragments[i];
+ if (newFrag && oldFrag) {
+ ccOffset = oldFrag.cc - newFrag.cc;
+ if (!isNaN(oldFrag.startPTS)) {
+ newFrag.start = newFrag.startPTS = oldFrag.startPTS;
+ newFrag.endPTS = oldFrag.endPTS;
+ newFrag.duration = oldFrag.duration;
+ PTSFrag = newFrag;
+ }
+ }
+ }
+
+ if (ccOffset) {
+ _logger.logger.log('discontinuity sliding from playlist, take drift into account');
+ for (i = 0; i < newfragments.length; i++) {
+ newfragments[i].cc += ccOffset;
+ }
+ }
+
+ // if at least one fragment contains PTS info, recompute PTS information for all fragments
+ if (PTSFrag) {
+ LevelHelper.updateFragPTSDTS(newDetails, PTSFrag.sn, PTSFrag.startPTS, PTSFrag.endPTS, PTSFrag.startDTS, PTSFrag.endDTS);
+ } else {
+ // ensure that delta is within oldfragments range
+ // also adjust sliding in case delta is 0 (we could have old=[50-60] and new=old=[50-61])
+ // in that case we also need to adjust start offset of all fragments
+ if (delta >= 0 && delta < oldfragments.length) {
+ // adjust start by sliding offset
+ var sliding = oldfragments[delta].start;
+ for (i = 0; i < newfragments.length; i++) {
+ newfragments[i].start += sliding;
+ }
+ }
+ }
+ // if we are here, it means we have fragments overlapping between
+ // old and new level. reliable PTS info is thus relying on old level
+ newDetails.PTSKnown = oldDetails.PTSKnown;
+ return;
+ }
+ }, {
+ key: 'updateFragPTSDTS',
+ value: function updateFragPTSDTS(details, sn, startPTS, endPTS, startDTS, endDTS) {
+ var fragIdx, fragments, frag, i;
+ // exit if sn out of range
+ if (sn < details.startSN || sn > details.endSN) {
+ return 0;
+ }
+ fragIdx = sn - details.startSN;
+ fragments = details.fragments;
+ frag = fragments[fragIdx];
+ if (!isNaN(frag.startPTS)) {
+ // delta PTS between audio and video
+ var deltaPTS = Math.abs(frag.startPTS - startPTS);
+ if (isNaN(frag.deltaPTS)) {
+ frag.deltaPTS = deltaPTS;
+ } else {
+ frag.deltaPTS = Math.max(deltaPTS, frag.deltaPTS);
+ }
+ startPTS = Math.min(startPTS, frag.startPTS);
+ endPTS = Math.max(endPTS, frag.endPTS);
+ startDTS = Math.min(startDTS, frag.startDTS);
+ endDTS = Math.max(endDTS, frag.endDTS);
+ }
+
+ var drift = startPTS - frag.start;
+
+ frag.start = frag.startPTS = startPTS;
+ frag.endPTS = endPTS;
+ frag.startDTS = startDTS;
+ frag.endDTS = endDTS;
+ frag.duration = endPTS - startPTS;
+ // adjust fragment PTS/duration from seqnum-1 to frag 0
+ for (i = fragIdx; i > 0; i--) {
+ LevelHelper.updatePTS(fragments, i, i - 1);
+ }
+
+ // adjust fragment PTS/duration from seqnum to last frag
+ for (i = fragIdx; i < fragments.length - 1; i++) {
+ LevelHelper.updatePTS(fragments, i, i + 1);
+ }
+ details.PTSKnown = true;
+ //logger.log(` frag start/end:${startPTS.toFixed(3)}/${endPTS.toFixed(3)}`);
+
+ return drift;
+ }
+ }, {
+ key: 'updatePTS',
+ value: function updatePTS(fragments, fromIdx, toIdx) {
+ var fragFrom = fragments[fromIdx],
+ fragTo = fragments[toIdx],
+ fragToPTS = fragTo.startPTS;
+ // if we know startPTS[toIdx]
+ if (!isNaN(fragToPTS)) {
+ // update fragment duration.
+ // it helps to fix drifts between playlist reported duration and fragment real duration
+ if (toIdx > fromIdx) {
+ fragFrom.duration = fragToPTS - fragFrom.start;
+ if (fragFrom.duration < 0) {
+ _logger.logger.warn('negative duration computed for frag ' + fragFrom.sn + ',level ' + fragFrom.level + ', there should be some duration drift between playlist and fragment!');
+ }
+ } else {
+ fragTo.duration = fragFrom.start - fragToPTS;
+ if (fragTo.duration < 0) {
+ _logger.logger.warn('negative duration computed for frag ' + fragTo.sn + ',level ' + fragTo.level + ', there should be some duration drift between playlist and fragment!');
+ }
+ }
+ } else {
+ // we dont know startPTS[toIdx]
+ if (toIdx > fromIdx) {
+ fragTo.start = fragFrom.start + fragFrom.duration;
+ } else {
+ fragTo.start = fragFrom.start - fragTo.duration;
+ }
+ }
+ }
+ }]);
+
+ return LevelHelper;
+ }();
+
+ exports.default = LevelHelper;
+
+ },{"43":43}],30:[function(_dereq_,module,exports){
+ /**
+ * HLS interface
+ */
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+ //import FetchLoader from './utils/fetch-loader';
+
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _errors = _dereq_(24);
+
+ var _playlistLoader = _dereq_(34);
+
+ var _playlistLoader2 = _interopRequireDefault(_playlistLoader);
+
+ var _fragmentLoader = _dereq_(32);
+
+ var _fragmentLoader2 = _interopRequireDefault(_fragmentLoader);
+
+ var _abrController = _dereq_(3);
+
+ var _abrController2 = _interopRequireDefault(_abrController);
+
+ var _bufferController = _dereq_(6);
+
+ var _bufferController2 = _interopRequireDefault(_bufferController);
+
+ var _capLevelController = _dereq_(7);
+
+ var _capLevelController2 = _interopRequireDefault(_capLevelController);
+
+ var _audioStreamController = _dereq_(4);
+
+ var _audioStreamController2 = _interopRequireDefault(_audioStreamController);
+
+ var _streamController = _dereq_(11);
+
+ var _streamController2 = _interopRequireDefault(_streamController);
+
+ var _levelController = _dereq_(10);
+
+ var _levelController2 = _interopRequireDefault(_levelController);
+
+ var _timelineController = _dereq_(12);
+
+ var _timelineController2 = _interopRequireDefault(_timelineController);
+
+ var _fpsController = _dereq_(9);
+
+ var _fpsController2 = _interopRequireDefault(_fpsController);
+
+ var _audioTrackController = _dereq_(5);
+
+ var _audioTrackController2 = _interopRequireDefault(_audioTrackController);
+
+ var _logger = _dereq_(43);
+
+ var _xhrLoader = _dereq_(47);
+
+ var _xhrLoader2 = _interopRequireDefault(_xhrLoader);
+
+ var _events3 = _dereq_(1);
+
+ var _events4 = _interopRequireDefault(_events3);
+
+ var _keyLoader = _dereq_(33);
+
+ var _keyLoader2 = _interopRequireDefault(_keyLoader);
+
+ var _cues = _dereq_(41);
+
+ var _cues2 = _interopRequireDefault(_cues);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var Hls = function () {
+ _createClass(Hls, null, [{
+ key: 'isSupported',
+ value: function isSupported() {
+ return window.MediaSource && typeof window.MediaSource.isTypeSupported === 'function' && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"');
+ }
+ }, {
+ key: 'version',
+ get: function get() {
+ // replaced with browserify-versionify transform
+ return '0.6.7';
+ }
+ }, {
+ key: 'Events',
+ get: function get() {
+ return _events2.default;
+ }
+ }, {
+ key: 'ErrorTypes',
+ get: function get() {
+ return _errors.ErrorTypes;
+ }
+ }, {
+ key: 'ErrorDetails',
+ get: function get() {
+ return _errors.ErrorDetails;
+ }
+ }, {
+ key: 'DefaultConfig',
+ get: function get() {
+ if (!Hls.defaultConfig) {
+ Hls.defaultConfig = {
+ autoStartLoad: true,
+ startPosition: -1,
+ defaultAudioCodec: undefined,
+ debug: false,
+ capLevelOnFPSDrop: false,
+ capLevelToPlayerSize: false,
+ maxBufferLength: 30,
+ maxBufferSize: 60 * 1000 * 1000,
+ maxBufferHole: 0.5,
+ maxSeekHole: 2,
+ seekHoleNudgeDuration: 0.01,
+ stalledInBufferedNudgeThreshold: 10,
+ maxFragLookUpTolerance: 0.2,
+ liveSyncDurationCount: 3,
+ liveMaxLatencyDurationCount: Infinity,
+ liveSyncDuration: undefined,
+ liveMaxLatencyDuration: undefined,
+ maxMaxBufferLength: 600,
+ enableWorker: true,
+ enableSoftwareAES: true,
+ manifestLoadingTimeOut: 10000,
+ manifestLoadingMaxRetry: 1,
+ manifestLoadingRetryDelay: 1000,
+ manifestLoadingMaxRetryTimeout: 64000,
+ startLevel: undefined,
+ levelLoadingTimeOut: 10000,
+ levelLoadingMaxRetry: 4,
+ levelLoadingRetryDelay: 1000,
+ levelLoadingMaxRetryTimeout: 64000,
+ fragLoadingTimeOut: 20000,
+ fragLoadingMaxRetry: 6,
+ fragLoadingRetryDelay: 1000,
+ fragLoadingMaxRetryTimeout: 64000,
+ fragLoadingLoopThreshold: 3,
+ startFragPrefetch: false,
+ fpsDroppedMonitoringPeriod: 5000,
+ fpsDroppedMonitoringThreshold: 0.2,
+ appendErrorMaxRetry: 3,
+ loader: _xhrLoader2.default,
+ //loader: FetchLoader,
+ fLoader: undefined,
+ pLoader: undefined,
+ xhrSetup: undefined,
+ fetchSetup: undefined,
+ abrController: _abrController2.default,
+ bufferController: _bufferController2.default,
+ capLevelController: _capLevelController2.default,
+ fpsController: _fpsController2.default,
+ streamController: _streamController2.default,
+ audioStreamController: _audioStreamController2.default,
+ timelineController: _timelineController2.default,
+ cueHandler: _cues2.default,
+ enableCEA708Captions: true,
+ enableMP2TPassThrough: false,
+ stretchShortVideoTrack: false,
+ forceKeyFrameOnDiscontinuity: true,
+ abrEwmaFastLive: 5,
+ abrEwmaSlowLive: 9,
+ abrEwmaFastVoD: 3,
+ abrEwmaSlowVoD: 9,
+ abrEwmaDefaultEstimate: 5e5, // 500 kbps
+ abrBandWidthFactor: 0.8,
+ abrBandWidthUpFactor: 0.7,
+ maxStarvationDelay: 4,
+ maxLoadingDelay: 4,
+ minAutoBitrate: 0
+ };
+ }
+ return Hls.defaultConfig;
+ },
+ set: function set(defaultConfig) {
+ Hls.defaultConfig = defaultConfig;
+ }
+ }]);
+
+ function Hls() {
+ var config = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
+
+ _classCallCheck(this, Hls);
+
+ var defaultConfig = Hls.DefaultConfig;
+
+ if ((config.liveSyncDurationCount || config.liveMaxLatencyDurationCount) && (config.liveSyncDuration || config.liveMaxLatencyDuration)) {
+ throw new Error('Illegal hls.js config: don\'t mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration');
+ }
+
+ for (var prop in defaultConfig) {
+ if (prop in config) {
+ continue;
+ }
+ config[prop] = defaultConfig[prop];
+ }
+
+ if (config.liveMaxLatencyDurationCount !== undefined && config.liveMaxLatencyDurationCount <= config.liveSyncDurationCount) {
+ throw new Error('Illegal hls.js config: "liveMaxLatencyDurationCount" must be gt "liveSyncDurationCount"');
+ }
+
+ if (config.liveMaxLatencyDuration !== undefined && (config.liveMaxLatencyDuration <= config.liveSyncDuration || config.liveSyncDuration === undefined)) {
+ throw new Error('Illegal hls.js config: "liveMaxLatencyDuration" must be gt "liveSyncDuration"');
+ }
+
+ (0, _logger.enableLogs)(config.debug);
+ this.config = config;
+ // observer setup
+ var observer = this.observer = new _events4.default();
+ observer.trigger = function trigger(event) {
+ for (var _len = arguments.length, data = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ data[_key - 1] = arguments[_key];
+ }
+
+ observer.emit.apply(observer, [event, event].concat(data));
+ };
+
+ observer.off = function off(event) {
+ for (var _len2 = arguments.length, data = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
+ data[_key2 - 1] = arguments[_key2];
+ }
+
+ observer.removeListener.apply(observer, [event].concat(data));
+ };
+ this.on = observer.on.bind(observer);
+ this.off = observer.off.bind(observer);
+ this.trigger = observer.trigger.bind(observer);
+ this.playlistLoader = new _playlistLoader2.default(this);
+ this.fragmentLoader = new _fragmentLoader2.default(this);
+ this.levelController = new _levelController2.default(this);
+ this.abrController = new config.abrController(this);
+ this.bufferController = new config.bufferController(this);
+ this.capLevelController = new config.capLevelController(this);
+ this.fpsController = new config.fpsController(this);
+ this.streamController = new config.streamController(this);
+ this.audioStreamController = new config.audioStreamController(this);
+ this.timelineController = new config.timelineController(this);
+ this.audioTrackController = new _audioTrackController2.default(this);
+ this.keyLoader = new _keyLoader2.default(this);
+ }
+
+ _createClass(Hls, [{
+ key: 'destroy',
+ value: function destroy() {
+ _logger.logger.log('destroy');
+ this.trigger(_events2.default.DESTROYING);
+ this.detachMedia();
+ this.playlistLoader.destroy();
+ this.fragmentLoader.destroy();
+ this.levelController.destroy();
+ this.abrController.destroy();
+ this.bufferController.destroy();
+ this.capLevelController.destroy();
+ this.fpsController.destroy();
+ this.streamController.destroy();
+ this.audioStreamController.destroy();
+ this.timelineController.destroy();
+ this.audioTrackController.destroy();
+ this.keyLoader.destroy();
+ this.url = null;
+ this.observer.removeAllListeners();
+ }
+ }, {
+ key: 'attachMedia',
+ value: function attachMedia(media) {
+ _logger.logger.log('attachMedia');
+ this.media = media;
+ this.trigger(_events2.default.MEDIA_ATTACHING, { media: media });
+ }
+ }, {
+ key: 'detachMedia',
+ value: function detachMedia() {
+ _logger.logger.log('detachMedia');
+ this.trigger(_events2.default.MEDIA_DETACHING);
+ this.media = null;
+ }
+ }, {
+ key: 'loadSource',
+ value: function loadSource(url) {
+ _logger.logger.log('loadSource:' + url);
+ this.url = url;
+ // when attaching to a source URL, trigger a playlist load
+ this.trigger(_events2.default.MANIFEST_LOADING, { url: url });
+ }
+ }, {
+ key: 'startLoad',
+ value: function startLoad() {
+ var startPosition = arguments.length <= 0 || arguments[0] === undefined ? -1 : arguments[0];
+
+ _logger.logger.log('startLoad');
+ this.levelController.startLoad();
+ this.streamController.startLoad(startPosition);
+ this.audioStreamController.startLoad(startPosition);
+ }
+ }, {
+ key: 'stopLoad',
+ value: function stopLoad() {
+ _logger.logger.log('stopLoad');
+ this.levelController.stopLoad();
+ this.streamController.stopLoad();
+ this.audioStreamController.stopLoad();
+ }
+ }, {
+ key: 'swapAudioCodec',
+ value: function swapAudioCodec() {
+ _logger.logger.log('swapAudioCodec');
+ this.streamController.swapAudioCodec();
+ }
+ }, {
+ key: 'recoverMediaError',
+ value: function recoverMediaError() {
+ _logger.logger.log('recoverMediaError');
+ var media = this.media;
+ this.detachMedia();
+ this.attachMedia(media);
+ }
+
+ /** Return all quality levels **/
+
+ }, {
+ key: 'levels',
+ get: function get() {
+ return this.levelController.levels;
+ }
+
+ /** Return current playback quality level **/
+
+ }, {
+ key: 'currentLevel',
+ get: function get() {
+ return this.streamController.currentLevel;
+ }
+
+ /* set quality level immediately (-1 for automatic level selection) */
+ ,
+ set: function set(newLevel) {
+ _logger.logger.log('set currentLevel:' + newLevel);
+ this.loadLevel = newLevel;
+ this.streamController.immediateLevelSwitch();
+ }
+
+ /** Return next playback quality level (quality level of next fragment) **/
+
+ }, {
+ key: 'nextLevel',
+ get: function get() {
+ return this.streamController.nextLevel;
+ }
+
+ /* set quality level for next fragment (-1 for automatic level selection) */
+ ,
+ set: function set(newLevel) {
+ _logger.logger.log('set nextLevel:' + newLevel);
+ this.levelController.manualLevel = newLevel;
+ this.streamController.nextLevelSwitch();
+ }
+
+ /** Return the quality level of current/last loaded fragment **/
+
+ }, {
+ key: 'loadLevel',
+ get: function get() {
+ return this.levelController.level;
+ }
+
+ /* set quality level for current/next loaded fragment (-1 for automatic level selection) */
+ ,
+ set: function set(newLevel) {
+ _logger.logger.log('set loadLevel:' + newLevel);
+ this.levelController.manualLevel = newLevel;
+ }
+
+ /** Return the quality level of next loaded fragment **/
+
+ }, {
+ key: 'nextLoadLevel',
+ get: function get() {
+ return this.levelController.nextLoadLevel;
+ }
+
+ /** set quality level of next loaded fragment **/
+ ,
+ set: function set(level) {
+ this.levelController.nextLoadLevel = level;
+ }
+
+ /** Return first level (index of first level referenced in manifest)
+ **/
+
+ }, {
+ key: 'firstLevel',
+ get: function get() {
+ return this.levelController.firstLevel;
+ }
+
+ /** set first level (index of first level referenced in manifest)
+ **/
+ ,
+ set: function set(newLevel) {
+ _logger.logger.log('set firstLevel:' + newLevel);
+ this.levelController.firstLevel = newLevel;
+ }
+
+ /** Return start level (level of first fragment that will be played back)
+ if not overrided by user, first level appearing in manifest will be used as start level
+ if -1 : automatic start level selection, playback will start from level matching download bandwidth (determined from download of first segment)
+ **/
+
+ }, {
+ key: 'startLevel',
+ get: function get() {
+ return this.levelController.startLevel;
+ }
+
+ /** set start level (level of first fragment that will be played back)
+ if not overrided by user, first level appearing in manifest will be used as start level
+ if -1 : automatic start level selection, playback will start from level matching download bandwidth (determined from download of first segment)
+ **/
+ ,
+ set: function set(newLevel) {
+ _logger.logger.log('set startLevel:' + newLevel);
+ this.levelController.startLevel = newLevel;
+ }
+
+ /** Return the capping/max level value that could be used by automatic level selection algorithm **/
+
+ }, {
+ key: 'autoLevelCapping',
+ get: function get() {
+ return this.abrController.autoLevelCapping;
+ }
+
+ /** set the capping/max level value that could be used by automatic level selection algorithm **/
+ ,
+ set: function set(newLevel) {
+ _logger.logger.log('set autoLevelCapping:' + newLevel);
+ this.abrController.autoLevelCapping = newLevel;
+ }
+
+ /* check if we are in automatic level selection mode */
+
+ }, {
+ key: 'autoLevelEnabled',
+ get: function get() {
+ return this.levelController.manualLevel === -1;
+ }
+
+ /* return manual level */
+
+ }, {
+ key: 'manualLevel',
+ get: function get() {
+ return this.levelController.manualLevel;
+ }
+
+ /** get alternate audio tracks list from playlist **/
+
+ }, {
+ key: 'audioTracks',
+ get: function get() {
+ return this.audioTrackController.audioTracks;
+ }
+
+ /** get index of the selected audio track (index in audio track lists) **/
+
+ }, {
+ key: 'audioTrack',
+ get: function get() {
+ return this.audioTrackController.audioTrack;
+ }
+
+ /** select an audio track, based on its index in audio track lists**/
+ ,
+ set: function set(audioTrackId) {
+ this.audioTrackController.audioTrack = audioTrackId;
+ }
+ }, {
+ key: 'liveSyncPosition',
+ get: function get() {
+ return this.streamController.liveSyncPosition;
+ }
+ }]);
+
+ return Hls;
+ }();
+
+ exports.default = Hls;
+
+ },{"1":1,"10":10,"11":11,"12":12,"24":24,"26":26,"3":3,"32":32,"33":33,"34":34,"4":4,"41":41,"43":43,"47":47,"5":5,"6":6,"7":7,"9":9}],31:[function(_dereq_,module,exports){
+ 'use strict';
+
+ // This is mostly for support of the es6 module export
+ // syntax with the babel compiler, it looks like it doesnt support
+ // function exports like we are used to in node/commonjs
+ module.exports = _dereq_(30).default;
+
+ },{"30":30}],32:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _eventHandler = _dereq_(25);
+
+ var _eventHandler2 = _interopRequireDefault(_eventHandler);
+
+ var _errors = _dereq_(24);
+
+ var _logger = _dereq_(43);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
+ * Fragment Loader
+ */
+
+ var FragmentLoader = function (_EventHandler) {
+ _inherits(FragmentLoader, _EventHandler);
+
+ function FragmentLoader(hls) {
+ _classCallCheck(this, FragmentLoader);
+
+ var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(FragmentLoader).call(this, hls, _events2.default.FRAG_LOADING));
+
+ _this.loaders = {};
+ return _this;
+ }
+
+ _createClass(FragmentLoader, [{
+ key: 'destroy',
+ value: function destroy() {
+ var loaders = this.loaders;
+ for (var loaderName in loaders) {
+ var loader = loaders[loaderName];
+ if (loader) {
+ loader.destroy();
+ }
+ }
+ this.loaders = {};
+ _eventHandler2.default.prototype.destroy.call(this);
+ }
+ }, {
+ key: 'onFragLoading',
+ value: function onFragLoading(data) {
+ var frag = data.frag,
+ type = frag.type,
+ loader = this.loaders[type],
+ config = this.hls.config;
+
+ frag.loaded = 0;
+ if (loader) {
+ _logger.logger.warn('abort previous fragment loader for type:' + type);
+ loader.abort();
+ }
+ loader = this.loaders[type] = frag.loader = typeof config.fLoader !== 'undefined' ? new config.fLoader(config) : new config.loader(config);
+
+ var loaderContext = void 0,
+ loaderConfig = void 0,
+ loaderCallbacks = void 0;
+ loaderContext = { url: frag.url, frag: frag, responseType: 'arraybuffer', progressData: false };
+ var start = frag.byteRangeStartOffset,
+ end = frag.byteRangeEndOffset;
+ if (!isNaN(start) && !isNaN(end)) {
+ loaderContext.rangeStart = start;
+ loaderContext.rangeEnd = end;
+ }
+ loaderConfig = { timeout: config.fragLoadingTimeOut, maxRetry: 0, retryDelay: 0, maxRetryDelay: config.fragLoadingMaxRetryTimeout };
+ loaderCallbacks = { onSuccess: this.loadsuccess.bind(this), onError: this.loaderror.bind(this), onTimeout: this.loadtimeout.bind(this), onProgress: this.loadprogress.bind(this) };
+ loader.load(loaderContext, loaderConfig, loaderCallbacks);
+ }
+ }, {
+ key: 'loadsuccess',
+ value: function loadsuccess(response, stats, context) {
+ var payload = response.data,
+ frag = context.frag;
+ // detach fragment loader on load success
+ frag.loader = undefined;
+ this.loaders[frag.type] = undefined;
+ this.hls.trigger(_events2.default.FRAG_LOADED, { payload: payload, frag: frag, stats: stats });
+ }
+ }, {
+ key: 'loaderror',
+ value: function loaderror(response, context) {
+ var loader = context.loader;
+ if (loader) {
+ loader.abort();
+ }
+ this.loaders[context.type] = undefined;
+ this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.NETWORK_ERROR, details: _errors.ErrorDetails.FRAG_LOAD_ERROR, fatal: false, frag: context.frag, response: response });
+ }
+ }, {
+ key: 'loadtimeout',
+ value: function loadtimeout(stats, context) {
+ var loader = context.loader;
+ if (loader) {
+ loader.abort();
+ }
+ this.loaders[context.type] = undefined;
+ this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.NETWORK_ERROR, details: _errors.ErrorDetails.FRAG_LOAD_TIMEOUT, fatal: false, frag: context.frag });
+ }
+
+ // data will be used for progressive parsing
+
+ }, {
+ key: 'loadprogress',
+ value: function loadprogress(stats, context, data) {
+ // jshint ignore:line
+ var frag = context.frag;
+ frag.loaded = stats.loaded;
+ this.hls.trigger(_events2.default.FRAG_LOAD_PROGRESS, { frag: frag, stats: stats });
+ }
+ }]);
+
+ return FragmentLoader;
+ }(_eventHandler2.default);
+
+ exports.default = FragmentLoader;
+
+ },{"24":24,"25":25,"26":26,"43":43}],33:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _eventHandler = _dereq_(25);
+
+ var _eventHandler2 = _interopRequireDefault(_eventHandler);
+
+ var _errors = _dereq_(24);
+
+ var _logger = _dereq_(43);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /*
+ * Decrypt key Loader
+ */
+
+ var KeyLoader = function (_EventHandler) {
+ _inherits(KeyLoader, _EventHandler);
+
+ function KeyLoader(hls) {
+ _classCallCheck(this, KeyLoader);
+
+ var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(KeyLoader).call(this, hls, _events2.default.KEY_LOADING));
+
+ _this.loaders = {};
+ _this.decryptkey = null;
+ _this.decrypturl = null;
+ return _this;
+ }
+
+ _createClass(KeyLoader, [{
+ key: 'destroy',
+ value: function destroy() {
+ for (var loaderName in this.loaders) {
+ var loader = this.loaders[loaderName];
+ if (loader) {
+ loader.destroy();
+ }
+ }
+ this.loaders = {};
+ _eventHandler2.default.prototype.destroy.call(this);
+ }
+ }, {
+ key: 'onKeyLoading',
+ value: function onKeyLoading(data) {
+ var frag = data.frag,
+ type = frag.type,
+ loader = this.loaders[type],
+ decryptdata = frag.decryptdata,
+ uri = decryptdata.uri;
+ // if uri is different from previous one or if decrypt key not retrieved yet
+ if (uri !== this.decrypturl || this.decryptkey === null) {
+ var config = this.hls.config;
+
+ if (loader) {
+ _logger.logger.warn('abort previous fragment loader for type:' + type);
+ loader.abort();
+ }
+ frag.loader = this.loaders[type] = new config.loader(config);
+ this.decrypturl = uri;
+ this.decryptkey = null;
+
+ var loaderContext = void 0,
+ loaderConfig = void 0,
+ loaderCallbacks = void 0;
+ loaderContext = { url: uri, frag: frag, responseType: 'arraybuffer' };
+ loaderConfig = { timeout: config.fragLoadingTimeOut, maxRetry: config.fragLoadingMaxRetry, retryDelay: config.fragLoadingRetryDelay, maxRetryDelay: config.fragLoadingMaxRetryTimeout };
+ loaderCallbacks = { onSuccess: this.loadsuccess.bind(this), onError: this.loaderror.bind(this), onTimeout: this.loadtimeout.bind(this) };
+ frag.loader.load(loaderContext, loaderConfig, loaderCallbacks);
+ } else if (this.decryptkey) {
+ // we already loaded this key, return it
+ decryptdata.key = this.decryptkey;
+ this.hls.trigger(_events2.default.KEY_LOADED, { frag: frag });
+ }
+ }
+ }, {
+ key: 'loadsuccess',
+ value: function loadsuccess(response, stats, context) {
+ var frag = context.frag;
+ this.decryptkey = frag.decryptdata.key = new Uint8Array(response.data);
+ // detach fragment loader on load success
+ frag.loader = undefined;
+ this.loaders[context.type] = undefined;
+ this.hls.trigger(_events2.default.KEY_LOADED, { frag: frag });
+ }
+ }, {
+ key: 'loaderror',
+ value: function loaderror(response, context) {
+ var frag = context.frag,
+ loader = frag.loader;
+ if (loader) {
+ loader.abort();
+ }
+ this.loaders[context.type] = undefined;
+ this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.NETWORK_ERROR, details: _errors.ErrorDetails.KEY_LOAD_ERROR, fatal: false, frag: frag, response: response });
+ }
+ }, {
+ key: 'loadtimeout',
+ value: function loadtimeout(stats, context) {
+ var frag = context.frag,
+ loader = frag.loader;
+ if (loader) {
+ loader.abort();
+ }
+ this.loaders[context.type] = undefined;
+ this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.NETWORK_ERROR, details: _errors.ErrorDetails.KEY_LOAD_TIMEOUT, fatal: false, frag: frag });
+ }
+ }]);
+
+ return KeyLoader;
+ }(_eventHandler2.default);
+
+ exports.default = KeyLoader;
+
+ },{"24":24,"25":25,"26":26,"43":43}],34:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _eventHandler = _dereq_(25);
+
+ var _eventHandler2 = _interopRequireDefault(_eventHandler);
+
+ var _errors = _dereq_(24);
+
+ var _url = _dereq_(46);
+
+ var _url2 = _interopRequireDefault(_url);
+
+ var _attrList = _dereq_(38);
+
+ var _attrList2 = _interopRequireDefault(_attrList);
+
+ var _logger = _dereq_(43);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+ * Playlist Loader
+ */
+
+ var PlaylistLoader = function (_EventHandler) {
+ _inherits(PlaylistLoader, _EventHandler);
+
+ function PlaylistLoader(hls) {
+ _classCallCheck(this, PlaylistLoader);
+
+ var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(PlaylistLoader).call(this, hls, _events2.default.MANIFEST_LOADING, _events2.default.LEVEL_LOADING, _events2.default.AUDIO_TRACK_LOADING));
+
+ _this.loaders = {};
+ return _this;
+ }
+
+ _createClass(PlaylistLoader, [{
+ key: 'destroy',
+ value: function destroy() {
+ for (var loaderName in this.loaders) {
+ var loader = this.loaders[loaderName];
+ if (loader) {
+ loader.destroy();
+ }
+ }
+ this.loaders = {};
+ _eventHandler2.default.prototype.destroy.call(this);
+ }
+ }, {
+ key: 'onManifestLoading',
+ value: function onManifestLoading(data) {
+ this.load(data.url, { type: 'manifest' });
+ }
+ }, {
+ key: 'onLevelLoading',
+ value: function onLevelLoading(data) {
+ this.load(data.url, { type: 'level', level: data.level, id: data.id });
+ }
+ }, {
+ key: 'onAudioTrackLoading',
+ value: function onAudioTrackLoading(data) {
+ this.load(data.url, { type: 'audioTrack', id: data.id });
+ }
+ }, {
+ key: 'load',
+ value: function load(url, context) {
+ var loader = this.loaders[context.type];
+ if (loader) {
+ var loaderContext = loader.context;
+ if (loaderContext && loaderContext.url === url) {
+ _logger.logger.trace('playlist request ongoing');
+ return;
+ } else {
+ _logger.logger.warn('abort previous loader for type:' + context.type);
+ loader.abort();
+ }
+ }
+ var config = this.hls.config,
+ retry = void 0,
+ timeout = void 0,
+ retryDelay = void 0,
+ maxRetryDelay = void 0;
+ if (context.type === 'manifest') {
+ retry = config.manifestLoadingMaxRetry;
+ timeout = config.manifestLoadingTimeOut;
+ retryDelay = config.manifestLoadingRetryDelay;
+ maxRetryDelay = config.manifestLoadingMaxRetryTimeOut;
+ } else {
+ retry = config.levelLoadingMaxRetry;
+ timeout = config.levelLoadingTimeOut;
+ retryDelay = config.levelLoadingRetryDelay;
+ maxRetryDelay = config.levelLoadingMaxRetryTimeOut;
+ _logger.logger.log('loading playlist for level ' + context.level);
+ }
+ loader = this.loaders[context.type] = context.loader = typeof config.pLoader !== 'undefined' ? new config.pLoader(config) : new config.loader(config);
+ context.url = url;
+ context.responseType = '';
+
+ var loaderConfig = void 0,
+ loaderCallbacks = void 0;
+ loaderConfig = { timeout: timeout, maxRetry: retry, retryDelay: retryDelay, maxRetryDelay: maxRetryDelay };
+ loaderCallbacks = { onSuccess: this.loadsuccess.bind(this), onError: this.loaderror.bind(this), onTimeout: this.loadtimeout.bind(this) };
+ loader.load(context, loaderConfig, loaderCallbacks);
+ }
+ }, {
+ key: 'resolve',
+ value: function resolve(url, baseUrl) {
+ return _url2.default.buildAbsoluteURL(baseUrl, url);
+ }
+ }, {
+ key: 'parseMasterPlaylist',
+ value: function parseMasterPlaylist(string, baseurl) {
+ var levels = [],
+ result = void 0;
+
+ // https://regex101.com is your friend
+ var re = /#EXT-X-STREAM-INF:([^\n\r]*)[\r\n]+([^\r\n]+)/g;
+ while ((result = re.exec(string)) != null) {
+ var level = {};
+
+ var attrs = level.attrs = new _attrList2.default(result[1]);
+ level.url = this.resolve(result[2], baseurl);
+
+ var resolution = attrs.decimalResolution('RESOLUTION');
+ if (resolution) {
+ level.width = resolution.width;
+ level.height = resolution.height;
+ }
+ level.bitrate = attrs.decimalInteger('AVERAGE-BANDWIDTH') || attrs.decimalInteger('BANDWIDTH');
+ level.name = attrs.NAME;
+
+ var codecs = attrs.CODECS;
+ if (codecs) {
+ codecs = codecs.split(',');
+ for (var i = 0; i < codecs.length; i++) {
+ var codec = codecs[i];
+ if (codec.indexOf('avc1') !== -1) {
+ level.videoCodec = this.avc1toavcoti(codec);
+ } else {
+ level.audioCodec = codec;
+ }
+ }
+ }
+
+ levels.push(level);
+ }
+ return levels;
+ }
+ }, {
+ key: 'parseMasterPlaylistMedia',
+ value: function parseMasterPlaylistMedia(string, baseurl, type) {
+ var result = void 0,
+ medias = [];
+
+ // https://regex101.com is your friend
+ var re = /#EXT-X-MEDIA:(.*)/g;
+ while ((result = re.exec(string)) != null) {
+ var media = {};
+ var attrs = new _attrList2.default(result[1]);
+ if (attrs.TYPE === type) {
+ media.groupId = attrs['GROUP-ID'];
+ media.name = attrs.NAME;
+ media.type = type;
+ media.default = attrs.DEFAULT === 'YES';
+ media.autoselect = attrs.AUTOSELECT === 'YES';
+ media.forced = attrs.FORCED === 'YES';
+ if (attrs.URI) {
+ media.url = this.resolve(attrs.URI, baseurl);
+ }
+ media.lang = attrs.LANGUAGE;
+ if (!media.name) {
+ media.name = media.lang;
+ }
+ medias.push(media);
+ }
+ }
+ return medias;
+ }
+ /**
+ * Utility method for parseLevelPlaylist to create an initialization vector for a given segment
+ * @returns {Uint8Array}
+ */
+
+ }, {
+ key: 'createInitializationVector',
+ value: function createInitializationVector(segmentNumber) {
+ var uint8View = new Uint8Array(16);
+
+ for (var i = 12; i < 16; i++) {
+ uint8View[i] = segmentNumber >> 8 * (15 - i) & 0xff;
+ }
+
+ return uint8View;
+ }
+
+ /**
+ * Utility method for parseLevelPlaylist to get a fragment's decryption data from the currently parsed encryption key data
+ * @param levelkey - a playlist's encryption info
+ * @param segmentNumber - the fragment's segment number
+ * @returns {*} - an object to be applied as a fragment's decryptdata
+ */
+
+ }, {
+ key: 'fragmentDecryptdataFromLevelkey',
+ value: function fragmentDecryptdataFromLevelkey(levelkey, segmentNumber) {
+ var decryptdata = levelkey;
+
+ if (levelkey && levelkey.method && levelkey.uri && !levelkey.iv) {
+ decryptdata = this.cloneObj(levelkey);
+ decryptdata.iv = this.createInitializationVector(segmentNumber);
+ }
+
+ return decryptdata;
+ }
+ }, {
+ key: 'avc1toavcoti',
+ value: function avc1toavcoti(codec) {
+ var result,
+ avcdata = codec.split('.');
+ if (avcdata.length > 2) {
+ result = avcdata.shift() + '.';
+ result += parseInt(avcdata.shift()).toString(16);
+ result += ('000' + parseInt(avcdata.shift()).toString(16)).substr(-4);
+ } else {
+ result = codec;
+ }
+ return result;
+ }
+ }, {
+ key: 'cloneObj',
+ value: function cloneObj(obj) {
+ return JSON.parse(JSON.stringify(obj));
+ }
+ }, {
+ key: 'parseLevelPlaylist',
+ value: function parseLevelPlaylist(string, baseurl, id, type) {
+ var currentSN = 0,
+ fragdecryptdata,
+ totalduration = 0,
+ level = { type: null, version: null, url: baseurl, fragments: [], live: true, startSN: 0 },
+ levelkey = { method: null, key: null, iv: null, uri: null },
+ cc = 0,
+ programDateTime = null,
+ frag = null,
+ result,
+ regexp,
+ duration = null,
+ title = null,
+ byteRangeEndOffset = null,
+ byteRangeStartOffset = null,
+ tagList = [];
+
+ regexp = /(?:(?:#(EXTM3U))|(?:#EXT-X-(PLAYLIST-TYPE):(.+))|(?:#EXT-X-(MEDIA-SEQUENCE):(\d+))|(?:#EXT-X-(TARGETDURATION):(\d+))|(?:#EXT-X-(KEY):(.+))|(?:#EXT-X-(START):(.+))|(?:#EXT(INF):(\d+(?:\.\d+)?)(?:,(.*))?)|(?:(?!#)()(\S.+))|(?:#EXT-X-(BYTERANGE):(\d+(?:@\d+(?:\.\d+)?)?)|(?:#EXT-X-(ENDLIST))|(?:#EXT-X-(DIS)CONTINUITY))|(?:#EXT-X-(PROGRAM-DATE-TIME):(.+))|(?:#EXT-X-(VERSION):(\d+))|(?:(#)(.*):(.*))|(?:(#)(.*)))(?:.*)\r?\n?/g;
+ while ((result = regexp.exec(string)) !== null) {
+ result.shift();
+ result = result.filter(function (n) {
+ return n !== undefined;
+ });
+ switch (result[0]) {
+ case 'PLAYLIST-TYPE':
+ level.type = result[1].toUpperCase();
+ break;
+ case 'MEDIA-SEQUENCE':
+ currentSN = level.startSN = parseInt(result[1]);
+ break;
+ case 'TARGETDURATION':
+ level.targetduration = parseFloat(result[1]);
+ break;
+ case 'VERSION':
+ level.version = parseInt(result[1]);
+ break;
+ case 'EXTM3U':
+ break;
+ case 'ENDLIST':
+ level.live = false;
+ break;
+ case 'DIS':
+ cc++;
+ tagList.push(result);
+ break;
+ case 'BYTERANGE':
+ var params = result[1].split('@');
+ if (params.length === 1) {
+ byteRangeStartOffset = byteRangeEndOffset;
+ } else {
+ byteRangeStartOffset = parseInt(params[1]);
+ }
+ byteRangeEndOffset = parseInt(params[0]) + byteRangeStartOffset;
+ break;
+ case 'INF':
+ duration = parseFloat(result[1]);
+ title = result[2] ? result[2] : null;
+ tagList.push(result);
+ break;
+ case '':
+ // url
+ if (!isNaN(duration)) {
+ var sn = currentSN++;
+ fragdecryptdata = this.fragmentDecryptdataFromLevelkey(levelkey, sn);
+ var url = result[1] ? this.resolve(result[1], baseurl) : null;
+ frag = { url: url,
+ type: type,
+ duration: duration,
+ title: title,
+ start: totalduration,
+ sn: sn,
+ level: id,
+ cc: cc,
+ decryptdata: fragdecryptdata,
+ programDateTime: programDateTime,
+ tagList: tagList };
+ // only include byte range options if used/needed
+ if (byteRangeStartOffset !== null) {
+ frag.byteRangeStartOffset = byteRangeStartOffset;
+ frag.byteRangeEndOffset = byteRangeEndOffset;
+ }
+ level.fragments.push(frag);
+ totalduration += duration;
+ duration = null;
+ title = null;
+ byteRangeStartOffset = null;
+ programDateTime = null;
+ tagList = [];
+ }
+ break;
+ case 'KEY':
+ // https://tools.ietf.org/html/draft-pantos-http-live-streaming-08#section-3.4.4
+ var decryptparams = result[1];
+ var keyAttrs = new _attrList2.default(decryptparams);
+ var decryptmethod = keyAttrs.enumeratedString('METHOD'),
+ decrypturi = keyAttrs.URI,
+ decryptiv = keyAttrs.hexadecimalInteger('IV');
+ if (decryptmethod) {
+ levelkey = { method: null, key: null, iv: null, uri: null };
+ if (decrypturi && decryptmethod === 'AES-128') {
+ levelkey.method = decryptmethod;
+ // URI to get the key
+ levelkey.uri = this.resolve(decrypturi, baseurl);
+ levelkey.key = null;
+ // Initialization Vector (IV)
+ levelkey.iv = decryptiv;
+ }
+ }
+ break;
+ case 'START':
+ var startParams = result[1];
+ var startAttrs = new _attrList2.default(startParams);
+ var startTimeOffset = startAttrs.decimalFloatingPoint('TIME-OFFSET');
+ //TIME-OFFSET can be 0
+ if (!isNaN(startTimeOffset)) {
+ level.startTimeOffset = startTimeOffset;
+ }
+ break;
+ case 'PROGRAM-DATE-TIME':
+ programDateTime = new Date(Date.parse(result[1]));
+ tagList.push(result);
+ break;
+ case '#':
+ result.shift();
+ tagList.push(result);
+ break;
+ default:
+ _logger.logger.warn('line parsed but not handled: ' + result);
+ break;
+ }
+ }
+ //logger.log('found ' + level.fragments.length + ' fragments');
+ if (frag && !frag.url) {
+ level.fragments.pop();
+ totalduration -= frag.duration;
+ }
+ level.totalduration = totalduration;
+ level.averagetargetduration = totalduration / level.fragments.length;
+ level.endSN = currentSN - 1;
+ return level;
+ }
+ }, {
+ key: 'loadsuccess',
+ value: function loadsuccess(response, stats, context) {
+ var string = response.data,
+ url = response.url,
+ type = context.type,
+ id = context.id,
+ level = context.level,
+ hls = this.hls;
+
+ this.loaders[type] = undefined;
+ // responseURL not supported on some browsers (it is used to detect URL redirection)
+ // data-uri mode also not supported (but no need to detect redirection)
+ if (url === undefined || url.indexOf('data:') === 0) {
+ // fallback to initial URL
+ url = context.url;
+ }
+ stats.tload = performance.now();
+ //stats.mtime = new Date(target.getResponseHeader('Last-Modified'));
+ if (string.indexOf('#EXTM3U') === 0) {
+ if (string.indexOf('#EXTINF:') > 0) {
+ var isLevel = type !== 'audioTrack',
+ levelDetails = this.parseLevelPlaylist(string, url, (isLevel ? level : id) || 0, isLevel ? 'main' : 'audio');
+ if (type === 'manifest') {
+ // first request, stream manifest (no master playlist), fire manifest loaded event with level details
+ hls.trigger(_events2.default.MANIFEST_LOADED, { levels: [{ url: url, details: levelDetails }], audioTracks: [], url: url, stats: stats });
+ }
+ stats.tparsed = performance.now();
+ if (isLevel) {
+ hls.trigger(_events2.default.LEVEL_LOADED, { details: levelDetails, level: level || 0, id: id || 0, stats: stats });
+ } else {
+ hls.trigger(_events2.default.AUDIO_TRACK_LOADED, { details: levelDetails, id: id, stats: stats });
+ }
+ } else {
+ var levels = this.parseMasterPlaylist(string, url);
+ // multi level playlist, parse level info
+ if (levels.length) {
+ var audiotracks = this.parseMasterPlaylistMedia(string, url, 'AUDIO');
+ if (audiotracks.length) {
+ // check if we have found an audio track embedded in main playlist (audio track without URI attribute)
+ var embeddedAudioFound = false;
+ audiotracks.forEach(function (audioTrack) {
+ if (!audioTrack.url) {
+ embeddedAudioFound = true;
+ }
+ });
+ // if no embedded audio track defined, but audio codec signaled in quality level, we need to signal this main audio track
+ // this could happen with playlists with alt audio rendition in which quality levels (main) contains both audio+video. but with mixed audio track not signaled
+ if (embeddedAudioFound === false && levels[0].audioCodec && !levels[0].attrs.AUDIO) {
+ _logger.logger.log('audio codec signaled in quality level, but no embedded audio track signaled, create one');
+ audiotracks.unshift({ type: 'main', name: 'main' });
+ }
+ }
+ hls.trigger(_events2.default.MANIFEST_LOADED, { levels: levels, audioTracks: audiotracks, url: url, stats: stats });
+ } else {
+ hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.NETWORK_ERROR, details: _errors.ErrorDetails.MANIFEST_PARSING_ERROR, fatal: true, url: url, reason: 'no level found in manifest' });
+ }
+ }
+ } else {
+ hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.NETWORK_ERROR, details: _errors.ErrorDetails.MANIFEST_PARSING_ERROR, fatal: true, url: url, reason: 'no EXTM3U delimiter' });
+ }
+ }
+ }, {
+ key: 'loaderror',
+ value: function loaderror(response, context) {
+ var details,
+ fatal,
+ loader = context.loader;
+ switch (context.type) {
+ case 'manifest':
+ details = _errors.ErrorDetails.MANIFEST_LOAD_ERROR;
+ fatal = true;
+ break;
+ case 'level':
+ details = _errors.ErrorDetails.LEVEL_LOAD_ERROR;
+ fatal = false;
+ break;
+ case 'audioTrack':
+ details = _errors.ErrorDetails.AUDIO_TRACK_LOAD_ERROR;
+ fatal = false;
+ break;
+ }
+ if (loader) {
+ loader.abort();
+ this.loaders[context.type] = undefined;
+ }
+ this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.NETWORK_ERROR, details: details, fatal: fatal, url: loader.url, loader: loader, response: response, context: context });
+ }
+ }, {
+ key: 'loadtimeout',
+ value: function loadtimeout(stats, context) {
+ var details,
+ fatal,
+ loader = context.loader;
+ switch (context.type) {
+ case 'manifest':
+ details = _errors.ErrorDetails.MANIFEST_LOAD_TIMEOUT;
+ fatal = true;
+ break;
+ case 'level':
+ details = _errors.ErrorDetails.LEVEL_LOAD_TIMEOUT;
+ fatal = false;
+ break;
+ case 'audioTrack':
+ details = _errors.ErrorDetails.AUDIO_TRACK_LOAD_TIMEOUT;
+ fatal = false;
+ break;
+ }
+ if (loader) {
+ loader.abort();
+ this.loaders[context.type] = undefined;
+ }
+ this.hls.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.NETWORK_ERROR, details: details, fatal: fatal, url: loader.url, loader: loader, context: context });
+ }
+ }]);
+
+ return PlaylistLoader;
+ }(_eventHandler2.default);
+
+ exports.default = PlaylistLoader;
+
+ },{"24":24,"25":25,"26":26,"38":38,"43":43,"46":46}],35:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ /**
+ * Generate MP4 Box
+ */
+
+ //import Hex from '../utils/hex';
+
+ var MP4 = function () {
+ function MP4() {
+ _classCallCheck(this, MP4);
+ }
+
+ _createClass(MP4, null, [{
+ key: 'init',
+ value: function init() {
+ MP4.types = {
+ avc1: [], // codingname
+ avcC: [],
+ btrt: [],
+ dinf: [],
+ dref: [],
+ esds: [],
+ ftyp: [],
+ hdlr: [],
+ mdat: [],
+ mdhd: [],
+ mdia: [],
+ mfhd: [],
+ minf: [],
+ moof: [],
+ moov: [],
+ mp4a: [],
+ mvex: [],
+ mvhd: [],
+ sdtp: [],
+ stbl: [],
+ stco: [],
+ stsc: [],
+ stsd: [],
+ stsz: [],
+ stts: [],
+ tfdt: [],
+ tfhd: [],
+ traf: [],
+ trak: [],
+ trun: [],
+ trex: [],
+ tkhd: [],
+ vmhd: [],
+ smhd: []
+ };
+
+ var i;
+ for (i in MP4.types) {
+ if (MP4.types.hasOwnProperty(i)) {
+ MP4.types[i] = [i.charCodeAt(0), i.charCodeAt(1), i.charCodeAt(2), i.charCodeAt(3)];
+ }
+ }
+
+ var videoHdlr = new Uint8Array([0x00, // version 0
+ 0x00, 0x00, 0x00, // flags
+ 0x00, 0x00, 0x00, 0x00, // pre_defined
+ 0x76, 0x69, 0x64, 0x65, // handler_type: 'vide'
+ 0x00, 0x00, 0x00, 0x00, // reserved
+ 0x00, 0x00, 0x00, 0x00, // reserved
+ 0x00, 0x00, 0x00, 0x00, // reserved
+ 0x56, 0x69, 0x64, 0x65, 0x6f, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'VideoHandler'
+ ]);
+
+ var audioHdlr = new Uint8Array([0x00, // version 0
+ 0x00, 0x00, 0x00, // flags
+ 0x00, 0x00, 0x00, 0x00, // pre_defined
+ 0x73, 0x6f, 0x75, 0x6e, // handler_type: 'soun'
+ 0x00, 0x00, 0x00, 0x00, // reserved
+ 0x00, 0x00, 0x00, 0x00, // reserved
+ 0x00, 0x00, 0x00, 0x00, // reserved
+ 0x53, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'SoundHandler'
+ ]);
+
+ MP4.HDLR_TYPES = {
+ 'video': videoHdlr,
+ 'audio': audioHdlr
+ };
+
+ var dref = new Uint8Array([0x00, // version 0
+ 0x00, 0x00, 0x00, // flags
+ 0x00, 0x00, 0x00, 0x01, // entry_count
+ 0x00, 0x00, 0x00, 0x0c, // entry_size
+ 0x75, 0x72, 0x6c, 0x20, // 'url' type
+ 0x00, // version 0
+ 0x00, 0x00, 0x01 // entry_flags
+ ]);
+
+ var stco = new Uint8Array([0x00, // version
+ 0x00, 0x00, 0x00, // flags
+ 0x00, 0x00, 0x00, 0x00 // entry_count
+ ]);
+
+ MP4.STTS = MP4.STSC = MP4.STCO = stco;
+
+ MP4.STSZ = new Uint8Array([0x00, // version
+ 0x00, 0x00, 0x00, // flags
+ 0x00, 0x00, 0x00, 0x00, // sample_size
+ 0x00, 0x00, 0x00, 0x00]);
+ // sample_count
+ MP4.VMHD = new Uint8Array([0x00, // version
+ 0x00, 0x00, 0x01, // flags
+ 0x00, 0x00, // graphicsmode
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // opcolor
+ ]);
+ MP4.SMHD = new Uint8Array([0x00, // version
+ 0x00, 0x00, 0x00, // flags
+ 0x00, 0x00, // balance
+ 0x00, 0x00 // reserved
+ ]);
+
+ MP4.STSD = new Uint8Array([0x00, // version 0
+ 0x00, 0x00, 0x00, // flags
+ 0x00, 0x00, 0x00, 0x01]); // entry_count
+
+ var majorBrand = new Uint8Array([105, 115, 111, 109]); // isom
+ var avc1Brand = new Uint8Array([97, 118, 99, 49]); // avc1
+ var minorVersion = new Uint8Array([0, 0, 0, 1]);
+
+ MP4.FTYP = MP4.box(MP4.types.ftyp, majorBrand, minorVersion, majorBrand, avc1Brand);
+ MP4.DINF = MP4.box(MP4.types.dinf, MP4.box(MP4.types.dref, dref));
+ }
+ }, {
+ key: 'box',
+ value: function box(type) {
+ var payload = Array.prototype.slice.call(arguments, 1),
+ size = 8,
+ i = payload.length,
+ len = i,
+ result;
+ // calculate the total size we need to allocate
+ while (i--) {
+ size += payload[i].byteLength;
+ }
+ result = new Uint8Array(size);
+ result[0] = size >> 24 & 0xff;
+ result[1] = size >> 16 & 0xff;
+ result[2] = size >> 8 & 0xff;
+ result[3] = size & 0xff;
+ result.set(type, 4);
+ // copy the payload into the result
+ for (i = 0, size = 8; i < len; i++) {
+ // copy payload[i] array @ offset size
+ result.set(payload[i], size);
+ size += payload[i].byteLength;
+ }
+ return result;
+ }
+ }, {
+ key: 'hdlr',
+ value: function hdlr(type) {
+ return MP4.box(MP4.types.hdlr, MP4.HDLR_TYPES[type]);
+ }
+ }, {
+ key: 'mdat',
+ value: function mdat(data) {
+ return MP4.box(MP4.types.mdat, data);
+ }
+ }, {
+ key: 'mdhd',
+ value: function mdhd(timescale, duration) {
+ duration *= timescale;
+ return MP4.box(MP4.types.mdhd, new Uint8Array([0x00, // version 0
+ 0x00, 0x00, 0x00, // flags
+ 0x00, 0x00, 0x00, 0x02, // creation_time
+ 0x00, 0x00, 0x00, 0x03, // modification_time
+ timescale >> 24 & 0xFF, timescale >> 16 & 0xFF, timescale >> 8 & 0xFF, timescale & 0xFF, // timescale
+ duration >> 24, duration >> 16 & 0xFF, duration >> 8 & 0xFF, duration & 0xFF, // duration
+ 0x55, 0xc4, // 'und' language (undetermined)
+ 0x00, 0x00]));
+ }
+ }, {
+ key: 'mdia',
+ value: function mdia(track) {
+ return MP4.box(MP4.types.mdia, MP4.mdhd(track.timescale, track.duration), MP4.hdlr(track.type), MP4.minf(track));
+ }
+ }, {
+ key: 'mfhd',
+ value: function mfhd(sequenceNumber) {
+ return MP4.box(MP4.types.mfhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // flags
+ sequenceNumber >> 24, sequenceNumber >> 16 & 0xFF, sequenceNumber >> 8 & 0xFF, sequenceNumber & 0xFF]));
+ }
+ }, {
+ key: 'minf',
+ // sequence_number
+ value: function minf(track) {
+ if (track.type === 'audio') {
+ return MP4.box(MP4.types.minf, MP4.box(MP4.types.smhd, MP4.SMHD), MP4.DINF, MP4.stbl(track));
+ } else {
+ return MP4.box(MP4.types.minf, MP4.box(MP4.types.vmhd, MP4.VMHD), MP4.DINF, MP4.stbl(track));
+ }
+ }
+ }, {
+ key: 'moof',
+ value: function moof(sn, baseMediaDecodeTime, track) {
+ return MP4.box(MP4.types.moof, MP4.mfhd(sn), MP4.traf(track, baseMediaDecodeTime));
+ }
+ /**
+ * @param tracks... (optional) {array} the tracks associated with this movie
+ */
+
+ }, {
+ key: 'moov',
+ value: function moov(tracks) {
+ var i = tracks.length,
+ boxes = [];
+
+ while (i--) {
+ boxes[i] = MP4.trak(tracks[i]);
+ }
+
+ return MP4.box.apply(null, [MP4.types.moov, MP4.mvhd(tracks[0].timescale, tracks[0].duration)].concat(boxes).concat(MP4.mvex(tracks)));
+ }
+ }, {
+ key: 'mvex',
+ value: function mvex(tracks) {
+ var i = tracks.length,
+ boxes = [];
+
+ while (i--) {
+ boxes[i] = MP4.trex(tracks[i]);
+ }
+ return MP4.box.apply(null, [MP4.types.mvex].concat(boxes));
+ }
+ }, {
+ key: 'mvhd',
+ value: function mvhd(timescale, duration) {
+ duration *= timescale;
+ var bytes = new Uint8Array([0x00, // version 0
+ 0x00, 0x00, 0x00, // flags
+ 0x00, 0x00, 0x00, 0x01, // creation_time
+ 0x00, 0x00, 0x00, 0x02, // modification_time
+ timescale >> 24 & 0xFF, timescale >> 16 & 0xFF, timescale >> 8 & 0xFF, timescale & 0xFF, // timescale
+ duration >> 24 & 0xFF, duration >> 16 & 0xFF, duration >> 8 & 0xFF, duration & 0xFF, // duration
+ 0x00, 0x01, 0x00, 0x00, // 1.0 rate
+ 0x01, 0x00, // 1.0 volume
+ 0x00, 0x00, // reserved
+ 0x00, 0x00, 0x00, 0x00, // reserved
+ 0x00, 0x00, 0x00, 0x00, // reserved
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // transformation: unity matrix
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pre_defined
+ 0xff, 0xff, 0xff, 0xff // next_track_ID
+ ]);
+ return MP4.box(MP4.types.mvhd, bytes);
+ }
+ }, {
+ key: 'sdtp',
+ value: function sdtp(track) {
+ var samples = track.samples || [],
+ bytes = new Uint8Array(4 + samples.length),
+ flags,
+ i;
+ // leave the full box header (4 bytes) all zero
+ // write the sample table
+ for (i = 0; i < samples.length; i++) {
+ flags = samples[i].flags;
+ bytes[i + 4] = flags.dependsOn << 4 | flags.isDependedOn << 2 | flags.hasRedundancy;
+ }
+
+ return MP4.box(MP4.types.sdtp, bytes);
+ }
+ }, {
+ key: 'stbl',
+ value: function stbl(track) {
+ return MP4.box(MP4.types.stbl, MP4.stsd(track), MP4.box(MP4.types.stts, MP4.STTS), MP4.box(MP4.types.stsc, MP4.STSC), MP4.box(MP4.types.stsz, MP4.STSZ), MP4.box(MP4.types.stco, MP4.STCO));
+ }
+ }, {
+ key: 'avc1',
+ value: function avc1(track) {
+ var sps = [],
+ pps = [],
+ i,
+ data,
+ len;
+ // assemble the SPSs
+
+ for (i = 0; i < track.sps.length; i++) {
+ data = track.sps[i];
+ len = data.byteLength;
+ sps.push(len >>> 8 & 0xFF);
+ sps.push(len & 0xFF);
+ sps = sps.concat(Array.prototype.slice.call(data)); // SPS
+ }
+
+ // assemble the PPSs
+ for (i = 0; i < track.pps.length; i++) {
+ data = track.pps[i];
+ len = data.byteLength;
+ pps.push(len >>> 8 & 0xFF);
+ pps.push(len & 0xFF);
+ pps = pps.concat(Array.prototype.slice.call(data));
+ }
+
+ var avcc = MP4.box(MP4.types.avcC, new Uint8Array([0x01, // version
+ sps[3], // profile
+ sps[4], // profile compat
+ sps[5], // level
+ 0xfc | 3, // lengthSizeMinusOne, hard-coded to 4 bytes
+ 0xE0 | track.sps.length // 3bit reserved (111) + numOfSequenceParameterSets
+ ].concat(sps).concat([track.pps.length // numOfPictureParameterSets
+ ]).concat(pps))),
+ // "PPS"
+ width = track.width,
+ height = track.height;
+ //console.log('avcc:' + Hex.hexDump(avcc));
+ return MP4.box(MP4.types.avc1, new Uint8Array([0x00, 0x00, 0x00, // reserved
+ 0x00, 0x00, 0x00, // reserved
+ 0x00, 0x01, // data_reference_index
+ 0x00, 0x00, // pre_defined
+ 0x00, 0x00, // reserved
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pre_defined
+ width >> 8 & 0xFF, width & 0xff, // width
+ height >> 8 & 0xFF, height & 0xff, // height
+ 0x00, 0x48, 0x00, 0x00, // horizresolution
+ 0x00, 0x48, 0x00, 0x00, // vertresolution
+ 0x00, 0x00, 0x00, 0x00, // reserved
+ 0x00, 0x01, // frame_count
+ 0x12, 0x64, 0x61, 0x69, 0x6C, //dailymotion/hls.js
+ 0x79, 0x6D, 0x6F, 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x68, 0x6C, 0x73, 0x2E, 0x6A, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // compressorname
+ 0x00, 0x18, // depth = 24
+ 0x11, 0x11]), // pre_defined = -1
+ avcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80, // bufferSizeDB
+ 0x00, 0x2d, 0xc6, 0xc0, // maxBitrate
+ 0x00, 0x2d, 0xc6, 0xc0])) // avgBitrate
+ );
+ }
+ }, {
+ key: 'esds',
+ value: function esds(track) {
+ var configlen = track.config.length;
+ return new Uint8Array([0x00, // version 0
+ 0x00, 0x00, 0x00, // flags
+
+ 0x03, // descriptor_type
+ 0x17 + configlen, // length
+ 0x00, 0x01, //es_id
+ 0x00, // stream_priority
+
+ 0x04, // descriptor_type
+ 0x0f + configlen, // length
+ 0x40, //codec : mpeg4_audio
+ 0x15, // stream_type
+ 0x00, 0x00, 0x00, // buffer_size
+ 0x00, 0x00, 0x00, 0x00, // maxBitrate
+ 0x00, 0x00, 0x00, 0x00, // avgBitrate
+
+ 0x05 // descriptor_type
+ ].concat([configlen]).concat(track.config).concat([0x06, 0x01, 0x02])); // GASpecificConfig)); // length + audio config descriptor
+ }
+ }, {
+ key: 'mp4a',
+ value: function mp4a(track) {
+ var audiosamplerate = track.audiosamplerate;
+ return MP4.box(MP4.types.mp4a, new Uint8Array([0x00, 0x00, 0x00, // reserved
+ 0x00, 0x00, 0x00, // reserved
+ 0x00, 0x01, // data_reference_index
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
+ 0x00, track.channelCount, // channelcount
+ 0x00, 0x10, // sampleSize:16bits
+ 0x00, 0x00, 0x00, 0x00, // reserved2
+ audiosamplerate >> 8 & 0xFF, audiosamplerate & 0xff, //
+ 0x00, 0x00]), MP4.box(MP4.types.esds, MP4.esds(track)));
+ }
+ }, {
+ key: 'stsd',
+ value: function stsd(track) {
+ if (track.type === 'audio') {
+ return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
+ } else {
+ return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
+ }
+ }
+ }, {
+ key: 'tkhd',
+ value: function tkhd(track) {
+ var id = track.id,
+ duration = track.duration * track.timescale,
+ width = track.width,
+ height = track.height;
+ return MP4.box(MP4.types.tkhd, new Uint8Array([0x00, // version 0
+ 0x00, 0x00, 0x07, // flags
+ 0x00, 0x00, 0x00, 0x00, // creation_time
+ 0x00, 0x00, 0x00, 0x00, // modification_time
+ id >> 24 & 0xFF, id >> 16 & 0xFF, id >> 8 & 0xFF, id & 0xFF, // track_ID
+ 0x00, 0x00, 0x00, 0x00, // reserved
+ duration >> 24, duration >> 16 & 0xFF, duration >> 8 & 0xFF, duration & 0xFF, // duration
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved
+ 0x00, 0x00, // layer
+ 0x00, 0x00, // alternate_group
+ 0x00, 0x00, // non-audio track volume
+ 0x00, 0x00, // reserved
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // transformation: unity matrix
+ width >> 8 & 0xFF, width & 0xFF, 0x00, 0x00, // width
+ height >> 8 & 0xFF, height & 0xFF, 0x00, 0x00 // height
+ ]));
+ }
+ }, {
+ key: 'traf',
+ value: function traf(track, baseMediaDecodeTime) {
+ var sampleDependencyTable = MP4.sdtp(track),
+ id = track.id;
+ return MP4.box(MP4.types.traf, MP4.box(MP4.types.tfhd, new Uint8Array([0x00, // version 0
+ 0x00, 0x00, 0x00, // flags
+ id >> 24, id >> 16 & 0XFF, id >> 8 & 0XFF, id & 0xFF])), // track_ID
+ MP4.box(MP4.types.tfdt, new Uint8Array([0x00, // version 0
+ 0x00, 0x00, 0x00, // flags
+ baseMediaDecodeTime >> 24, baseMediaDecodeTime >> 16 & 0XFF, baseMediaDecodeTime >> 8 & 0XFF, baseMediaDecodeTime & 0xFF])), // baseMediaDecodeTime
+ MP4.trun(track, sampleDependencyTable.length + 16 + // tfhd
+ 16 + // tfdt
+ 8 + // traf header
+ 16 + // mfhd
+ 8 + // moof header
+ 8), // mdat header
+ sampleDependencyTable);
+ }
+
+ /**
+ * Generate a track box.
+ * @param track {object} a track definition
+ * @return {Uint8Array} the track box
+ */
+
+ }, {
+ key: 'trak',
+ value: function trak(track) {
+ track.duration = track.duration || 0xffffffff;
+ return MP4.box(MP4.types.trak, MP4.tkhd(track), MP4.mdia(track));
+ }
+ }, {
+ key: 'trex',
+ value: function trex(track) {
+ var id = track.id;
+ return MP4.box(MP4.types.trex, new Uint8Array([0x00, // version 0
+ 0x00, 0x00, 0x00, // flags
+ id >> 24, id >> 16 & 0XFF, id >> 8 & 0XFF, id & 0xFF, // track_ID
+ 0x00, 0x00, 0x00, 0x01, // default_sample_description_index
+ 0x00, 0x00, 0x00, 0x00, // default_sample_duration
+ 0x00, 0x00, 0x00, 0x00, // default_sample_size
+ 0x00, 0x01, 0x00, 0x01 // default_sample_flags
+ ]));
+ }
+ }, {
+ key: 'trun',
+ value: function trun(track, offset) {
+ var samples = track.samples || [],
+ len = samples.length,
+ arraylen = 12 + 16 * len,
+ array = new Uint8Array(arraylen),
+ i,
+ sample,
+ duration,
+ size,
+ flags,
+ cts;
+ offset += 8 + arraylen;
+ array.set([0x00, // version 0
+ 0x00, 0x0f, 0x01, // flags
+ len >>> 24 & 0xFF, len >>> 16 & 0xFF, len >>> 8 & 0xFF, len & 0xFF, // sample_count
+ offset >>> 24 & 0xFF, offset >>> 16 & 0xFF, offset >>> 8 & 0xFF, offset & 0xFF // data_offset
+ ], 0);
+ for (i = 0; i < len; i++) {
+ sample = samples[i];
+ duration = sample.duration;
+ size = sample.size;
+ flags = sample.flags;
+ cts = sample.cts;
+ array.set([duration >>> 24 & 0xFF, duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, // sample_duration
+ size >>> 24 & 0xFF, size >>> 16 & 0xFF, size >>> 8 & 0xFF, size & 0xFF, // sample_size
+ flags.isLeading << 2 | flags.dependsOn, flags.isDependedOn << 6 | flags.hasRedundancy << 4 | flags.paddingValue << 1 | flags.isNonSync, flags.degradPrio & 0xF0 << 8, flags.degradPrio & 0x0F, // sample_flags
+ cts >>> 24 & 0xFF, cts >>> 16 & 0xFF, cts >>> 8 & 0xFF, cts & 0xFF // sample_composition_time_offset
+ ], 12 + 16 * i);
+ }
+ return MP4.box(MP4.types.trun, array);
+ }
+ }, {
+ key: 'initSegment',
+ value: function initSegment(tracks) {
+ if (!MP4.types) {
+ MP4.init();
+ }
+ var movie = MP4.moov(tracks),
+ result;
+ result = new Uint8Array(MP4.FTYP.byteLength + movie.byteLength);
+ result.set(MP4.FTYP);
+ result.set(movie, MP4.FTYP.byteLength);
+ return result;
+ }
+ }]);
+
+ return MP4;
+ }();
+
+ exports.default = MP4;
+
+ },{}],36:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
+ * fMP4 remuxer
+ */
+
+ var _aac = _dereq_(27);
+
+ var _aac2 = _interopRequireDefault(_aac);
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _logger = _dereq_(43);
+
+ var _mp4Generator = _dereq_(35);
+
+ var _mp4Generator2 = _interopRequireDefault(_mp4Generator);
+
+ var _errors = _dereq_(24);
+
+ _dereq_(44);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var MP4Remuxer = function () {
+ function MP4Remuxer(observer, id, config) {
+ _classCallCheck(this, MP4Remuxer);
+
+ this.observer = observer;
+ this.id = id;
+ this.config = config;
+ this.ISGenerated = false;
+ this.PES2MP4SCALEFACTOR = 4;
+ this.PES_TIMESCALE = 90000;
+ this.MP4_TIMESCALE = this.PES_TIMESCALE / this.PES2MP4SCALEFACTOR;
+ }
+
+ _createClass(MP4Remuxer, [{
+ key: 'destroy',
+ value: function destroy() {}
+ }, {
+ key: 'insertDiscontinuity',
+ value: function insertDiscontinuity() {
+ this._initPTS = this._initDTS = undefined;
+ }
+ }, {
+ key: 'switchLevel',
+ value: function switchLevel() {
+ this.ISGenerated = false;
+ }
+ }, {
+ key: 'remux',
+ value: function remux(level, sn, audioTrack, videoTrack, id3Track, textTrack, timeOffset, contiguous, accurateTimeOffset) {
+ this.level = level;
+ this.sn = sn;
+ // generate Init Segment if needed
+ if (!this.ISGenerated) {
+ this.generateIS(audioTrack, videoTrack, timeOffset);
+ }
+
+ if (this.ISGenerated) {
+ // Purposefully remuxing audio before video, so that remuxVideo can use nextAacPts, which is
+ // calculated in remuxAudio.
+ //logger.log('nb AAC samples:' + audioTrack.samples.length);
+ if (audioTrack.samples.length) {
+ var audioData = this.remuxAudio(audioTrack, timeOffset, contiguous, accurateTimeOffset);
+ //logger.log('nb AVC samples:' + videoTrack.samples.length);
+ if (videoTrack.samples.length) {
+ var audioTrackLength = void 0;
+ if (audioData) {
+ audioTrackLength = audioData.endPTS - audioData.startPTS;
+ }
+ this.remuxVideo(videoTrack, timeOffset, contiguous, audioTrackLength);
+ }
+ } else {
+ var videoData = void 0;
+ //logger.log('nb AVC samples:' + videoTrack.samples.length);
+ if (videoTrack.samples.length) {
+ videoData = this.remuxVideo(videoTrack, timeOffset, contiguous);
+ }
+ if (videoData && audioTrack.codec) {
+ this.remuxEmptyAudio(audioTrack, timeOffset, contiguous, videoData);
+ }
+ }
+ }
+ //logger.log('nb ID3 samples:' + audioTrack.samples.length);
+ if (id3Track.samples.length) {
+ this.remuxID3(id3Track, timeOffset);
+ }
+ //logger.log('nb ID3 samples:' + audioTrack.samples.length);
+ if (textTrack.samples.length) {
+ this.remuxText(textTrack, timeOffset);
+ }
+ //notify end of parsing
+ this.observer.trigger(_events2.default.FRAG_PARSED, { id: this.id, level: this.level, sn: this.sn });
+ }
+ }, {
+ key: 'generateIS',
+ value: function generateIS(audioTrack, videoTrack, timeOffset) {
+ var observer = this.observer,
+ audioSamples = audioTrack.samples,
+ videoSamples = videoTrack.samples,
+ pesTimeScale = this.PES_TIMESCALE,
+ tracks = {},
+ data = { id: this.id, level: this.level, sn: this.sn, tracks: tracks, unique: false },
+ computePTSDTS = this._initPTS === undefined,
+ initPTS,
+ initDTS;
+
+ if (computePTSDTS) {
+ initPTS = initDTS = Infinity;
+ }
+ if (audioTrack.config && audioSamples.length) {
+ audioTrack.timescale = audioTrack.audiosamplerate;
+ // MP4 duration (track duration in seconds multiplied by timescale) is coded on 32 bits
+ // we know that each AAC sample contains 1024 frames....
+ // in order to avoid overflowing the 32 bit counter for large duration, we use smaller timescale (timescale/gcd)
+ // we just need to ensure that AAC sample duration will still be an integer (will be 1024/gcd)
+ if (audioTrack.timescale * audioTrack.duration > Math.pow(2, 32)) {
+ (function () {
+ var greatestCommonDivisor = function greatestCommonDivisor(a, b) {
+ if (!b) {
+ return a;
+ }
+ return greatestCommonDivisor(b, a % b);
+ };
+ audioTrack.timescale = audioTrack.audiosamplerate / greatestCommonDivisor(audioTrack.audiosamplerate, 1024);
+ })();
+ }
+ _logger.logger.log('audio mp4 timescale :' + audioTrack.timescale);
+ tracks.audio = {
+ container: 'audio/mp4',
+ codec: audioTrack.codec,
+ initSegment: _mp4Generator2.default.initSegment([audioTrack]),
+ metadata: {
+ channelCount: audioTrack.channelCount
+ }
+ };
+ if (computePTSDTS) {
+ // remember first PTS of this demuxing context. for audio, PTS = DTS
+ initPTS = initDTS = audioSamples[0].pts - pesTimeScale * timeOffset;
+ }
+ }
+
+ if (videoTrack.sps && videoTrack.pps && videoSamples.length) {
+ videoTrack.timescale = this.MP4_TIMESCALE;
+ tracks.video = {
+ container: 'video/mp4',
+ codec: videoTrack.codec,
+ initSegment: _mp4Generator2.default.initSegment([videoTrack]),
+ metadata: {
+ width: videoTrack.width,
+ height: videoTrack.height
+ }
+ };
+ if (computePTSDTS) {
+ initPTS = Math.min(initPTS, videoSamples[0].pts - pesTimeScale * timeOffset);
+ initDTS = Math.min(initDTS, videoSamples[0].dts - pesTimeScale * timeOffset);
+ }
+ }
+
+ if (Object.keys(tracks).length) {
+ observer.trigger(_events2.default.FRAG_PARSING_INIT_SEGMENT, data);
+ this.ISGenerated = true;
+ if (computePTSDTS) {
+ this._initPTS = initPTS;
+ this._initDTS = initDTS;
+ }
+ } else {
+ observer.trigger(_events2.default.ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, id: this.id, details: _errors.ErrorDetails.FRAG_PARSING_ERROR, fatal: false, reason: 'no audio/video samples found' });
+ }
+ }
+ }, {
+ key: 'remuxVideo',
+ value: function remuxVideo(track, timeOffset, contiguous, audioTrackLength) {
+ var offset = 8,
+ pesTimeScale = this.PES_TIMESCALE,
+ pes2mp4ScaleFactor = this.PES2MP4SCALEFACTOR,
+ mp4SampleDuration,
+ mdat,
+ moof,
+ firstPTS,
+ firstDTS,
+ nextDTS,
+ lastPTS,
+ lastDTS,
+ inputSamples = track.samples,
+ outputSamples = [];
+
+ // for (let i = 0; i < track.samples.length; i++) {
+ // let avcSample = track.samples[i];
+ // let units = avcSample.units.units;
+ // let unitsString = '';
+ // for (let j = 0; j < units.length ; j++) {
+ // unitsString += units[j].type + ',';
+ // if (units[j].data.length < 500) {
+ // unitsString += Hex.hexDump(units[j].data);
+ // }
+ // }
+ // logger.log(avcSample.pts + '/' + avcSample.dts + ',' + unitsString + avcSample.units.length);
+ // }
+
+ // handle broken streams with PTS < DTS, tolerance up 200ms (18000 in 90kHz timescale)
+ var PTSDTSshift = inputSamples.reduce(function (prev, curr) {
+ return Math.max(Math.min(prev, curr.pts - curr.dts), -18000);
+ }, 0);
+ if (PTSDTSshift < 0) {
+ _logger.logger.warn('PTS < DTS detected in video samples, shifting DTS by ' + Math.round(PTSDTSshift / 90) + ' ms to overcome this issue');
+ for (var i = 0; i < inputSamples.length; i++) {
+ inputSamples[i].dts += PTSDTSshift;
+ }
+ }
+
+ // PTS is coded on 33bits, and can loop from -2^32 to 2^32
+ // PTSNormalize will make PTS/DTS value monotonic, we use last known DTS value as reference value
+ var nextAvcDts = void 0;
+ // contiguous fragments are consecutive fragments from same quality level (same level, new SN = old SN + 1)
+ if (contiguous) {
+ // if parsed fragment is contiguous with last one, let's use last DTS value as reference
+ nextAvcDts = this.nextAvcDts;
+ } else {
+ // if not contiguous, let's use target timeOffset
+ nextAvcDts = timeOffset * pesTimeScale;
+ }
+
+ // compute first DTS and last DTS, normalize them against reference value
+ var sample = inputSamples[0];
+ firstDTS = Math.max(this._PTSNormalize(sample.dts - this._initDTS, nextAvcDts), 0);
+ firstPTS = Math.max(this._PTSNormalize(sample.pts - this._initDTS, nextAvcDts), 0);
+
+ // check timestamp continuity accross consecutive fragments (this is to remove inter-fragment gap/hole)
+ var delta = Math.round((firstDTS - nextAvcDts) / 90);
+ // if fragment are contiguous, detect hole/overlapping between fragments
+ if (contiguous) {
+ if (delta) {
+ if (delta > 1) {
+ _logger.logger.log('AVC:' + delta + ' ms hole between fragments detected,filling it');
+ } else if (delta < -1) {
+ _logger.logger.log('AVC:' + -delta + ' ms overlapping between fragments detected');
+ }
+ // remove hole/gap : set DTS to next expected DTS
+ firstDTS = nextAvcDts;
+ inputSamples[0].dts = firstDTS + this._initDTS;
+ // offset PTS as well, ensure that PTS is smaller or equal than new DTS
+ firstPTS = Math.max(firstPTS - delta, nextAvcDts);
+ inputSamples[0].pts = firstPTS + this._initDTS;
+ _logger.logger.log('Video/PTS/DTS adjusted: ' + Math.round(firstPTS / 90) + '/' + Math.round(firstDTS / 90) + ',delta:' + delta + ' ms');
+ }
+ }
+ nextDTS = firstDTS;
+
+ // compute lastPTS/lastDTS
+ sample = inputSamples[inputSamples.length - 1];
+ lastDTS = Math.max(this._PTSNormalize(sample.dts - this._initDTS, nextAvcDts), 0);
+ lastPTS = Math.max(this._PTSNormalize(sample.pts - this._initDTS, nextAvcDts), 0);
+ lastPTS = Math.max(lastPTS, lastDTS);
+
+ var vendor = navigator.vendor,
+ userAgent = navigator.userAgent,
+ isSafari = vendor && vendor.indexOf('Apple') > -1 && userAgent && !userAgent.match('CriOS');
+
+ // on Safari let's signal the same sample duration for all samples
+ // sample duration (as expected by trun MP4 boxes), should be the delta between sample DTS
+ // set this constant duration as being the avg delta between consecutive DTS.
+ if (isSafari) {
+ mp4SampleDuration = Math.round((lastDTS - firstDTS) / (pes2mp4ScaleFactor * (inputSamples.length - 1)));
+ }
+
+ // normalize all PTS/DTS now ...
+ for (var _i = 0; _i < inputSamples.length; _i++) {
+ var _sample = inputSamples[_i];
+ if (isSafari) {
+ // sample DTS is computed using a constant decoding offset (mp4SampleDuration) between samples
+ _sample.dts = firstDTS + _i * pes2mp4ScaleFactor * mp4SampleDuration;
+ } else {
+ // ensure sample monotonic DTS
+ _sample.dts = Math.max(this._PTSNormalize(_sample.dts - this._initDTS, nextAvcDts), firstDTS);
+ // ensure dts is a multiple of scale factor to avoid rounding issues
+ _sample.dts = Math.round(_sample.dts / pes2mp4ScaleFactor) * pes2mp4ScaleFactor;
+ }
+ // we normalize PTS against nextAvcDts, we also substract initDTS (some streams don't start @ PTS O)
+ // and we ensure that computed value is greater or equal than sample DTS
+ _sample.pts = Math.max(this._PTSNormalize(_sample.pts - this._initDTS, nextAvcDts), _sample.dts);
+ // ensure pts is a multiple of scale factor to avoid rounding issues
+ _sample.pts = Math.round(_sample.pts / pes2mp4ScaleFactor) * pes2mp4ScaleFactor;
+ }
+
+ /* concatenate the video data and construct the mdat in place
+ (need 8 more bytes to fill length and mpdat type) */
+ mdat = new Uint8Array(track.len + 4 * track.nbNalu + 8);
+ var view = new DataView(mdat.buffer);
+ view.setUint32(0, mdat.byteLength);
+ mdat.set(_mp4Generator2.default.types.mdat, 4);
+
+ for (var _i2 = 0; _i2 < inputSamples.length; _i2++) {
+ var avcSample = inputSamples[_i2],
+ mp4SampleLength = 0,
+ compositionTimeOffset = void 0;
+ // convert NALU bitstream to MP4 format (prepend NALU with size field)
+ while (avcSample.units.units.length) {
+ var unit = avcSample.units.units.shift();
+ view.setUint32(offset, unit.data.byteLength);
+ offset += 4;
+ mdat.set(unit.data, offset);
+ offset += unit.data.byteLength;
+ mp4SampleLength += 4 + unit.data.byteLength;
+ }
+
+ if (!isSafari) {
+ // expected sample duration is the Decoding Timestamp diff of consecutive samples
+ if (_i2 < inputSamples.length - 1) {
+ mp4SampleDuration = inputSamples[_i2 + 1].dts - avcSample.dts;
+ } else {
+ var config = this.config,
+ lastFrameDuration = avcSample.dts - inputSamples[_i2 > 0 ? _i2 - 1 : _i2].dts;
+ if (config.stretchShortVideoTrack) {
+ // In some cases, a segment's audio track duration may exceed the video track duration.
+ // Since we've already remuxed audio, and we know how long the audio track is, we look to
+ // see if the delta to the next segment is longer than the minimum of maxBufferHole and
+ // maxSeekHole. If so, playback would potentially get stuck, so we artificially inflate
+ // the duration of the last frame to minimize any potential gap between segments.
+ var maxBufferHole = config.maxBufferHole,
+ maxSeekHole = config.maxSeekHole,
+ gapTolerance = Math.floor(Math.min(maxBufferHole, maxSeekHole) * pesTimeScale),
+ deltaToFrameEnd = (audioTrackLength ? firstPTS + audioTrackLength * pesTimeScale : this.nextAacPts) - avcSample.pts;
+ if (deltaToFrameEnd > gapTolerance) {
+ // We subtract lastFrameDuration from deltaToFrameEnd to try to prevent any video
+ // frame overlap. maxBufferHole/maxSeekHole should be >> lastFrameDuration anyway.
+ mp4SampleDuration = deltaToFrameEnd - lastFrameDuration;
+ if (mp4SampleDuration < 0) {
+ mp4SampleDuration = lastFrameDuration;
+ }
+ _logger.logger.log('It is approximately ' + deltaToFrameEnd / 90 + ' ms to the next segment; using duration ' + mp4SampleDuration / 90 + ' ms for the last video frame.');
+ } else {
+ mp4SampleDuration = lastFrameDuration;
+ }
+ } else {
+ mp4SampleDuration = lastFrameDuration;
+ }
+ }
+ mp4SampleDuration /= pes2mp4ScaleFactor;
+ compositionTimeOffset = Math.round((avcSample.pts - avcSample.dts) / pes2mp4ScaleFactor);
+ } else {
+ compositionTimeOffset = Math.max(0, mp4SampleDuration * Math.round((avcSample.pts - avcSample.dts) / (pes2mp4ScaleFactor * mp4SampleDuration)));
+ }
+
+ //console.log('PTS/DTS/initDTS/normPTS/normDTS/relative PTS : ${avcSample.pts}/${avcSample.dts}/${this._initDTS}/${ptsnorm}/${dtsnorm}/${(avcSample.pts/4294967296).toFixed(3)}');
+ outputSamples.push({
+ size: mp4SampleLength,
+ // constant duration
+ duration: mp4SampleDuration,
+ cts: compositionTimeOffset,
+ flags: {
+ isLeading: 0,
+ isDependedOn: 0,
+ hasRedundancy: 0,
+ degradPrio: 0,
+ dependsOn: avcSample.key ? 2 : 1,
+ isNonSync: avcSample.key ? 0 : 1
+ }
+ });
+ }
+ // next AVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
+ this.nextAvcDts = lastDTS + mp4SampleDuration * pes2mp4ScaleFactor;
+ var dropped = track.dropped;
+ track.len = 0;
+ track.nbNalu = 0;
+ track.dropped = 0;
+ if (outputSamples.length && navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
+ var flags = outputSamples[0].flags;
+ // chrome workaround, mark first sample as being a Random Access Point to avoid sourcebuffer append issue
+ // https://code.google.com/p/chromium/issues/detail?id=229412
+ flags.dependsOn = 2;
+ flags.isNonSync = 0;
+ }
+ track.samples = outputSamples;
+ moof = _mp4Generator2.default.moof(track.sequenceNumber++, firstDTS / pes2mp4ScaleFactor, track);
+ track.samples = [];
+
+ var data = {
+ id: this.id,
+ level: this.level,
+ sn: this.sn,
+ data1: moof,
+ data2: mdat,
+ startPTS: firstPTS / pesTimeScale,
+ endPTS: (lastPTS + pes2mp4ScaleFactor * mp4SampleDuration) / pesTimeScale,
+ startDTS: firstDTS / pesTimeScale,
+ endDTS: this.nextAvcDts / pesTimeScale,
+ type: 'video',
+ nb: outputSamples.length,
+ dropped: dropped
+ };
+ this.observer.trigger(_events2.default.FRAG_PARSING_DATA, data);
+ return data;
+ }
+ }, {
+ key: 'remuxAudio',
+ value: function remuxAudio(track, timeOffset, contiguous, accurateTimeOffset) {
+ var pesTimeScale = this.PES_TIMESCALE,
+ mp4timeScale = track.timescale,
+ pes2mp4ScaleFactor = pesTimeScale / mp4timeScale,
+ expectedSampleDuration = track.timescale * 1024 / track.audiosamplerate;
+ var view,
+ offset = 8,
+ aacSample,
+ mp4Sample,
+ unit,
+ mdat,
+ moof,
+ firstPTS,
+ firstDTS,
+ lastDTS,
+ pts,
+ dts,
+ ptsnorm,
+ dtsnorm,
+ samples = [],
+ samples0 = [],
+ fillFrame,
+ newStamp;
+
+ track.samples.sort(function (a, b) {
+ return a.pts - b.pts;
+ });
+ samples0 = track.samples;
+
+ // for audio samples, also consider consecutive fragments as being contiguous (even if a level switch occurs),
+ // for sake of clarity:
+ // consecutive fragments are frags with less than 100ms gaps between new time offset and next expected PTS
+ // contiguous fragments are consecutive fragments from same quality level (same level, new SN = old SN + 1)
+ // this helps ensuring audio continuity
+ // and this also avoids audio glitches/cut when switching quality, or reporting wrong duration on first audio frame
+
+ contiguous |= samples0.length && this.nextAacPts && Math.abs(timeOffset - this.nextAacPts / pesTimeScale) < 0.1;
+
+ var nextAacPts = contiguous ? this.nextAacPts : timeOffset * pesTimeScale;
+
+ // If the audio track is missing samples, the frames seem to get "left-shifted" within the
+ // resulting mp4 segment, causing sync issues and leaving gaps at the end of the audio segment.
+ // In an effort to prevent this from happening, we inject frames here where there are gaps.
+ // When possible, we inject a silent frame; when that's not possible, we duplicate the last
+ // frame.
+ var pesFrameDuration = expectedSampleDuration * pes2mp4ScaleFactor;
+ var nextPtsNorm = nextAacPts;
+
+ // only inject/drop audio frames in case time offset is accurate
+ if (accurateTimeOffset) {
+ for (var i = 0; i < samples0.length;) {
+ // First, let's see how far off this frame is from where we expect it to be
+ var sample = samples0[i],
+ ptsNorm = this._PTSNormalize(sample.pts - this._initDTS, nextAacPts),
+ delta = ptsNorm - nextPtsNorm;
+
+ // If we're overlapping by more than a duration, drop this sample
+ if (delta <= -pesFrameDuration) {
+ _logger.logger.warn('Dropping 1 audio frame @ ' + Math.round(nextPtsNorm / 90) / 1000 + 's due to ' + Math.round(Math.abs(delta / 90)) + ' ms overlap.');
+ samples0.splice(i, 1);
+ track.len -= sample.unit.length;
+ // Don't touch nextPtsNorm or i
+ }
+ // Otherwise, if we're more than a frame away from where we should be, insert missing frames
+ else if (delta >= pesFrameDuration) {
+ var missing = Math.round(delta / pesFrameDuration);
+ _logger.logger.warn('Injecting ' + missing + ' audio frame @ ' + Math.round(nextPtsNorm / 90) / 1000 + 's due to ' + Math.round(delta / 90) + ' ms gap.');
+ for (var j = 0; j < missing; j++) {
+ newStamp = nextPtsNorm + this._initDTS;
+ newStamp = Math.max(newStamp, this._initDTS);
+ fillFrame = _aac2.default.getSilentFrame(track.channelCount);
+ if (!fillFrame) {
+ _logger.logger.log('Unable to get silent frame for given audio codec; duplicating last frame instead.');
+ fillFrame = sample.unit.slice(0);
+ }
+ samples0.splice(i, 0, { unit: fillFrame, pts: newStamp, dts: newStamp });
+ track.len += fillFrame.length;
+ nextPtsNorm += pesFrameDuration;
+ i += 1;
+ }
+
+ // Adjust sample to next expected pts
+ sample.pts = sample.dts = nextPtsNorm + this._initDTS;
+ nextPtsNorm += pesFrameDuration;
+ i += 1;
+ }
+ // Otherwise, we're within half a frame duration, so just adjust pts
+ else {
+ if (Math.abs(delta) > 0.1 * pesFrameDuration) {
+ //logger.log(`Invalid frame delta ${Math.round(ptsNorm - nextPtsNorm + pesFrameDuration)} at PTS ${Math.round(ptsNorm / 90)} (should be ${Math.round(pesFrameDuration)}).`);
+ }
+ nextPtsNorm += pesFrameDuration;
+ if (i === 0) {
+ sample.pts = sample.dts = this._initDTS + nextAacPts;
+ } else {
+ sample.pts = sample.dts = samples0[i - 1].pts + pesFrameDuration;
+ }
+ i += 1;
+ }
+ }
+ }
+
+ while (samples0.length) {
+ aacSample = samples0.shift();
+ unit = aacSample.unit;
+ pts = aacSample.pts - this._initDTS;
+ dts = aacSample.dts - this._initDTS;
+ //logger.log(`Audio/PTS:${Math.round(pts/90)}`);
+ // if not first sample
+ if (lastDTS !== undefined) {
+ ptsnorm = this._PTSNormalize(pts, lastDTS);
+ dtsnorm = this._PTSNormalize(dts, lastDTS);
+ mp4Sample.duration = Math.round((dtsnorm - lastDTS) / pes2mp4ScaleFactor);
+ } else {
+ ptsnorm = this._PTSNormalize(pts, nextAacPts);
+ dtsnorm = this._PTSNormalize(dts, nextAacPts);
+ var _delta = Math.round(1000 * (ptsnorm - nextAacPts) / pesTimeScale),
+ numMissingFrames = 0;
+ // if fragment are contiguous, detect hole/overlapping between fragments
+ // contiguous fragments are consecutive fragments from same quality level (same level, new SN = old SN + 1)
+ if (contiguous) {
+ // log delta
+ if (_delta) {
+ if (_delta > 0) {
+ numMissingFrames = Math.round((ptsnorm - nextAacPts) / pesFrameDuration);
+ _logger.logger.log(_delta + ' ms hole between AAC samples detected,filling it');
+ if (numMissingFrames > 0) {
+ fillFrame = _aac2.default.getSilentFrame(track.channelCount);
+ if (!fillFrame) {
+ fillFrame = unit.slice(0);
+ }
+ track.len += numMissingFrames * fillFrame.length;
+ }
+ // if we have frame overlap, overlapping for more than half a frame duraion
+ } else if (_delta < -12) {
+ // drop overlapping audio frames... browser will deal with it
+ _logger.logger.log(-_delta + ' ms overlapping between AAC samples detected, drop frame');
+ track.len -= unit.byteLength;
+ continue;
+ }
+ // set PTS/DTS to expected PTS/DTS
+ ptsnorm = dtsnorm = nextAacPts;
+ }
+ }
+ // remember first PTS of our aacSamples, ensure value is positive
+ firstPTS = Math.max(0, ptsnorm);
+ firstDTS = Math.max(0, dtsnorm);
+ if (track.len > 0) {
+ /* concatenate the audio data and construct the mdat in place
+ (need 8 more bytes to fill length and mdat type) */
+ mdat = new Uint8Array(track.len + 8);
+ view = new DataView(mdat.buffer);
+ view.setUint32(0, mdat.byteLength);
+ mdat.set(_mp4Generator2.default.types.mdat, 4);
+ } else {
+ // no audio samples
+ return;
+ }
+ for (var _i3 = 0; _i3 < numMissingFrames; _i3++) {
+ newStamp = ptsnorm - (numMissingFrames - _i3) * pesFrameDuration;
+ fillFrame = _aac2.default.getSilentFrame(track.channelCount);
+ if (!fillFrame) {
+ _logger.logger.log('Unable to get silent frame for given audio codec; duplicating this frame instead.');
+ fillFrame = unit.slice(0);
+ }
+ mdat.set(fillFrame, offset);
+ offset += fillFrame.byteLength;
+ mp4Sample = {
+ size: fillFrame.byteLength,
+ cts: 0,
+ duration: 1024,
+ flags: {
+ isLeading: 0,
+ isDependedOn: 0,
+ hasRedundancy: 0,
+ degradPrio: 0,
+ dependsOn: 1
+ }
+ };
+ samples.push(mp4Sample);
+ }
+ }
+ mdat.set(unit, offset);
+ offset += unit.byteLength;
+ //console.log('PTS/DTS/initDTS/normPTS/normDTS/relative PTS : ${aacSample.pts}/${aacSample.dts}/${this._initDTS}/${ptsnorm}/${dtsnorm}/${(aacSample.pts/4294967296).toFixed(3)}');
+ mp4Sample = {
+ size: unit.byteLength,
+ cts: 0,
+ duration: 0,
+ flags: {
+ isLeading: 0,
+ isDependedOn: 0,
+ hasRedundancy: 0,
+ degradPrio: 0,
+ dependsOn: 1
+ }
+ };
+ samples.push(mp4Sample);
+ lastDTS = dtsnorm;
+ }
+ var lastSampleDuration = 0;
+ var nbSamples = samples.length;
+ //set last sample duration as being identical to previous sample
+ if (nbSamples >= 2) {
+ lastSampleDuration = samples[nbSamples - 2].duration;
+ mp4Sample.duration = lastSampleDuration;
+ }
+ if (nbSamples) {
+ // next aac sample PTS should be equal to last sample PTS + duration
+ this.nextAacPts = ptsnorm + pes2mp4ScaleFactor * lastSampleDuration;
+ //logger.log('Audio/PTS/PTSend:' + aacSample.pts.toFixed(0) + '/' + this.nextAacDts.toFixed(0));
+ track.len = 0;
+ track.samples = samples;
+ moof = _mp4Generator2.default.moof(track.sequenceNumber++, firstDTS / pes2mp4ScaleFactor, track);
+ track.samples = [];
+ var audioData = {
+ id: this.id,
+ level: this.level,
+ sn: this.sn,
+ data1: moof,
+ data2: mdat,
+ startPTS: firstPTS / pesTimeScale,
+ endPTS: this.nextAacPts / pesTimeScale,
+ startDTS: firstDTS / pesTimeScale,
+ endDTS: (dtsnorm + pes2mp4ScaleFactor * lastSampleDuration) / pesTimeScale,
+ type: 'audio',
+ nb: nbSamples
+ };
+ this.observer.trigger(_events2.default.FRAG_PARSING_DATA, audioData);
+ return audioData;
+ }
+ return null;
+ }
+ }, {
+ key: 'remuxEmptyAudio',
+ value: function remuxEmptyAudio(track, timeOffset, contiguous, videoData) {
+ var pesTimeScale = this.PES_TIMESCALE,
+ mp4timeScale = track.timescale ? track.timescale : track.audiosamplerate,
+ pes2mp4ScaleFactor = pesTimeScale / mp4timeScale,
+
+
+ // sync with video's timestamp
+ startDTS = videoData.startDTS * pesTimeScale + this._initDTS,
+ endDTS = videoData.endDTS * pesTimeScale + this._initDTS,
+
+
+ // one sample's duration value
+ sampleDuration = 1024,
+ frameDuration = pes2mp4ScaleFactor * sampleDuration,
+
+
+ // samples count of this segment's duration
+ nbSamples = Math.ceil((endDTS - startDTS) / frameDuration),
+
+
+ // silent frame
+ silentFrame = _aac2.default.getSilentFrame(track.channelCount);
+
+ // Can't remux if we can't generate a silent frame...
+ if (!silentFrame) {
+ _logger.logger.trace('Unable to remuxEmptyAudio since we were unable to get a silent frame for given audio codec!');
+ return;
+ }
+
+ var samples = [];
+ for (var i = 0; i < nbSamples; i++) {
+ var stamp = startDTS + i * frameDuration;
+ samples.push({ unit: silentFrame.slice(0), pts: stamp, dts: stamp });
+ track.len += silentFrame.length;
+ }
+ track.samples = samples;
+
+ this.remuxAudio(track, timeOffset, contiguous);
+ }
+ }, {
+ key: 'remuxID3',
+ value: function remuxID3(track, timeOffset) {
+ var length = track.samples.length,
+ sample;
+ // consume samples
+ if (length) {
+ for (var index = 0; index < length; index++) {
+ sample = track.samples[index];
+ // setting id3 pts, dts to relative time
+ // using this._initPTS and this._initDTS to calculate relative time
+ sample.pts = (sample.pts - this._initPTS) / this.PES_TIMESCALE;
+ sample.dts = (sample.dts - this._initDTS) / this.PES_TIMESCALE;
+ }
+ this.observer.trigger(_events2.default.FRAG_PARSING_METADATA, {
+ id: this.id,
+ level: this.level,
+ sn: this.sn,
+ samples: track.samples
+ });
+ }
+
+ track.samples = [];
+ timeOffset = timeOffset;
+ }
+ }, {
+ key: 'remuxText',
+ value: function remuxText(track, timeOffset) {
+ track.samples.sort(function (a, b) {
+ return a.pts - b.pts;
+ });
+
+ var length = track.samples.length,
+ sample;
+ // consume samples
+ if (length) {
+ for (var index = 0; index < length; index++) {
+ sample = track.samples[index];
+ // setting text pts, dts to relative time
+ // using this._initPTS and this._initDTS to calculate relative time
+ sample.pts = (sample.pts - this._initPTS) / this.PES_TIMESCALE;
+ }
+ this.observer.trigger(_events2.default.FRAG_PARSING_USERDATA, {
+ id: this.id,
+ level: this.level,
+ sn: this.sn,
+ samples: track.samples
+ });
+ }
+
+ track.samples = [];
+ timeOffset = timeOffset;
+ }
+ }, {
+ key: '_PTSNormalize',
+ value: function _PTSNormalize(value, reference) {
+ var offset;
+ if (reference === undefined) {
+ return value;
+ }
+ if (reference < value) {
+ // - 2^33
+ offset = -8589934592;
+ } else {
+ // + 2^33
+ offset = 8589934592;
+ }
+ /* PTS is 33bit (from 0 to 2^33 -1)
+ if diff between value and reference is bigger than half of the amplitude (2^32) then it means that
+ PTS looping occured. fill the gap */
+ while (Math.abs(value - reference) > 4294967296) {
+ value += offset;
+ }
+ return value;
+ }
+ }, {
+ key: 'passthrough',
+ get: function get() {
+ return false;
+ }
+ }]);
+
+ return MP4Remuxer;
+ }();
+
+ exports.default = MP4Remuxer;
+
+ },{"24":24,"26":26,"27":27,"35":35,"43":43,"44":44}],37:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
+ * passthrough remuxer
+ */
+
+
+ var _events = _dereq_(26);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var PassThroughRemuxer = function () {
+ function PassThroughRemuxer(observer, id) {
+ _classCallCheck(this, PassThroughRemuxer);
+
+ this.observer = observer;
+ this.id = id;
+ this.ISGenerated = false;
+ }
+
+ _createClass(PassThroughRemuxer, [{
+ key: 'destroy',
+ value: function destroy() {}
+ }, {
+ key: 'insertDiscontinuity',
+ value: function insertDiscontinuity() {}
+ }, {
+ key: 'switchLevel',
+ value: function switchLevel() {
+ this.ISGenerated = false;
+ }
+ }, {
+ key: 'remux',
+ value: function remux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, rawData) {
+ var observer = this.observer;
+ // generate Init Segment if needed
+ if (!this.ISGenerated) {
+ var tracks = {},
+ data = { id: this.id, tracks: tracks, unique: true },
+ track = videoTrack,
+ codec = track.codec;
+
+ if (codec) {
+ data.tracks.video = {
+ container: track.container,
+ codec: codec,
+ metadata: {
+ width: track.width,
+ height: track.height
+ }
+ };
+ }
+
+ track = audioTrack;
+ codec = track.codec;
+ if (codec) {
+ data.tracks.audio = {
+ container: track.container,
+ codec: codec,
+ metadata: {
+ channelCount: track.channelCount
+ }
+ };
+ }
+ this.ISGenerated = true;
+ observer.trigger(_events2.default.FRAG_PARSING_INIT_SEGMENT, data);
+ }
+ observer.trigger(_events2.default.FRAG_PARSING_DATA, {
+ id: this.id,
+ data1: rawData,
+ startPTS: timeOffset,
+ startDTS: timeOffset,
+ type: 'audiovideo',
+ nb: 1,
+ dropped: 0
+ });
+ }
+ }, {
+ key: 'passthrough',
+ get: function get() {
+ return true;
+ }
+ }]);
+
+ return PassThroughRemuxer;
+ }();
+
+ exports.default = PassThroughRemuxer;
+
+ },{"26":26}],38:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ // adapted from https://github.com/kanongil/node-m3u8parse/blob/master/attrlist.js
+
+ var AttrList = function () {
+ function AttrList(attrs) {
+ _classCallCheck(this, AttrList);
+
+ if (typeof attrs === 'string') {
+ attrs = AttrList.parseAttrList(attrs);
+ }
+ for (var attr in attrs) {
+ if (attrs.hasOwnProperty(attr)) {
+ this[attr] = attrs[attr];
+ }
+ }
+ }
+
+ _createClass(AttrList, [{
+ key: 'decimalInteger',
+ value: function decimalInteger(attrName) {
+ var intValue = parseInt(this[attrName], 10);
+ if (intValue > Number.MAX_SAFE_INTEGER) {
+ return Infinity;
+ }
+ return intValue;
+ }
+ }, {
+ key: 'hexadecimalInteger',
+ value: function hexadecimalInteger(attrName) {
+ if (this[attrName]) {
+ var stringValue = (this[attrName] || '0x').slice(2);
+ stringValue = (stringValue.length & 1 ? '0' : '') + stringValue;
+
+ var value = new Uint8Array(stringValue.length / 2);
+ for (var i = 0; i < stringValue.length / 2; i++) {
+ value[i] = parseInt(stringValue.slice(i * 2, i * 2 + 2), 16);
+ }
+ return value;
+ } else {
+ return null;
+ }
+ }
+ }, {
+ key: 'hexadecimalIntegerAsNumber',
+ value: function hexadecimalIntegerAsNumber(attrName) {
+ var intValue = parseInt(this[attrName], 16);
+ if (intValue > Number.MAX_SAFE_INTEGER) {
+ return Infinity;
+ }
+ return intValue;
+ }
+ }, {
+ key: 'decimalFloatingPoint',
+ value: function decimalFloatingPoint(attrName) {
+ return parseFloat(this[attrName]);
+ }
+ }, {
+ key: 'enumeratedString',
+ value: function enumeratedString(attrName) {
+ return this[attrName];
+ }
+ }, {
+ key: 'decimalResolution',
+ value: function decimalResolution(attrName) {
+ var res = /^(\d+)x(\d+)$/.exec(this[attrName]);
+ if (res === null) {
+ return undefined;
+ }
+ return {
+ width: parseInt(res[1], 10),
+ height: parseInt(res[2], 10)
+ };
+ }
+ }], [{
+ key: 'parseAttrList',
+ value: function parseAttrList(input) {
+ var re = /\s*(.+?)\s*=((?:\".*?\")|.*?)(?:,|$)/g;
+ var match,
+ attrs = {};
+ while ((match = re.exec(input)) !== null) {
+ var value = match[2],
+ quote = '"';
+
+ if (value.indexOf(quote) === 0 && value.lastIndexOf(quote) === value.length - 1) {
+ value = value.slice(1, -1);
+ }
+ attrs[match[1]] = value;
+ }
+ return attrs;
+ }
+ }]);
+
+ return AttrList;
+ }();
+
+ exports.default = AttrList;
+
+ },{}],39:[function(_dereq_,module,exports){
+ "use strict";
+
+ var BinarySearch = {
+ /**
+ * Searches for an item in an array which matches a certain condition.
+ * This requires the condition to only match one item in the array,
+ * and for the array to be ordered.
+ *
+ * @param {Array} list The array to search.
+ * @param {Function} comparisonFunction
+ * Called and provided a candidate item as the first argument.
+ * Should return:
+ * > -1 if the item should be located at a lower index than the provided item.
+ * > 1 if the item should be located at a higher index than the provided item.
+ * > 0 if the item is the item you're looking for.
+ *
+ * @return {*} The object if it is found or null otherwise.
+ */
+ search: function search(list, comparisonFunction) {
+ var minIndex = 0;
+ var maxIndex = list.length - 1;
+ var currentIndex = null;
+ var currentElement = null;
+
+ while (minIndex <= maxIndex) {
+ currentIndex = (minIndex + maxIndex) / 2 | 0;
+ currentElement = list[currentIndex];
+
+ var comparisonResult = comparisonFunction(currentElement);
+ if (comparisonResult > 0) {
+ minIndex = currentIndex + 1;
+ } else if (comparisonResult < 0) {
+ maxIndex = currentIndex - 1;
+ } else {
+ return currentElement;
+ }
+ }
+
+ return null;
+ }
+ };
+
+ module.exports = BinarySearch;
+
+ },{}],40:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ /**
+ *
+ * This code was ported from the dash.js project at:
+ * https://github.com/Dash-Industry-Forum/dash.js/blob/development/externals/cea608-parser.js
+ * https://github.com/Dash-Industry-Forum/dash.js/commit/8269b26a761e0853bb21d78780ed945144ecdd4d#diff-71bc295a2d6b6b7093a1d3290d53a4b2
+ *
+ * The original copyright appears below:
+ *
+ * The copyright in this software is being made available under the BSD License,
+ * included below. This software may be subject to other third party and contributor
+ * rights, including patent rights, and no such rights are granted under this license.
+ *
+ * Copyright (c) 2015-2016, DASH Industry Forum.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * 2. Neither the name of Dash Industry Forum nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ /**
+ * Exceptions from regular ASCII. CodePoints are mapped to UTF-16 codes
+ */
+
+ var specialCea608CharsCodes = {
+ 0x2a: 0xe1, // lowercase a, acute accent
+ 0x5c: 0xe9, // lowercase e, acute accent
+ 0x5e: 0xed, // lowercase i, acute accent
+ 0x5f: 0xf3, // lowercase o, acute accent
+ 0x60: 0xfa, // lowercase u, acute accent
+ 0x7b: 0xe7, // lowercase c with cedilla
+ 0x7c: 0xf7, // division symbol
+ 0x7d: 0xd1, // uppercase N tilde
+ 0x7e: 0xf1, // lowercase n tilde
+ 0x7f: 0x2588, // Full block
+ // THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
+ // THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F
+ // THIS MEANS THAT \x50 MUST BE ADDED TO THE VALUES
+ 0x80: 0xae, // Registered symbol (R)
+ 0x81: 0xb0, // degree sign
+ 0x82: 0xbd, // 1/2 symbol
+ 0x83: 0xbf, // Inverted (open) question mark
+ 0x84: 0x2122, // Trademark symbol (TM)
+ 0x85: 0xa2, // Cents symbol
+ 0x86: 0xa3, // Pounds sterling
+ 0x87: 0x266a, // Music 8'th note
+ 0x88: 0xe0, // lowercase a, grave accent
+ 0x89: 0x20, // transparent space (regular)
+ 0x8a: 0xe8, // lowercase e, grave accent
+ 0x8b: 0xe2, // lowercase a, circumflex accent
+ 0x8c: 0xea, // lowercase e, circumflex accent
+ 0x8d: 0xee, // lowercase i, circumflex accent
+ 0x8e: 0xf4, // lowercase o, circumflex accent
+ 0x8f: 0xfb, // lowercase u, circumflex accent
+ // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
+ // THAT COME FROM HI BYTE=0x12 AND LOW BETWEEN 0x20 AND 0x3F
+ 0x90: 0xc1, // capital letter A with acute
+ 0x91: 0xc9, // capital letter E with acute
+ 0x92: 0xd3, // capital letter O with acute
+ 0x93: 0xda, // capital letter U with acute
+ 0x94: 0xdc, // capital letter U with diaresis
+ 0x95: 0xfc, // lowercase letter U with diaeresis
+ 0x96: 0x2018, // opening single quote
+ 0x97: 0xa1, // inverted exclamation mark
+ 0x98: 0x2a, // asterisk
+ 0x99: 0x2019, // closing single quote
+ 0x9a: 0x2501, // box drawings heavy horizontal
+ 0x9b: 0xa9, // copyright sign
+ 0x9c: 0x2120, // Service mark
+ 0x9d: 0x2022, // (round) bullet
+ 0x9e: 0x201c, // Left double quotation mark
+ 0x9f: 0x201d, // Right double quotation mark
+ 0xa0: 0xc0, // uppercase A, grave accent
+ 0xa1: 0xc2, // uppercase A, circumflex
+ 0xa2: 0xc7, // uppercase C with cedilla
+ 0xa3: 0xc8, // uppercase E, grave accent
+ 0xa4: 0xca, // uppercase E, circumflex
+ 0xa5: 0xcb, // capital letter E with diaresis
+ 0xa6: 0xeb, // lowercase letter e with diaresis
+ 0xa7: 0xce, // uppercase I, circumflex
+ 0xa8: 0xcf, // uppercase I, with diaresis
+ 0xa9: 0xef, // lowercase i, with diaresis
+ 0xaa: 0xd4, // uppercase O, circumflex
+ 0xab: 0xd9, // uppercase U, grave accent
+ 0xac: 0xf9, // lowercase u, grave accent
+ 0xad: 0xdb, // uppercase U, circumflex
+ 0xae: 0xab, // left-pointing double angle quotation mark
+ 0xaf: 0xbb, // right-pointing double angle quotation mark
+ // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS
+ // THAT COME FROM HI BYTE=0x13 AND LOW BETWEEN 0x20 AND 0x3F
+ 0xb0: 0xc3, // Uppercase A, tilde
+ 0xb1: 0xe3, // Lowercase a, tilde
+ 0xb2: 0xcd, // Uppercase I, acute accent
+ 0xb3: 0xcc, // Uppercase I, grave accent
+ 0xb4: 0xec, // Lowercase i, grave accent
+ 0xb5: 0xd2, // Uppercase O, grave accent
+ 0xb6: 0xf2, // Lowercase o, grave accent
+ 0xb7: 0xd5, // Uppercase O, tilde
+ 0xb8: 0xf5, // Lowercase o, tilde
+ 0xb9: 0x7b, // Open curly brace
+ 0xba: 0x7d, // Closing curly brace
+ 0xbb: 0x5c, // Backslash
+ 0xbc: 0x5e, // Caret
+ 0xbd: 0x5f, // Underscore
+ 0xbe: 0x7c, // Pipe (vertical line)
+ 0xbf: 0x223c, // Tilde operator
+ 0xc0: 0xc4, // Uppercase A, umlaut
+ 0xc1: 0xe4, // Lowercase A, umlaut
+ 0xc2: 0xd6, // Uppercase O, umlaut
+ 0xc3: 0xf6, // Lowercase o, umlaut
+ 0xc4: 0xdf, // Esszett (sharp S)
+ 0xc5: 0xa5, // Yen symbol
+ 0xc6: 0xa4, // Generic currency sign
+ 0xc7: 0x2503, // Box drawings heavy vertical
+ 0xc8: 0xc5, // Uppercase A, ring
+ 0xc9: 0xe5, // Lowercase A, ring
+ 0xca: 0xd8, // Uppercase O, stroke
+ 0xcb: 0xf8, // Lowercase o, strok
+ 0xcc: 0x250f, // Box drawings heavy down and right
+ 0xcd: 0x2513, // Box drawings heavy down and left
+ 0xce: 0x2517, // Box drawings heavy up and right
+ 0xcf: 0x251b // Box drawings heavy up and left
+ };
+
+ /**
+ * Utils
+ */
+ var getCharForByte = function getCharForByte(byte) {
+ var charCode = byte;
+ if (specialCea608CharsCodes.hasOwnProperty(byte)) {
+ charCode = specialCea608CharsCodes[byte];
+ }
+ return String.fromCharCode(charCode);
+ };
+
+ var NR_ROWS = 15,
+ NR_COLS = 32;
+ // Tables to look up row from PAC data
+ var rowsLowCh1 = { 0x11: 1, 0x12: 3, 0x15: 5, 0x16: 7, 0x17: 9, 0x10: 11, 0x13: 12, 0x14: 14 };
+ var rowsHighCh1 = { 0x11: 2, 0x12: 4, 0x15: 6, 0x16: 8, 0x17: 10, 0x13: 13, 0x14: 15 };
+ var rowsLowCh2 = { 0x19: 1, 0x1A: 3, 0x1D: 5, 0x1E: 7, 0x1F: 9, 0x18: 11, 0x1B: 12, 0x1C: 14 };
+ var rowsHighCh2 = { 0x19: 2, 0x1A: 4, 0x1D: 6, 0x1E: 8, 0x1F: 10, 0x1B: 13, 0x1C: 15 };
+
+ var backgroundColors = ['white', 'green', 'blue', 'cyan', 'red', 'yellow', 'magenta', 'black', 'transparent'];
+
+ /**
+ * Simple logger class to be able to write with time-stamps and filter on level.
+ */
+ var logger = {
+ verboseFilter: { 'DATA': 3, 'DEBUG': 3, 'INFO': 2, 'WARNING': 2, 'TEXT': 1, 'ERROR': 0 },
+ time: null,
+ verboseLevel: 0, // Only write errors
+ setTime: function setTime(newTime) {
+ this.time = newTime;
+ },
+ log: function log(severity, msg) {
+ var minLevel = this.verboseFilter[severity];
+ if (this.verboseLevel >= minLevel) {
+ console.log(this.time + ' [' + severity + '] ' + msg);
+ }
+ }
+ };
+
+ var numArrayToHexArray = function numArrayToHexArray(numArray) {
+ var hexArray = [];
+ for (var j = 0; j < numArray.length; j++) {
+ hexArray.push(numArray[j].toString(16));
+ }
+ return hexArray;
+ };
+
+ var PenState = function () {
+ function PenState(foreground, underline, italics, background, flash) {
+ _classCallCheck(this, PenState);
+
+ this.foreground = foreground || 'white';
+ this.underline = underline || false;
+ this.italics = italics || false;
+ this.background = background || 'black';
+ this.flash = flash || false;
+ }
+
+ _createClass(PenState, [{
+ key: 'reset',
+ value: function reset() {
+ this.foreground = 'white';
+ this.underline = false;
+ this.italics = false;
+ this.background = 'black';
+ this.flash = false;
+ }
+ }, {
+ key: 'setStyles',
+ value: function setStyles(styles) {
+ var attribs = ['foreground', 'underline', 'italics', 'background', 'flash'];
+ for (var i = 0; i < attribs.length; i++) {
+ var style = attribs[i];
+ if (styles.hasOwnProperty(style)) {
+ this[style] = styles[style];
+ }
+ }
+ }
+ }, {
+ key: 'isDefault',
+ value: function isDefault() {
+ return this.foreground === 'white' && !this.underline && !this.italics && this.background === 'black' && !this.flash;
+ }
+ }, {
+ key: 'equals',
+ value: function equals(other) {
+ return this.foreground === other.foreground && this.underline === other.underline && this.italics === other.italics && this.background === other.background && this.flash === other.flash;
+ }
+ }, {
+ key: 'copy',
+ value: function copy(newPenState) {
+ this.foreground = newPenState.foreground;
+ this.underline = newPenState.underline;
+ this.italics = newPenState.italics;
+ this.background = newPenState.background;
+ this.flash = newPenState.flash;
+ }
+ }, {
+ key: 'toString',
+ value: function toString() {
+ return 'color=' + this.foreground + ', underline=' + this.underline + ', italics=' + this.italics + ', background=' + this.background + ', flash=' + this.flash;
+ }
+ }]);
+
+ return PenState;
+ }();
+
+ /**
+ * Unicode character with styling and background.
+ * @constructor
+ */
+
+
+ var StyledUnicodeChar = function () {
+ function StyledUnicodeChar(uchar, foreground, underline, italics, background, flash) {
+ _classCallCheck(this, StyledUnicodeChar);
+
+ this.uchar = uchar || ' '; // unicode character
+ this.penState = new PenState(foreground, underline, italics, background, flash);
+ }
+
+ _createClass(StyledUnicodeChar, [{
+ key: 'reset',
+ value: function reset() {
+ this.uchar = ' ';
+ this.penState.reset();
+ }
+ }, {
+ key: 'setChar',
+ value: function setChar(uchar, newPenState) {
+ this.uchar = uchar;
+ this.penState.copy(newPenState);
+ }
+ }, {
+ key: 'setPenState',
+ value: function setPenState(newPenState) {
+ this.penState.copy(newPenState);
+ }
+ }, {
+ key: 'equals',
+ value: function equals(other) {
+ return this.uchar === other.uchar && this.penState.equals(other.penState);
+ }
+ }, {
+ key: 'copy',
+ value: function copy(newChar) {
+ this.uchar = newChar.uchar;
+ this.penState.copy(newChar.penState);
+ }
+ }, {
+ key: 'isEmpty',
+ value: function isEmpty() {
+ return this.uchar === ' ' && this.penState.isDefault();
+ }
+ }]);
+
+ return StyledUnicodeChar;
+ }();
+
+ /**
+ * CEA-608 row consisting of NR_COLS instances of StyledUnicodeChar.
+ * @constructor
+ */
+
+
+ var Row = function () {
+ function Row() {
+ _classCallCheck(this, Row);
+
+ this.chars = [];
+ for (var i = 0; i < NR_COLS; i++) {
+ this.chars.push(new StyledUnicodeChar());
+ }
+ this.pos = 0;
+ this.currPenState = new PenState();
+ }
+
+ _createClass(Row, [{
+ key: 'equals',
+ value: function equals(other) {
+ var equal = true;
+ for (var i = 0; i < NR_COLS; i++) {
+ if (!this.chars[i].equals(other.chars[i])) {
+ equal = false;
+ break;
+ }
+ }
+ return equal;
+ }
+ }, {
+ key: 'copy',
+ value: function copy(other) {
+ for (var i = 0; i < NR_COLS; i++) {
+ this.chars[i].copy(other.chars[i]);
+ }
+ }
+ }, {
+ key: 'isEmpty',
+ value: function isEmpty() {
+ var empty = true;
+ for (var i = 0; i < NR_COLS; i++) {
+ if (!this.chars[i].isEmpty()) {
+ empty = false;
+ break;
+ }
+ }
+ return empty;
+ }
+
+ /**
+ * Set the cursor to a valid column.
+ */
+
+ }, {
+ key: 'setCursor',
+ value: function setCursor(absPos) {
+ if (this.pos !== absPos) {
+ this.pos = absPos;
+ }
+ if (this.pos < 0) {
+ logger.log('ERROR', 'Negative cursor position ' + this.pos);
+ this.pos = 0;
+ } else if (this.pos > NR_COLS) {
+ logger.log('ERROR', 'Too large cursor position ' + this.pos);
+ this.pos = NR_COLS;
+ }
+ }
+
+ /**
+ * Move the cursor relative to current position.
+ */
+
+ }, {
+ key: 'moveCursor',
+ value: function moveCursor(relPos) {
+ var newPos = this.pos + relPos;
+ if (relPos > 1) {
+ for (var i = this.pos + 1; i < newPos + 1; i++) {
+ this.chars[i].setPenState(this.currPenState);
+ }
+ }
+ this.setCursor(newPos);
+ }
+
+ /**
+ * Backspace, move one step back and clear character.
+ */
+
+ }, {
+ key: 'backSpace',
+ value: function backSpace() {
+ this.moveCursor(-1);
+ this.chars[this.pos].setChar(' ', this.currPenState);
+ }
+ }, {
+ key: 'insertChar',
+ value: function insertChar(byte) {
+ if (byte >= 0x90) {
+ //Extended char
+ this.backSpace();
+ }
+ var char = getCharForByte(byte);
+ if (this.pos >= NR_COLS) {
+ logger.log('ERROR', 'Cannot insert ' + byte.toString(16) + ' (' + char + ') at position ' + this.pos + '. Skipping it!');
+ return;
+ }
+ this.chars[this.pos].setChar(char, this.currPenState);
+ this.moveCursor(1);
+ }
+ }, {
+ key: 'clearFromPos',
+ value: function clearFromPos(startPos) {
+ var i;
+ for (i = startPos; i < NR_COLS; i++) {
+ this.chars[i].reset();
+ }
+ }
+ }, {
+ key: 'clear',
+ value: function clear() {
+ this.clearFromPos(0);
+ this.pos = 0;
+ this.currPenState.reset();
+ }
+ }, {
+ key: 'clearToEndOfRow',
+ value: function clearToEndOfRow() {
+ this.clearFromPos(this.pos);
+ }
+ }, {
+ key: 'getTextString',
+ value: function getTextString() {
+ var chars = [];
+ var empty = true;
+ for (var i = 0; i < NR_COLS; i++) {
+ var char = this.chars[i].uchar;
+ if (char !== ' ') {
+ empty = false;
+ }
+ chars.push(char);
+ }
+ if (empty) {
+ return '';
+ } else {
+ return chars.join('');
+ }
+ }
+ }, {
+ key: 'setPenStyles',
+ value: function setPenStyles(styles) {
+ this.currPenState.setStyles(styles);
+ var currChar = this.chars[this.pos];
+ currChar.setPenState(this.currPenState);
+ }
+ }]);
+
+ return Row;
+ }();
+
+ /**
+ * Keep a CEA-608 screen of 32x15 styled characters
+ * @constructor
+ */
+
+
+ var CaptionScreen = function () {
+ function CaptionScreen() {
+ _classCallCheck(this, CaptionScreen);
+
+ this.rows = [];
+ for (var i = 0; i < NR_ROWS; i++) {
+ this.rows.push(new Row()); // Note that we use zero-based numbering (0-14)
+ }
+ this.currRow = NR_ROWS - 1;
+ this.nrRollUpRows = null;
+ this.reset();
+ }
+
+ _createClass(CaptionScreen, [{
+ key: 'reset',
+ value: function reset() {
+ for (var i = 0; i < NR_ROWS; i++) {
+ this.rows[i].clear();
+ }
+ this.currRow = NR_ROWS - 1;
+ }
+ }, {
+ key: 'equals',
+ value: function equals(other) {
+ var equal = true;
+ for (var i = 0; i < NR_ROWS; i++) {
+ if (!this.rows[i].equals(other.rows[i])) {
+ equal = false;
+ break;
+ }
+ }
+ return equal;
+ }
+ }, {
+ key: 'copy',
+ value: function copy(other) {
+ for (var i = 0; i < NR_ROWS; i++) {
+ this.rows[i].copy(other.rows[i]);
+ }
+ }
+ }, {
+ key: 'isEmpty',
+ value: function isEmpty() {
+ var empty = true;
+ for (var i = 0; i < NR_ROWS; i++) {
+ if (!this.rows[i].isEmpty()) {
+ empty = false;
+ break;
+ }
+ }
+ return empty;
+ }
+ }, {
+ key: 'backSpace',
+ value: function backSpace() {
+ var row = this.rows[this.currRow];
+ row.backSpace();
+ }
+ }, {
+ key: 'clearToEndOfRow',
+ value: function clearToEndOfRow() {
+ var row = this.rows[this.currRow];
+ row.clearToEndOfRow();
+ }
+
+ /**
+ * Insert a character (without styling) in the current row.
+ */
+
+ }, {
+ key: 'insertChar',
+ value: function insertChar(char) {
+ var row = this.rows[this.currRow];
+ row.insertChar(char);
+ }
+ }, {
+ key: 'setPen',
+ value: function setPen(styles) {
+ var row = this.rows[this.currRow];
+ row.setPenStyles(styles);
+ }
+ }, {
+ key: 'moveCursor',
+ value: function moveCursor(relPos) {
+ var row = this.rows[this.currRow];
+ row.moveCursor(relPos);
+ }
+ }, {
+ key: 'setCursor',
+ value: function setCursor(absPos) {
+ logger.log('INFO', 'setCursor: ' + absPos);
+ var row = this.rows[this.currRow];
+ row.setCursor(absPos);
+ }
+ }, {
+ key: 'setPAC',
+ value: function setPAC(pacData) {
+ logger.log('INFO', 'pacData = ' + JSON.stringify(pacData));
+ var newRow = pacData.row - 1;
+ if (this.nrRollUpRows && newRow < this.nrRollUpRows - 1) {
+ newRow = this.nrRollUpRows - 1;
+ }
+ this.currRow = newRow;
+ var row = this.rows[this.currRow];
+ if (pacData.indent !== null) {
+ var indent = pacData.indent;
+ var prevPos = Math.max(indent - 1, 0);
+ row.setCursor(pacData.indent);
+ pacData.color = row.chars[prevPos].penState.foreground;
+ }
+ var styles = { foreground: pacData.color, underline: pacData.underline, italics: pacData.italics, background: 'black', flash: false };
+ this.setPen(styles);
+ }
+
+ /**
+ * Set background/extra foreground, but first do back_space, and then insert space (backwards compatibility).
+ */
+
+ }, {
+ key: 'setBkgData',
+ value: function setBkgData(bkgData) {
+
+ logger.log('INFO', 'bkgData = ' + JSON.stringify(bkgData));
+ this.backSpace();
+ this.setPen(bkgData);
+ this.insertChar(0x20); //Space
+ }
+ }, {
+ key: 'setRollUpRows',
+ value: function setRollUpRows(nrRows) {
+ this.nrRollUpRows = nrRows;
+ }
+ }, {
+ key: 'rollUp',
+ value: function rollUp() {
+ if (this.nrRollUpRows === null) {
+ logger.log('DEBUG', 'roll_up but nrRollUpRows not set yet');
+ return; //Not properly setup
+ }
+ logger.log('TEXT', this.getDisplayText());
+ var topRowIndex = this.currRow + 1 - this.nrRollUpRows;
+ var topRow = this.rows.splice(topRowIndex, 1)[0];
+ topRow.clear();
+ this.rows.splice(this.currRow, 0, topRow);
+ logger.log('INFO', 'Rolling up');
+ //logger.log('TEXT', this.get_display_text())
+ }
+
+ /**
+ * Get all non-empty rows with as unicode text.
+ */
+
+ }, {
+ key: 'getDisplayText',
+ value: function getDisplayText(asOneRow) {
+ asOneRow = asOneRow || false;
+ var displayText = [];
+ var text = '';
+ var rowNr = -1;
+ for (var i = 0; i < NR_ROWS; i++) {
+ var rowText = this.rows[i].getTextString();
+ if (rowText) {
+ rowNr = i + 1;
+ if (asOneRow) {
+ displayText.push('Row ' + rowNr + ': \'' + rowText + '\'');
+ } else {
+ displayText.push(rowText.trim());
+ }
+ }
+ }
+ if (displayText.length > 0) {
+ if (asOneRow) {
+ text = '[' + displayText.join(' | ') + ']';
+ } else {
+ text = displayText.join('\n');
+ }
+ }
+ return text;
+ }
+ }, {
+ key: 'getTextAndFormat',
+ value: function getTextAndFormat() {
+ return this.rows;
+ }
+ }]);
+
+ return CaptionScreen;
+ }();
+
+ //var modes = ['MODE_ROLL-UP', 'MODE_POP-ON', 'MODE_PAINT-ON', 'MODE_TEXT'];
+
+ var Cea608Channel = function () {
+ function Cea608Channel(channelNumber, outputFilter) {
+ _classCallCheck(this, Cea608Channel);
+
+ this.chNr = channelNumber;
+ this.outputFilter = outputFilter;
+ this.mode = null;
+ this.verbose = 0;
+ this.displayedMemory = new CaptionScreen();
+ this.nonDisplayedMemory = new CaptionScreen();
+ this.lastOutputScreen = new CaptionScreen();
+ this.currRollUpRow = this.displayedMemory.rows[NR_ROWS - 1];
+ this.writeScreen = this.displayedMemory;
+ this.mode = null;
+ this.cueStartTime = null; // Keeps track of where a cue started.
+ }
+
+ _createClass(Cea608Channel, [{
+ key: 'reset',
+ value: function reset() {
+ this.mode = null;
+ this.displayedMemory.reset();
+ this.nonDisplayedMemory.reset();
+ this.lastOutputScreen.reset();
+ this.currRollUpRow = this.displayedMemory.rows[NR_ROWS - 1];
+ this.writeScreen = this.displayedMemory;
+ this.mode = null;
+ this.cueStartTime = null;
+ this.lastCueEndTime = null;
+ }
+ }, {
+ key: 'getHandler',
+ value: function getHandler() {
+ return this.outputFilter;
+ }
+ }, {
+ key: 'setHandler',
+ value: function setHandler(newHandler) {
+ this.outputFilter = newHandler;
+ }
+ }, {
+ key: 'setPAC',
+ value: function setPAC(pacData) {
+ this.writeScreen.setPAC(pacData);
+ }
+ }, {
+ key: 'setBkgData',
+ value: function setBkgData(bkgData) {
+ this.writeScreen.setBkgData(bkgData);
+ }
+ }, {
+ key: 'setMode',
+ value: function setMode(newMode) {
+ if (newMode === this.mode) {
+ return;
+ }
+ this.mode = newMode;
+ logger.log('INFO', 'MODE=' + newMode);
+ if (this.mode === 'MODE_POP-ON') {
+ this.writeScreen = this.nonDisplayedMemory;
+ } else {
+ this.writeScreen = this.displayedMemory;
+ this.writeScreen.reset();
+ }
+ if (this.mode !== 'MODE_ROLL-UP') {
+ this.displayedMemory.nrRollUpRows = null;
+ this.nonDisplayedMemory.nrRollUpRows = null;
+ }
+ this.mode = newMode;
+ }
+ }, {
+ key: 'insertChars',
+ value: function insertChars(chars) {
+ for (var i = 0; i < chars.length; i++) {
+ this.writeScreen.insertChar(chars[i]);
+ }
+ var screen = this.writeScreen === this.displayedMemory ? 'DISP' : 'NON_DISP';
+ logger.log('INFO', screen + ': ' + this.writeScreen.getDisplayText(true));
+ if (this.mode === 'MODE_PAINT-ON' || this.mode === 'MODE_ROLL-UP') {
+ logger.log('TEXT', 'DISPLAYED: ' + this.displayedMemory.getDisplayText(true));
+ this.outputDataUpdate();
+ }
+ }
+ }, {
+ key: 'ccRCL',
+ value: function ccRCL() {
+ // Resume Caption Loading (switch mode to Pop On)
+ logger.log('INFO', 'RCL - Resume Caption Loading');
+ this.setMode('MODE_POP-ON');
+ }
+ }, {
+ key: 'ccBS',
+ value: function ccBS() {
+ // BackSpace
+ logger.log('INFO', 'BS - BackSpace');
+ if (this.mode === 'MODE_TEXT') {
+ return;
+ }
+ this.writeScreen.backSpace();
+ if (this.writeScreen === this.displayedMemory) {
+ this.outputDataUpdate();
+ }
+ }
+ }, {
+ key: 'ccAOF',
+ value: function ccAOF() {
+ // Reserved (formerly Alarm Off)
+ return;
+ }
+ }, {
+ key: 'ccAON',
+ value: function ccAON() {
+ // Reserved (formerly Alarm On)
+ return;
+ }
+ }, {
+ key: 'ccDER',
+ value: function ccDER() {
+ // Delete to End of Row
+ logger.log('INFO', 'DER- Delete to End of Row');
+ this.writeScreen.clearToEndOfRow();
+ this.outputDataUpdate();
+ }
+ }, {
+ key: 'ccRU',
+ value: function ccRU(nrRows) {
+ //Roll-Up Captions-2,3,or 4 Rows
+ logger.log('INFO', 'RU(' + nrRows + ') - Roll Up');
+ this.writeScreen = this.displayedMemory;
+ this.setMode('MODE_ROLL-UP');
+ this.writeScreen.setRollUpRows(nrRows);
+ }
+ }, {
+ key: 'ccFON',
+ value: function ccFON() {
+ //Flash On
+ logger.log('INFO', 'FON - Flash On');
+ this.writeScreen.setPen({ flash: true });
+ }
+ }, {
+ key: 'ccRDC',
+ value: function ccRDC() {
+ // Resume Direct Captioning (switch mode to PaintOn)
+ logger.log('INFO', 'RDC - Resume Direct Captioning');
+ this.setMode('MODE_PAINT-ON');
+ }
+ }, {
+ key: 'ccTR',
+ value: function ccTR() {
+ // Text Restart in text mode (not supported, however)
+ logger.log('INFO', 'TR');
+ this.setMode('MODE_TEXT');
+ }
+ }, {
+ key: 'ccRTD',
+ value: function ccRTD() {
+ // Resume Text Display in Text mode (not supported, however)
+ logger.log('INFO', 'RTD');
+ this.setMode('MODE_TEXT');
+ }
+ }, {
+ key: 'ccEDM',
+ value: function ccEDM() {
+ // Erase Displayed Memory
+ logger.log('INFO', 'EDM - Erase Displayed Memory');
+ this.displayedMemory.reset();
+ this.outputDataUpdate();
+ }
+ }, {
+ key: 'ccCR',
+ value: function ccCR() {
+ // Carriage Return
+ logger.log('CR - Carriage Return');
+ this.writeScreen.rollUp();
+ this.outputDataUpdate();
+ }
+ }, {
+ key: 'ccENM',
+ value: function ccENM() {
+ //Erase Non-Displayed Memory
+ logger.log('INFO', 'ENM - Erase Non-displayed Memory');
+ this.nonDisplayedMemory.reset();
+ }
+ }, {
+ key: 'ccEOC',
+ value: function ccEOC() {
+ //End of Caption (Flip Memories)
+ logger.log('INFO', 'EOC - End Of Caption');
+ if (this.mode === 'MODE_POP-ON') {
+ var tmp = this.displayedMemory;
+ this.displayedMemory = this.nonDisplayedMemory;
+ this.nonDisplayedMemory = tmp;
+ this.writeScreen = this.nonDisplayedMemory;
+ logger.log('TEXT', 'DISP: ' + this.displayedMemory.getDisplayText());
+ }
+ this.outputDataUpdate();
+ }
+ }, {
+ key: 'ccTO',
+ value: function ccTO(nrCols) {
+ // Tab Offset 1,2, or 3 columns
+ logger.log('INFO', 'TO(' + nrCols + ') - Tab Offset');
+ this.writeScreen.moveCursor(nrCols);
+ }
+ }, {
+ key: 'ccMIDROW',
+ value: function ccMIDROW(secondByte) {
+ // Parse MIDROW command
+ var styles = { flash: false };
+ styles.underline = secondByte % 2 === 1;
+ styles.italics = secondByte >= 0x2e;
+ if (!styles.italics) {
+ var colorIndex = Math.floor(secondByte / 2) - 0x10;
+ var colors = ['white', 'green', 'blue', 'cyan', 'red', 'yellow', 'magenta'];
+ styles.foreground = colors[colorIndex];
+ } else {
+ styles.foreground = 'white';
+ }
+ logger.log('INFO', 'MIDROW: ' + JSON.stringify(styles));
+ this.writeScreen.setPen(styles);
+ }
+ }, {
+ key: 'outputDataUpdate',
+ value: function outputDataUpdate() {
+ var t = logger.time;
+ if (t === null) {
+ return;
+ }
+ if (this.outputFilter) {
+ if (this.outputFilter.updateData) {
+ this.outputFilter.updateData(t, this.displayedMemory);
+ }
+ if (this.cueStartTime === null && !this.displayedMemory.isEmpty()) {
+ // Start of a new cue
+ this.cueStartTime = t;
+ } else {
+ if (!this.displayedMemory.equals(this.lastOutputScreen)) {
+ if (this.outputFilter.newCue) {
+ this.outputFilter.newCue(this.cueStartTime, t, this.lastOutputScreen);
+ }
+ this.cueStartTime = this.displayedMemory.isEmpty() ? null : t;
+ }
+ }
+ this.lastOutputScreen.copy(this.displayedMemory);
+ }
+ }
+ }, {
+ key: 'cueSplitAtTime',
+ value: function cueSplitAtTime(t) {
+ if (this.outputFilter) {
+ if (!this.displayedMemory.isEmpty()) {
+ if (this.outputFilter.newCue) {
+ this.outputFilter.newCue(this.cueStartTime, t, this.displayedMemory);
+ }
+ this.cueStartTime = t;
+ }
+ }
+ }
+ }]);
+
+ return Cea608Channel;
+ }();
+
+ var Cea608Parser = function () {
+ function Cea608Parser(field, out1, out2) {
+ _classCallCheck(this, Cea608Parser);
+
+ this.field = field || 1;
+ this.outputs = [out1, out2];
+ this.channels = [new Cea608Channel(1, out1), new Cea608Channel(2, out2)];
+ this.currChNr = -1; // Will be 1 or 2
+ this.lastCmdA = null; // First byte of last command
+ this.lastCmdB = null; // Second byte of last command
+ this.bufferedData = [];
+ this.startTime = null;
+ this.lastTime = null;
+ this.dataCounters = { 'padding': 0, 'char': 0, 'cmd': 0, 'other': 0 };
+ }
+
+ _createClass(Cea608Parser, [{
+ key: 'getHandler',
+ value: function getHandler(index) {
+ return this.channels[index].getHandler();
+ }
+ }, {
+ key: 'setHandler',
+ value: function setHandler(index, newHandler) {
+ this.channels[index].setHandler(newHandler);
+ }
+
+ /**
+ * Add data for time t in forms of list of bytes (unsigned ints). The bytes are treated as pairs.
+ */
+
+ }, {
+ key: 'addData',
+ value: function addData(t, byteList) {
+ var cmdFound,
+ a,
+ b,
+ charsFound = false;
+
+ this.lastTime = t;
+ logger.setTime(t);
+
+ for (var i = 0; i < byteList.length; i += 2) {
+ a = byteList[i] & 0x7f;
+ b = byteList[i + 1] & 0x7f;
+ if (a === 0 && b === 0) {
+ this.dataCounters.padding += 2;
+ continue;
+ } else {
+ logger.log('DATA', '[' + numArrayToHexArray([byteList[i], byteList[i + 1]]) + '] -> (' + numArrayToHexArray([a, b]) + ')');
+ }
+ cmdFound = this.parseCmd(a, b);
+ if (!cmdFound) {
+ cmdFound = this.parseMidrow(a, b);
+ }
+ if (!cmdFound) {
+ cmdFound = this.parsePAC(a, b);
+ }
+ if (!cmdFound) {
+ cmdFound = this.parseBackgroundAttributes(a, b);
+ }
+ if (!cmdFound) {
+ charsFound = this.parseChars(a, b);
+ if (charsFound) {
+ if (this.currChNr && this.currChNr >= 0) {
+ var channel = this.channels[this.currChNr - 1];
+ channel.insertChars(charsFound);
+ } else {
+ logger.log('WARNING', 'No channel found yet. TEXT-MODE?');
+ }
+ }
+ }
+ if (cmdFound) {
+ this.dataCounters.cmd += 2;
+ } else if (charsFound) {
+ this.dataCounters.char += 2;
+ } else {
+ this.dataCounters.other += 2;
+ logger.log('WARNING', 'Couldn\'t parse cleaned data ' + numArrayToHexArray([a, b]) + ' orig: ' + numArrayToHexArray([byteList[i], byteList[i + 1]]));
+ }
+ }
+ }
+
+ /**
+ * Parse Command.
+ * @returns {Boolean} Tells if a command was found
+ */
+
+ }, {
+ key: 'parseCmd',
+ value: function parseCmd(a, b) {
+ var chNr = null;
+
+ var cond1 = (a === 0x14 || a === 0x1C) && 0x20 <= b && b <= 0x2F;
+ var cond2 = (a === 0x17 || a === 0x1F) && 0x21 <= b && b <= 0x23;
+ if (!(cond1 || cond2)) {
+ return false;
+ }
+
+ if (a === this.lastCmdA && b === this.lastCmdB) {
+ this.lastCmdA = null;
+ this.lastCmdB = null; // Repeated commands are dropped (once)
+ logger.log('DEBUG', 'Repeated command (' + numArrayToHexArray([a, b]) + ') is dropped');
+ return true;
+ }
+
+ if (a === 0x14 || a === 0x17) {
+ chNr = 1;
+ } else {
+ chNr = 2; // (a === 0x1C || a=== 0x1f)
+ }
+
+ var channel = this.channels[chNr - 1];
+
+ if (a === 0x14 || a === 0x1C) {
+ if (b === 0x20) {
+ channel.ccRCL();
+ } else if (b === 0x21) {
+ channel.ccBS();
+ } else if (b === 0x22) {
+ channel.ccAOF();
+ } else if (b === 0x23) {
+ channel.ccAON();
+ } else if (b === 0x24) {
+ channel.ccDER();
+ } else if (b === 0x25) {
+ channel.ccRU(2);
+ } else if (b === 0x26) {
+ channel.ccRU(3);
+ } else if (b === 0x27) {
+ channel.ccRU(4);
+ } else if (b === 0x28) {
+ channel.ccFON();
+ } else if (b === 0x29) {
+ channel.ccRDC();
+ } else if (b === 0x2A) {
+ channel.ccTR();
+ } else if (b === 0x2B) {
+ channel.ccRTD();
+ } else if (b === 0x2C) {
+ channel.ccEDM();
+ } else if (b === 0x2D) {
+ channel.ccCR();
+ } else if (b === 0x2E) {
+ channel.ccENM();
+ } else if (b === 0x2F) {
+ channel.ccEOC();
+ }
+ } else {
+ //a == 0x17 || a == 0x1F
+ channel.ccTO(b - 0x20);
+ }
+ this.lastCmdA = a;
+ this.lastCmdB = b;
+ this.currChNr = chNr;
+ return true;
+ }
+
+ /**
+ * Parse midrow styling command
+ * @returns {Boolean}
+ */
+
+ }, {
+ key: 'parseMidrow',
+ value: function parseMidrow(a, b) {
+ var chNr = null;
+
+ if ((a === 0x11 || a === 0x19) && 0x20 <= b && b <= 0x2f) {
+ if (a === 0x11) {
+ chNr = 1;
+ } else {
+ chNr = 2;
+ }
+ if (chNr !== this.currChNr) {
+ logger.log('ERROR', 'Mismatch channel in midrow parsing');
+ return false;
+ }
+ var channel = this.channels[chNr - 1];
+ channel.ccMIDROW(b);
+ logger.log('DEBUG', 'MIDROW (' + numArrayToHexArray([a, b]) + ')');
+ return true;
+ }
+ return false;
+ }
+ /**
+ * Parse Preable Access Codes (Table 53).
+ * @returns {Boolean} Tells if PAC found
+ */
+
+ }, {
+ key: 'parsePAC',
+ value: function parsePAC(a, b) {
+
+ var chNr = null;
+ var row = null;
+
+ var case1 = (0x11 <= a && a <= 0x17 || 0x19 <= a && a <= 0x1F) && 0x40 <= b && b <= 0x7F;
+ var case2 = (a === 0x10 || a === 0x18) && 0x40 <= b && b <= 0x5F;
+ if (!(case1 || case2)) {
+ return false;
+ }
+
+ if (a === this.lastCmdA && b === this.lastCmdB) {
+ this.lastCmdA = null;
+ this.lastCmdB = null;
+ return true; // Repeated commands are dropped (once)
+ }
+
+ chNr = a <= 0x17 ? 1 : 2;
+
+ if (0x40 <= b && b <= 0x5F) {
+ row = chNr === 1 ? rowsLowCh1[a] : rowsLowCh2[a];
+ } else {
+ // 0x60 <= b <= 0x7F
+ row = chNr === 1 ? rowsHighCh1[a] : rowsHighCh2[a];
+ }
+ var pacData = this.interpretPAC(row, b);
+ var channel = this.channels[chNr - 1];
+ channel.setPAC(pacData);
+ this.lastCmdA = a;
+ this.lastCmdB = b;
+ this.currChNr = chNr;
+ return true;
+ }
+
+ /**
+ * Interpret the second byte of the pac, and return the information.
+ * @returns {Object} pacData with style parameters.
+ */
+
+ }, {
+ key: 'interpretPAC',
+ value: function interpretPAC(row, byte) {
+ var pacIndex = byte;
+ var pacData = { color: null, italics: false, indent: null, underline: false, row: row };
+
+ if (byte > 0x5F) {
+ pacIndex = byte - 0x60;
+ } else {
+ pacIndex = byte - 0x40;
+ }
+ pacData.underline = (pacIndex & 1) === 1;
+ if (pacIndex <= 0xd) {
+ pacData.color = ['white', 'green', 'blue', 'cyan', 'red', 'yellow', 'magenta', 'white'][Math.floor(pacIndex / 2)];
+ } else if (pacIndex <= 0xf) {
+ pacData.italics = true;
+ pacData.color = 'white';
+ } else {
+ pacData.indent = Math.floor((pacIndex - 0x10) / 2) * 4;
+ }
+ return pacData; // Note that row has zero offset. The spec uses 1.
+ }
+
+ /**
+ * Parse characters.
+ * @returns An array with 1 to 2 codes corresponding to chars, if found. null otherwise.
+ */
+
+ }, {
+ key: 'parseChars',
+ value: function parseChars(a, b) {
+
+ var channelNr = null,
+ charCodes = null,
+ charCode1 = null;
+
+ if (a >= 0x19) {
+ channelNr = 2;
+ charCode1 = a - 8;
+ } else {
+ channelNr = 1;
+ charCode1 = a;
+ }
+ if (0x11 <= charCode1 && charCode1 <= 0x13) {
+ // Special character
+ var oneCode = b;
+ if (charCode1 === 0x11) {
+ oneCode = b + 0x50;
+ } else if (charCode1 === 0x12) {
+ oneCode = b + 0x70;
+ } else {
+ oneCode = b + 0x90;
+ }
+ logger.log('INFO', 'Special char \'' + getCharForByte(oneCode) + '\' in channel ' + channelNr);
+ charCodes = [oneCode];
+ } else if (0x20 <= a && a <= 0x7f) {
+ charCodes = b === 0 ? [a] : [a, b];
+ }
+ if (charCodes) {
+ var hexCodes = numArrayToHexArray(charCodes);
+ logger.log('DEBUG', 'Char codes = ' + hexCodes.join(','));
+ this.lastCmdA = null;
+ this.lastCmdB = null;
+ }
+ return charCodes;
+ }
+
+ /**
+ * Parse extended background attributes as well as new foreground color black.
+ * @returns{Boolean} Tells if background attributes are found
+ */
+
+ }, {
+ key: 'parseBackgroundAttributes',
+ value: function parseBackgroundAttributes(a, b) {
+ var bkgData, index, chNr, channel;
+
+ var case1 = (a === 0x10 || a === 0x18) && 0x20 <= b && b <= 0x2f;
+ var case2 = (a === 0x17 || a === 0x1f) && 0x2d <= b && b <= 0x2f;
+ if (!(case1 || case2)) {
+ return false;
+ }
+ bkgData = {};
+ if (a === 0x10 || a === 0x18) {
+ index = Math.floor((b - 0x20) / 2);
+ bkgData.background = backgroundColors[index];
+ if (b % 2 === 1) {
+ bkgData.background = bkgData.background + '_semi';
+ }
+ } else if (b === 0x2d) {
+ bkgData.background = 'transparent';
+ } else {
+ bkgData.foreground = 'black';
+ if (b === 0x2f) {
+ bkgData.underline = true;
+ }
+ }
+ chNr = a < 0x18 ? 1 : 2;
+ channel = this.channels[chNr - 1];
+ channel.setBkgData(bkgData);
+ this.lastCmdA = null;
+ this.lastCmdB = null;
+ return true;
+ }
+
+ /**
+ * Reset state of parser and its channels.
+ */
+
+ }, {
+ key: 'reset',
+ value: function reset() {
+ for (var i = 0; i < this.channels.length; i++) {
+ if (this.channels[i]) {
+ this.channels[i].reset();
+ }
+ }
+ this.lastCmdA = null;
+ this.lastCmdB = null;
+ }
+
+ /**
+ * Trigger the generation of a cue, and the start of a new one if displayScreens are not empty.
+ */
+
+ }, {
+ key: 'cueSplitAtTime',
+ value: function cueSplitAtTime(t) {
+ for (var i = 0; i < this.channels.length; i++) {
+ if (this.channels[i]) {
+ this.channels[i].cueSplitAtTime(t);
+ }
+ }
+ }
+ }]);
+
+ return Cea608Parser;
+ }();
+
+ exports.default = Cea608Parser;
+
+ },{}],41:[function(_dereq_,module,exports){
+ 'use strict';
+
+ var Cues = {
+
+ newCue: function newCue(track, startTime, endTime, captionScreen) {
+ var row;
+ var cue;
+ var indenting;
+ var indent;
+ var text;
+ var VTTCue = window.VTTCue || window.TextTrackCue;
+
+ for (var r = 0; r < captionScreen.rows.length; r++) {
+ row = captionScreen.rows[r];
+ indenting = true;
+ indent = 0;
+ text = '';
+
+ if (!row.isEmpty()) {
+ for (var c = 0; c < row.chars.length; c++) {
+ if (row.chars[c].uchar.match(/\s/) && indenting) {
+ indent++;
+ } else {
+ text += row.chars[c].uchar;
+ indenting = false;
+ }
+ }
+ cue = new VTTCue(startTime, endTime, text.trim());
+
+ if (indent >= 16) {
+ indent--;
+ } else {
+ indent++;
+ }
+
+ // VTTCue.line get's flakey when using controls, so let's now include line 13&14
+ // also, drop line 1 since it's to close to the top
+ if (navigator.userAgent.match(/Firefox\//)) {
+ cue.line = r + 1;
+ } else {
+ cue.line = r > 7 ? r - 2 : r + 1;
+ }
+ cue.align = 'left';
+ cue.position = 100 * (indent / 32) + (navigator.userAgent.match(/Firefox\//) ? 50 : 0);
+ track.addCue(cue);
+ }
+ }
+ }
+
+ };
+
+ module.exports = Cues;
+
+ },{}],42:[function(_dereq_,module,exports){
+ "use strict";
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ /*
+ * compute an Exponential Weighted moving average
+ * - https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
+ * - heavily inspired from shaka-player
+ */
+
+ var EWMA = function () {
+
+ // About half of the estimated value will be from the last |halfLife| samples by weight.
+
+ function EWMA(halfLife) {
+ _classCallCheck(this, EWMA);
+
+ // Larger values of alpha expire historical data more slowly.
+ this.alpha_ = halfLife ? Math.exp(Math.log(0.5) / halfLife) : 0;
+ this.estimate_ = 0;
+ this.totalWeight_ = 0;
+ }
+
+ _createClass(EWMA, [{
+ key: "sample",
+ value: function sample(weight, value) {
+ var adjAlpha = Math.pow(this.alpha_, weight);
+ this.estimate_ = value * (1 - adjAlpha) + adjAlpha * this.estimate_;
+ this.totalWeight_ += weight;
+ }
+ }, {
+ key: "getTotalWeight",
+ value: function getTotalWeight() {
+ return this.totalWeight_;
+ }
+ }, {
+ key: "getEstimate",
+ value: function getEstimate() {
+ if (this.alpha_) {
+ var zeroFactor = 1 - Math.pow(this.alpha_, this.totalWeight_);
+ return this.estimate_ / zeroFactor;
+ } else {
+ return this.estimate_;
+ }
+ }
+ }]);
+
+ return EWMA;
+ }();
+
+ exports.default = EWMA;
+
+ },{}],43:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
+
+ function noop() {}
+
+ var fakeLogger = {
+ trace: noop,
+ debug: noop,
+ log: noop,
+ warn: noop,
+ info: noop,
+ error: noop
+ };
+
+ var exportedLogger = fakeLogger;
+
+ /*globals self: false */
+
+ //let lastCallTime;
+ // function formatMsgWithTimeInfo(type, msg) {
+ // const now = Date.now();
+ // const diff = lastCallTime ? '+' + (now - lastCallTime) : '0';
+ // lastCallTime = now;
+ // msg = (new Date(now)).toISOString() + ' | [' + type + '] > ' + msg + ' ( ' + diff + ' ms )';
+ // return msg;
+ // }
+
+ function formatMsg(type, msg) {
+ msg = '[' + type + '] > ' + msg;
+ return msg;
+ }
+
+ function consolePrintFn(type) {
+ var func = self.console[type];
+ if (func) {
+ return function () {
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ if (args[0]) {
+ args[0] = formatMsg(type, args[0]);
+ }
+ func.apply(self.console, args);
+ };
+ }
+ return noop;
+ }
+
+ function exportLoggerFunctions(debugConfig) {
+ for (var _len2 = arguments.length, functions = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
+ functions[_key2 - 1] = arguments[_key2];
+ }
+
+ functions.forEach(function (type) {
+ exportedLogger[type] = debugConfig[type] ? debugConfig[type].bind(debugConfig) : consolePrintFn(type);
+ });
+ }
+
+ var enableLogs = exports.enableLogs = function enableLogs(debugConfig) {
+ if (debugConfig === true || (typeof debugConfig === 'undefined' ? 'undefined' : _typeof(debugConfig)) === 'object') {
+ exportLoggerFunctions(debugConfig,
+ // Remove out from list here to hard-disable a log-level
+ //'trace',
+ 'debug', 'log', 'info', 'warn', 'error');
+ // Some browsers don't allow to use bind on console object anyway
+ // fallback to default if needed
+ try {
+ exportedLogger.log();
+ } catch (e) {
+ exportedLogger = fakeLogger;
+ }
+ } else {
+ exportedLogger = fakeLogger;
+ }
+ };
+
+ var logger = exports.logger = exportedLogger;
+
+ },{}],44:[function(_dereq_,module,exports){
+ 'use strict';
+
+ if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
+ ArrayBuffer.prototype.slice = function (start, end) {
+ var that = new Uint8Array(this);
+ if (end === undefined) {
+ end = that.length;
+ }
+ var result = new ArrayBuffer(end - start);
+ var resultArray = new Uint8Array(result);
+ for (var i = 0; i < resultArray.length; i++) {
+ resultArray[i] = that[i + start];
+ }
+ return result;
+ };
+ }
+
+ },{}],45:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ /**
+ * TimeRanges to string helper
+ */
+
+ var TimeRanges = function () {
+ function TimeRanges() {
+ _classCallCheck(this, TimeRanges);
+ }
+
+ _createClass(TimeRanges, null, [{
+ key: 'toString',
+ value: function toString(r) {
+ var log = '',
+ len = r.length;
+ for (var i = 0; i < len; i++) {
+ log += '[' + r.start(i).toFixed(3) + ',' + r.end(i).toFixed(3) + ']';
+ }
+ return log;
+ }
+ }]);
+
+ return TimeRanges;
+ }();
+
+ exports.default = TimeRanges;
+
+ },{}],46:[function(_dereq_,module,exports){
+ 'use strict';
+
+ var URLHelper = {
+ // build an absolute URL from a relative one using the provided baseURL
+ // if relativeURL is an absolute URL it will be returned as is.
+ buildAbsoluteURL: function buildAbsoluteURL(baseURL, relativeURL) {
+ // remove any remaining space and CRLF
+ relativeURL = relativeURL.trim();
+ if (/^[a-z]+:/i.test(relativeURL)) {
+ // complete url, not relative
+ return relativeURL;
+ }
+
+ var relativeURLQuery = null;
+ var relativeURLHash = null;
+
+ var relativeURLHashSplit = /^([^#]*)(.*)$/.exec(relativeURL);
+ if (relativeURLHashSplit) {
+ relativeURLHash = relativeURLHashSplit[2];
+ relativeURL = relativeURLHashSplit[1];
+ }
+ var relativeURLQuerySplit = /^([^\?]*)(.*)$/.exec(relativeURL);
+ if (relativeURLQuerySplit) {
+ relativeURLQuery = relativeURLQuerySplit[2];
+ relativeURL = relativeURLQuerySplit[1];
+ }
+
+ var baseURLHashSplit = /^([^#]*)(.*)$/.exec(baseURL);
+ if (baseURLHashSplit) {
+ baseURL = baseURLHashSplit[1];
+ }
+ var baseURLQuerySplit = /^([^\?]*)(.*)$/.exec(baseURL);
+ if (baseURLQuerySplit) {
+ baseURL = baseURLQuerySplit[1];
+ }
+
+ var baseURLDomainSplit = /^(([a-z]+:)?\/\/[a-z0-9\.\-_~]+(:[0-9]+)?)?(\/.*)$/i.exec(baseURL);
+ if (!baseURLDomainSplit) {
+ throw new Error('Error trying to parse base URL.');
+ }
+
+ // e.g. 'http:', 'https:', ''
+ var baseURLProtocol = baseURLDomainSplit[2] || '';
+ // e.g. 'http://example.com', '//example.com', ''
+ var baseURLProtocolDomain = baseURLDomainSplit[1] || '';
+ // e.g. '/a/b/c/playlist.m3u8'
+ var baseURLPath = baseURLDomainSplit[4];
+
+ var builtURL = null;
+ if (/^\/\//.test(relativeURL)) {
+ // relative url starts wth '//' so copy protocol (which may be '' if baseUrl didn't provide one)
+ builtURL = baseURLProtocol + '//' + URLHelper.buildAbsolutePath('', relativeURL.substring(2));
+ } else if (/^\//.test(relativeURL)) {
+ // relative url starts with '/' so start from root of domain
+ builtURL = baseURLProtocolDomain + '/' + URLHelper.buildAbsolutePath('', relativeURL.substring(1));
+ } else {
+ builtURL = URLHelper.buildAbsolutePath(baseURLProtocolDomain + baseURLPath, relativeURL);
+ }
+
+ // put the query and hash parts back
+ if (relativeURLQuery) {
+ builtURL += relativeURLQuery;
+ }
+ if (relativeURLHash) {
+ builtURL += relativeURLHash;
+ }
+ return builtURL;
+ },
+
+ // build an absolute path using the provided basePath
+ // adapted from https://developer.mozilla.org/en-US/docs/Web/API/document/cookie#Using_relative_URLs_in_the_path_parameter
+ // this does not handle the case where relativePath is "/" or "//". These cases should be handled outside this.
+ buildAbsolutePath: function buildAbsolutePath(basePath, relativePath) {
+ var sRelPath = relativePath;
+ var nUpLn,
+ sDir = '',
+ sPath = basePath.replace(/[^\/]*$/, sRelPath.replace(/(\/|^)(?:\.?\/+)+/g, '$1'));
+ for (var nEnd, nStart = 0; nEnd = sPath.indexOf('/../', nStart), nEnd > -1; nStart = nEnd + nUpLn) {
+ nUpLn = /^\/(?:\.\.\/)*/.exec(sPath.slice(nEnd))[0].length;
+ sDir = (sDir + sPath.substring(nStart, nEnd)).replace(new RegExp('(?:\\\/+[^\\\/]*){0,' + (nUpLn - 1) / 3 + '}$'), '/');
+ }
+ return sDir + sPath.substr(nStart);
+ }
+ };
+
+ module.exports = URLHelper;
+
+ },{}],47:[function(_dereq_,module,exports){
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
+ * XHR based logger
+ */
+
+ var _logger = _dereq_(43);
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ var XhrLoader = function () {
+ function XhrLoader(config) {
+ _classCallCheck(this, XhrLoader);
+
+ if (config && config.xhrSetup) {
+ this.xhrSetup = config.xhrSetup;
+ }
+ }
+
+ _createClass(XhrLoader, [{
+ key: 'destroy',
+ value: function destroy() {
+ this.abort();
+ this.loader = null;
+ }
+ }, {
+ key: 'abort',
+ value: function abort() {
+ var loader = this.loader;
+ if (loader && loader.readyState !== 4) {
+ this.stats.aborted = true;
+ loader.abort();
+ }
+
+ window.clearTimeout(this.requestTimeout);
+ this.requestTimeout = null;
+ window.clearTimeout(this.retryTimeout);
+ this.retryTimeout = null;
+ }
+ }, {
+ key: 'load',
+ value: function load(context, config, callbacks) {
+ this.context = context;
+ this.config = config;
+ this.callbacks = callbacks;
+ this.stats = { trequest: performance.now(), retry: 0 };
+ this.retryDelay = config.retryDelay;
+ this.loadInternal();
+ }
+ }, {
+ key: 'loadInternal',
+ value: function loadInternal() {
+ var xhr,
+ context = this.context;
+
+ if (typeof XDomainRequest !== 'undefined') {
+ xhr = this.loader = new XDomainRequest();
+ } else {
+ xhr = this.loader = new XMLHttpRequest();
+ }
+
+ xhr.onreadystatechange = this.readystatechange.bind(this);
+ xhr.onprogress = this.loadprogress.bind(this);
+
+ xhr.open('GET', context.url, true);
+
+ if (context.rangeEnd) {
+ xhr.setRequestHeader('Range', 'bytes=' + context.rangeStart + '-' + (context.rangeEnd - 1));
+ }
+ xhr.responseType = context.responseType;
+ var stats = this.stats;
+ stats.tfirst = 0;
+ stats.loaded = 0;
+ if (this.xhrSetup) {
+ this.xhrSetup(xhr, context.url);
+ }
+ // setup timeout before we perform request
+ this.requestTimeout = window.setTimeout(this.loadtimeout.bind(this), this.config.timeout);
+ xhr.send();
+ }
+ }, {
+ key: 'readystatechange',
+ value: function readystatechange(event) {
+ var xhr = event.currentTarget,
+ readyState = xhr.readyState,
+ stats = this.stats,
+ context = this.context,
+ config = this.config;
+
+ // don't proceed if xhr has been aborted
+ if (stats.aborted) {
+ return;
+ }
+
+ // in any case clear the current xhrs timeout
+ window.clearTimeout(this.requestTimeout);
+
+ // HEADERS_RECEIVED
+ if (readyState >= 2) {
+ if (stats.tfirst === 0) {
+ stats.tfirst = Math.max(performance.now(), stats.trequest);
+ // reset timeout to total timeout duration minus the time it took to receive headers
+ this.requestTimeout = window.setTimeout(this.loadtimeout.bind(this), config.timeout - (stats.tfirst - stats.trequest));
+ }
+ if (readyState === 4) {
+ var status = xhr.status;
+ // http status between 200 to 299 are all successful
+ if (status >= 200 && status < 300) {
+ stats.tload = Math.max(stats.tfirst, performance.now());
+ var data = void 0,
+ len = void 0;
+ if (context.responseType === 'arraybuffer') {
+ data = xhr.response;
+ len = data.byteLength;
+ } else {
+ data = xhr.responseText;
+ len = data.length;
+ }
+ stats.loaded = stats.total = len;
+ var response = { url: xhr.responseURL, data: data };
+ this.callbacks.onSuccess(response, stats, context);
+ } else {
+ // if max nb of retries reached or if http status between 400 and 499 (such error cannot be recovered, retrying is useless), return error
+ if (stats.retry >= config.maxRetry || status >= 400 && status < 499) {
+ _logger.logger.error(status + ' while loading ' + context.url);
+ this.callbacks.onError({ code: status, text: xhr.statusText }, context);
+ } else {
+ // retry
+ _logger.logger.warn(status + ' while loading ' + context.url + ', retrying in ' + this.retryDelay + '...');
+ // aborts and resets internal state
+ this.destroy();
+ // schedule retry
+ this.retryTimeout = window.setTimeout(this.loadInternal.bind(this), this.retryDelay);
+ // set exponential backoff
+ this.retryDelay = Math.min(2 * this.retryDelay, config.maxRetryDelay);
+ stats.retry++;
+ }
+ }
+ }
+ }
+ }
+ }, {
+ key: 'loadtimeout',
+ value: function loadtimeout() {
+ _logger.logger.warn('timeout while loading ' + this.context.url);
+ this.callbacks.onTimeout(this.stats, this.context);
+ }
+ }, {
+ key: 'loadprogress',
+ value: function loadprogress(event) {
+ var stats = this.stats;
+ stats.loaded = event.loaded;
+ if (event.lengthComputable) {
+ stats.total = event.total;
+ }
+ var onProgress = this.callbacks.onProgress;
+ if (onProgress) {
+ // last args is to provide on progress data
+ onProgress(stats, this.context, null);
+ }
+ }
+ }]);
+
+ return XhrLoader;
+ }();
+
+ exports.default = XhrLoader;
+
+ },{"43":43}]},{},[31])(31)
+ });
+ //# sourceMappingURL=hls.js.map
+
+
+/***/ },
+/* 70 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /* WEBPACK VAR INJECTION */(function(global, module) {/**
+ * lodash (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors <https://jquery.org/>
+ * Released under MIT license <https://lodash.com/license>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+
+ /** Used as the size to enable large array optimizations. */
+ var LARGE_ARRAY_SIZE = 200;
+
+ /** Used to stand-in for `undefined` hash values. */
+ var HASH_UNDEFINED = '__lodash_hash_undefined__';
+
+ /** Used to compose bitmasks for comparison styles. */
+ var UNORDERED_COMPARE_FLAG = 1,
+ PARTIAL_COMPARE_FLAG = 2;
+
+ /** Used as references for various `Number` constants. */
+ var MAX_SAFE_INTEGER = 9007199254740991;
+
+ /** `Object#toString` result references. */
+ var argsTag = '[object Arguments]',
+ arrayTag = '[object Array]',
+ boolTag = '[object Boolean]',
+ dateTag = '[object Date]',
+ errorTag = '[object Error]',
+ funcTag = '[object Function]',
+ genTag = '[object GeneratorFunction]',
+ mapTag = '[object Map]',
+ numberTag = '[object Number]',
+ objectTag = '[object Object]',
+ promiseTag = '[object Promise]',
+ regexpTag = '[object RegExp]',
+ setTag = '[object Set]',
+ stringTag = '[object String]',
+ symbolTag = '[object Symbol]',
+ weakMapTag = '[object WeakMap]';
+
+ var arrayBufferTag = '[object ArrayBuffer]',
+ dataViewTag = '[object DataView]',
+ float32Tag = '[object Float32Array]',
+ float64Tag = '[object Float64Array]',
+ int8Tag = '[object Int8Array]',
+ int16Tag = '[object Int16Array]',
+ int32Tag = '[object Int32Array]',
+ uint8Tag = '[object Uint8Array]',
+ uint8ClampedTag = '[object Uint8ClampedArray]',
+ uint16Tag = '[object Uint16Array]',
+ uint32Tag = '[object Uint32Array]';
+
+ /**
+ * Used to match `RegExp`
+ * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
+ */
+ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
+
+ /** Used to detect host constructors (Safari). */
+ var reIsHostCtor = /^\[object .+?Constructor\]$/;
+
+ /** Used to detect unsigned integer values. */
+ var reIsUint = /^(?:0|[1-9]\d*)$/;
+
+ /** Used to identify `toStringTag` values of typed arrays. */
+ var typedArrayTags = {};
+ typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
+ typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
+ typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
+ typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
+ typedArrayTags[uint32Tag] = true;
+ typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
+ typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
+ typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
+ typedArrayTags[errorTag] = typedArrayTags[funcTag] =
+ typedArrayTags[mapTag] = typedArrayTags[numberTag] =
+ typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
+ typedArrayTags[setTag] = typedArrayTags[stringTag] =
+ typedArrayTags[weakMapTag] = false;
+
+ /** Detect free variable `global` from Node.js. */
+ var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
+
+ /** Detect free variable `self`. */
+ var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
+
+ /** Used as a reference to the global object. */
+ var root = freeGlobal || freeSelf || Function('return this')();
+
+ /** Detect free variable `exports`. */
+ var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
+
+ /** Detect free variable `module`. */
+ var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
+
+ /** Detect the popular CommonJS extension `module.exports`. */
+ var moduleExports = freeModule && freeModule.exports === freeExports;
+
+ /** Detect free variable `process` from Node.js. */
+ var freeProcess = moduleExports && freeGlobal.process;
+
+ /** Used to access faster Node.js helpers. */
+ var nodeUtil = (function() {
+ try {
+ return freeProcess && freeProcess.binding('util');
+ } catch (e) {}
+ }());
+
+ /* Node.js helper references. */
+ var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
+
+ /**
+ * A specialized version of `_.some` for arrays without support for iteratee
+ * shorthands.
+ *
+ * @private
+ * @param {Array} [array] The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ * else `false`.
+ */
+ function arraySome(array, predicate) {
+ var index = -1,
+ length = array ? array.length : 0;
+
+ while (++index < length) {
+ if (predicate(array[index], index, array)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * The base implementation of `_.times` without support for iteratee shorthands
+ * or max array length checks.
+ *
+ * @private
+ * @param {number} n The number of times to invoke `iteratee`.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the array of results.
+ */
+ function baseTimes(n, iteratee) {
+ var index = -1,
+ result = Array(n);
+
+ while (++index < n) {
+ result[index] = iteratee(index);
+ }
+ return result;
+ }
+
+ /**
+ * The base implementation of `_.unary` without support for storing metadata.
+ *
+ * @private
+ * @param {Function} func The function to cap arguments for.
+ * @returns {Function} Returns the new capped function.
+ */
+ function baseUnary(func) {
+ return function(value) {
+ return func(value);
+ };
+ }
+
+ /**
+ * Gets the value at `key` of `object`.
+ *
+ * @private
+ * @param {Object} [object] The object to query.
+ * @param {string} key The key of the property to get.
+ * @returns {*} Returns the property value.
+ */
+ function getValue(object, key) {
+ return object == null ? undefined : object[key];
+ }
+
+ /**
+ * Checks if `value` is a host object in IE < 9.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
+ */
+ function isHostObject(value) {
+ // Many host objects are `Object` objects that can coerce to strings
+ // despite having improperly defined `toString` methods.
+ var result = false;
+ if (value != null && typeof value.toString != 'function') {
+ try {
+ result = !!(value + '');
+ } catch (e) {}
+ }
+ return result;
+ }
+
+ /**
+ * Converts `map` to its key-value pairs.
+ *
+ * @private
+ * @param {Object} map The map to convert.
+ * @returns {Array} Returns the key-value pairs.
+ */
+ function mapToArray(map) {
+ var index = -1,
+ result = Array(map.size);
+
+ map.forEach(function(value, key) {
+ result[++index] = [key, value];
+ });
+ return result;
+ }
+
+ /**
+ * Creates a unary function that invokes `func` with its argument transformed.
+ *
+ * @private
+ * @param {Function} func The function to wrap.
+ * @param {Function} transform The argument transform.
+ * @returns {Function} Returns the new function.
+ */
+ function overArg(func, transform) {
+ return function(arg) {
+ return func(transform(arg));
+ };
+ }
+
+ /**
+ * Converts `set` to an array of its values.
+ *
+ * @private
+ * @param {Object} set The set to convert.
+ * @returns {Array} Returns the values.
+ */
+ function setToArray(set) {
+ var index = -1,
+ result = Array(set.size);
+
+ set.forEach(function(value) {
+ result[++index] = value;
+ });
+ return result;
+ }
+
+ /** Used for built-in method references. */
+ var arrayProto = Array.prototype,
+ funcProto = Function.prototype,
+ objectProto = Object.prototype;
+
+ /** Used to detect overreaching core-js shims. */
+ var coreJsData = root['__core-js_shared__'];
+
+ /** Used to detect methods masquerading as native. */
+ var maskSrcKey = (function() {
+ var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
+ return uid ? ('Symbol(src)_1.' + uid) : '';
+ }());
+
+ /** Used to resolve the decompiled source of functions. */
+ var funcToString = funcProto.toString;
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+ var objectToString = objectProto.toString;
+
+ /** Used to detect if a method is native. */
+ var reIsNative = RegExp('^' +
+ funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
+ .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+ );
+
+ /** Built-in value references. */
+ var Symbol = root.Symbol,
+ Uint8Array = root.Uint8Array,
+ propertyIsEnumerable = objectProto.propertyIsEnumerable,
+ splice = arrayProto.splice;
+
+ /* Built-in method references for those with the same name as other `lodash` methods. */
+ var nativeKeys = overArg(Object.keys, Object);
+
+ /* Built-in method references that are verified to be native. */
+ var DataView = getNative(root, 'DataView'),
+ Map = getNative(root, 'Map'),
+ Promise = getNative(root, 'Promise'),
+ Set = getNative(root, 'Set'),
+ WeakMap = getNative(root, 'WeakMap'),
+ nativeCreate = getNative(Object, 'create');
+
+ /** Used to detect maps, sets, and weakmaps. */
+ var dataViewCtorString = toSource(DataView),
+ mapCtorString = toSource(Map),
+ promiseCtorString = toSource(Promise),
+ setCtorString = toSource(Set),
+ weakMapCtorString = toSource(WeakMap);
+
+ /** Used to convert symbols to primitives and strings. */
+ var symbolProto = Symbol ? Symbol.prototype : undefined,
+ symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;
+
+ /**
+ * Creates a hash object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function Hash(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the hash.
+ *
+ * @private
+ * @name clear
+ * @memberOf Hash
+ */
+ function hashClear() {
+ this.__data__ = nativeCreate ? nativeCreate(null) : {};
+ }
+
+ /**
+ * Removes `key` and its value from the hash.
+ *
+ * @private
+ * @name delete
+ * @memberOf Hash
+ * @param {Object} hash The hash to modify.
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function hashDelete(key) {
+ return this.has(key) && delete this.__data__[key];
+ }
+
+ /**
+ * Gets the hash value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf Hash
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function hashGet(key) {
+ var data = this.__data__;
+ if (nativeCreate) {
+ var result = data[key];
+ return result === HASH_UNDEFINED ? undefined : result;
+ }
+ return hasOwnProperty.call(data, key) ? data[key] : undefined;
+ }
+
+ /**
+ * Checks if a hash value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf Hash
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function hashHas(key) {
+ var data = this.__data__;
+ return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
+ }
+
+ /**
+ * Sets the hash `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf Hash
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the hash instance.
+ */
+ function hashSet(key, value) {
+ var data = this.__data__;
+ data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
+ return this;
+ }
+
+ // Add methods to `Hash`.
+ Hash.prototype.clear = hashClear;
+ Hash.prototype['delete'] = hashDelete;
+ Hash.prototype.get = hashGet;
+ Hash.prototype.has = hashHas;
+ Hash.prototype.set = hashSet;
+
+ /**
+ * Creates an list cache object.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function ListCache(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the list cache.
+ *
+ * @private
+ * @name clear
+ * @memberOf ListCache
+ */
+ function listCacheClear() {
+ this.__data__ = [];
+ }
+
+ /**
+ * Removes `key` and its value from the list cache.
+ *
+ * @private
+ * @name delete
+ * @memberOf ListCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function listCacheDelete(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ return false;
+ }
+ var lastIndex = data.length - 1;
+ if (index == lastIndex) {
+ data.pop();
+ } else {
+ splice.call(data, index, 1);
+ }
+ return true;
+ }
+
+ /**
+ * Gets the list cache value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf ListCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function listCacheGet(key) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ return index < 0 ? undefined : data[index][1];
+ }
+
+ /**
+ * Checks if a list cache value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf ListCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function listCacheHas(key) {
+ return assocIndexOf(this.__data__, key) > -1;
+ }
+
+ /**
+ * Sets the list cache `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf ListCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the list cache instance.
+ */
+ function listCacheSet(key, value) {
+ var data = this.__data__,
+ index = assocIndexOf(data, key);
+
+ if (index < 0) {
+ data.push([key, value]);
+ } else {
+ data[index][1] = value;
+ }
+ return this;
+ }
+
+ // Add methods to `ListCache`.
+ ListCache.prototype.clear = listCacheClear;
+ ListCache.prototype['delete'] = listCacheDelete;
+ ListCache.prototype.get = listCacheGet;
+ ListCache.prototype.has = listCacheHas;
+ ListCache.prototype.set = listCacheSet;
+
+ /**
+ * Creates a map cache object to store key-value pairs.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function MapCache(entries) {
+ var index = -1,
+ length = entries ? entries.length : 0;
+
+ this.clear();
+ while (++index < length) {
+ var entry = entries[index];
+ this.set(entry[0], entry[1]);
+ }
+ }
+
+ /**
+ * Removes all key-value entries from the map.
+ *
+ * @private
+ * @name clear
+ * @memberOf MapCache
+ */
+ function mapCacheClear() {
+ this.__data__ = {
+ 'hash': new Hash,
+ 'map': new (Map || ListCache),
+ 'string': new Hash
+ };
+ }
+
+ /**
+ * Removes `key` and its value from the map.
+ *
+ * @private
+ * @name delete
+ * @memberOf MapCache
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function mapCacheDelete(key) {
+ return getMapData(this, key)['delete'](key);
+ }
+
+ /**
+ * Gets the map value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf MapCache
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function mapCacheGet(key) {
+ return getMapData(this, key).get(key);
+ }
+
+ /**
+ * Checks if a map value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf MapCache
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function mapCacheHas(key) {
+ return getMapData(this, key).has(key);
+ }
+
+ /**
+ * Sets the map `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf MapCache
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the map cache instance.
+ */
+ function mapCacheSet(key, value) {
+ getMapData(this, key).set(key, value);
+ return this;
+ }
+
+ // Add methods to `MapCache`.
+ MapCache.prototype.clear = mapCacheClear;
+ MapCache.prototype['delete'] = mapCacheDelete;
+ MapCache.prototype.get = mapCacheGet;
+ MapCache.prototype.has = mapCacheHas;
+ MapCache.prototype.set = mapCacheSet;
+
+ /**
+ *
+ * Creates an array cache object to store unique values.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [values] The values to cache.
+ */
+ function SetCache(values) {
+ var index = -1,
+ length = values ? values.length : 0;
+
+ this.__data__ = new MapCache;
+ while (++index < length) {
+ this.add(values[index]);
+ }
+ }
+
+ /**
+ * Adds `value` to the array cache.
+ *
+ * @private
+ * @name add
+ * @memberOf SetCache
+ * @alias push
+ * @param {*} value The value to cache.
+ * @returns {Object} Returns the cache instance.
+ */
+ function setCacheAdd(value) {
+ this.__data__.set(value, HASH_UNDEFINED);
+ return this;
+ }
+
+ /**
+ * Checks if `value` is in the array cache.
+ *
+ * @private
+ * @name has
+ * @memberOf SetCache
+ * @param {*} value The value to search for.
+ * @returns {number} Returns `true` if `value` is found, else `false`.
+ */
+ function setCacheHas(value) {
+ return this.__data__.has(value);
+ }
+
+ // Add methods to `SetCache`.
+ SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
+ SetCache.prototype.has = setCacheHas;
+
+ /**
+ * Creates a stack cache object to store key-value pairs.
+ *
+ * @private
+ * @constructor
+ * @param {Array} [entries] The key-value pairs to cache.
+ */
+ function Stack(entries) {
+ this.__data__ = new ListCache(entries);
+ }
+
+ /**
+ * Removes all key-value entries from the stack.
+ *
+ * @private
+ * @name clear
+ * @memberOf Stack
+ */
+ function stackClear() {
+ this.__data__ = new ListCache;
+ }
+
+ /**
+ * Removes `key` and its value from the stack.
+ *
+ * @private
+ * @name delete
+ * @memberOf Stack
+ * @param {string} key The key of the value to remove.
+ * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+ */
+ function stackDelete(key) {
+ return this.__data__['delete'](key);
+ }
+
+ /**
+ * Gets the stack value for `key`.
+ *
+ * @private
+ * @name get
+ * @memberOf Stack
+ * @param {string} key The key of the value to get.
+ * @returns {*} Returns the entry value.
+ */
+ function stackGet(key) {
+ return this.__data__.get(key);
+ }
+
+ /**
+ * Checks if a stack value for `key` exists.
+ *
+ * @private
+ * @name has
+ * @memberOf Stack
+ * @param {string} key The key of the entry to check.
+ * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+ */
+ function stackHas(key) {
+ return this.__data__.has(key);
+ }
+
+ /**
+ * Sets the stack `key` to `value`.
+ *
+ * @private
+ * @name set
+ * @memberOf Stack
+ * @param {string} key The key of the value to set.
+ * @param {*} value The value to set.
+ * @returns {Object} Returns the stack cache instance.
+ */
+ function stackSet(key, value) {
+ var cache = this.__data__;
+ if (cache instanceof ListCache) {
+ var pairs = cache.__data__;
+ if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
+ pairs.push([key, value]);
+ return this;
+ }
+ cache = this.__data__ = new MapCache(pairs);
+ }
+ cache.set(key, value);
+ return this;
+ }
+
+ // Add methods to `Stack`.
+ Stack.prototype.clear = stackClear;
+ Stack.prototype['delete'] = stackDelete;
+ Stack.prototype.get = stackGet;
+ Stack.prototype.has = stackHas;
+ Stack.prototype.set = stackSet;
+
+ /**
+ * Creates an array of the enumerable property names of the array-like `value`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @param {boolean} inherited Specify returning inherited property names.
+ * @returns {Array} Returns the array of property names.
+ */
+ function arrayLikeKeys(value, inherited) {
+ // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
+ // Safari 9 makes `arguments.length` enumerable in strict mode.
+ var result = (isArray(value) || isArguments(value))
+ ? baseTimes(value.length, String)
+ : [];
+
+ var length = result.length,
+ skipIndexes = !!length;
+
+ for (var key in value) {
+ if ((inherited || hasOwnProperty.call(value, key)) &&
+ !(skipIndexes && (key == 'length' || isIndex(key, length)))) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the index at which the `key` is found in `array` of key-value pairs.
+ *
+ * @private
+ * @param {Array} array The array to inspect.
+ * @param {*} key The key to search for.
+ * @returns {number} Returns the index of the matched value, else `-1`.
+ */
+ function assocIndexOf(array, key) {
+ var length = array.length;
+ while (length--) {
+ if (eq(array[length][0], key)) {
+ return length;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * The base implementation of `getTag`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+ function baseGetTag(value) {
+ return objectToString.call(value);
+ }
+
+ /**
+ * The base implementation of `_.isEqual` which supports partial comparisons
+ * and tracks traversed objects.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparisons.
+ * @param {boolean} [bitmask] The bitmask of comparison flags.
+ * The bitmask may be composed of the following flags:
+ * 1 - Unordered comparison
+ * 2 - Partial comparison
+ * @param {Object} [stack] Tracks traversed `value` and `other` objects.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ */
+ function baseIsEqual(value, other, customizer, bitmask, stack) {
+ if (value === other) {
+ return true;
+ }
+ if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) {
+ return value !== value && other !== other;
+ }
+ return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stack);
+ }
+
+ /**
+ * A specialized version of `baseIsEqual` for arrays and objects which performs
+ * deep comparisons and tracks traversed objects enabling objects with circular
+ * references to be compared.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparisons.
+ * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual`
+ * for more details.
+ * @param {Object} [stack] Tracks traversed `object` and `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stack) {
+ var objIsArr = isArray(object),
+ othIsArr = isArray(other),
+ objTag = arrayTag,
+ othTag = arrayTag;
+
+ if (!objIsArr) {
+ objTag = getTag(object);
+ objTag = objTag == argsTag ? objectTag : objTag;
+ }
+ if (!othIsArr) {
+ othTag = getTag(other);
+ othTag = othTag == argsTag ? objectTag : othTag;
+ }
+ var objIsObj = objTag == objectTag && !isHostObject(object),
+ othIsObj = othTag == objectTag && !isHostObject(other),
+ isSameTag = objTag == othTag;
+
+ if (isSameTag && !objIsObj) {
+ stack || (stack = new Stack);
+ return (objIsArr || isTypedArray(object))
+ ? equalArrays(object, other, equalFunc, customizer, bitmask, stack)
+ : equalByTag(object, other, objTag, equalFunc, customizer, bitmask, stack);
+ }
+ if (!(bitmask & PARTIAL_COMPARE_FLAG)) {
+ var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
+ othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
+
+ if (objIsWrapped || othIsWrapped) {
+ var objUnwrapped = objIsWrapped ? object.value() : object,
+ othUnwrapped = othIsWrapped ? other.value() : other;
+
+ stack || (stack = new Stack);
+ return equalFunc(objUnwrapped, othUnwrapped, customizer, bitmask, stack);
+ }
+ }
+ if (!isSameTag) {
+ return false;
+ }
+ stack || (stack = new Stack);
+ return equalObjects(object, other, equalFunc, customizer, bitmask, stack);
+ }
+
+ /**
+ * The base implementation of `_.isNative` without bad shim checks.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function,
+ * else `false`.
+ */
+ function baseIsNative(value) {
+ if (!isObject(value) || isMasked(value)) {
+ return false;
+ }
+ var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;
+ return pattern.test(toSource(value));
+ }
+
+ /**
+ * The base implementation of `_.isTypedArray` without Node.js optimizations.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
+ */
+ function baseIsTypedArray(value) {
+ return isObjectLike(value) &&
+ isLength(value.length) && !!typedArrayTags[objectToString.call(value)];
+ }
+
+ /**
+ * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+ function baseKeys(object) {
+ if (!isPrototype(object)) {
+ return nativeKeys(object);
+ }
+ var result = [];
+ for (var key in Object(object)) {
+ if (hasOwnProperty.call(object, key) && key != 'constructor') {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for arrays with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Array} array The array to compare.
+ * @param {Array} other The other array to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} customizer The function to customize comparisons.
+ * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
+ * for more details.
+ * @param {Object} stack Tracks traversed `array` and `other` objects.
+ * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
+ */
+ function equalArrays(array, other, equalFunc, customizer, bitmask, stack) {
+ var isPartial = bitmask & PARTIAL_COMPARE_FLAG,
+ arrLength = array.length,
+ othLength = other.length;
+
+ if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
+ return false;
+ }
+ // Assume cyclic values are equal.
+ var stacked = stack.get(array);
+ if (stacked && stack.get(other)) {
+ return stacked == other;
+ }
+ var index = -1,
+ result = true,
+ seen = (bitmask & UNORDERED_COMPARE_FLAG) ? new SetCache : undefined;
+
+ stack.set(array, other);
+ stack.set(other, array);
+
+ // Ignore non-index properties.
+ while (++index < arrLength) {
+ var arrValue = array[index],
+ othValue = other[index];
+
+ if (customizer) {
+ var compared = isPartial
+ ? customizer(othValue, arrValue, index, other, array, stack)
+ : customizer(arrValue, othValue, index, array, other, stack);
+ }
+ if (compared !== undefined) {
+ if (compared) {
+ continue;
+ }
+ result = false;
+ break;
+ }
+ // Recursively compare arrays (susceptible to call stack limits).
+ if (seen) {
+ if (!arraySome(other, function(othValue, othIndex) {
+ if (!seen.has(othIndex) &&
+ (arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack))) {
+ return seen.add(othIndex);
+ }
+ })) {
+ result = false;
+ break;
+ }
+ } else if (!(
+ arrValue === othValue ||
+ equalFunc(arrValue, othValue, customizer, bitmask, stack)
+ )) {
+ result = false;
+ break;
+ }
+ }
+ stack['delete'](array);
+ stack['delete'](other);
+ return result;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for comparing objects of
+ * the same `toStringTag`.
+ *
+ * **Note:** This function only supports comparing values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {string} tag The `toStringTag` of the objects to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} customizer The function to customize comparisons.
+ * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
+ * for more details.
+ * @param {Object} stack Tracks traversed `object` and `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalByTag(object, other, tag, equalFunc, customizer, bitmask, stack) {
+ switch (tag) {
+ case dataViewTag:
+ if ((object.byteLength != other.byteLength) ||
+ (object.byteOffset != other.byteOffset)) {
+ return false;
+ }
+ object = object.buffer;
+ other = other.buffer;
+
+ case arrayBufferTag:
+ if ((object.byteLength != other.byteLength) ||
+ !equalFunc(new Uint8Array(object), new Uint8Array(other))) {
+ return false;
+ }
+ return true;
+
+ case boolTag:
+ case dateTag:
+ case numberTag:
+ // Coerce booleans to `1` or `0` and dates to milliseconds.
+ // Invalid dates are coerced to `NaN`.
+ return eq(+object, +other);
+
+ case errorTag:
+ return object.name == other.name && object.message == other.message;
+
+ case regexpTag:
+ case stringTag:
+ // Coerce regexes to strings and treat strings, primitives and objects,
+ // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
+ // for more details.
+ return object == (other + '');
+
+ case mapTag:
+ var convert = mapToArray;
+
+ case setTag:
+ var isPartial = bitmask & PARTIAL_COMPARE_FLAG;
+ convert || (convert = setToArray);
+
+ if (object.size != other.size && !isPartial) {
+ return false;
+ }
+ // Assume cyclic values are equal.
+ var stacked = stack.get(object);
+ if (stacked) {
+ return stacked == other;
+ }
+ bitmask |= UNORDERED_COMPARE_FLAG;
+
+ // Recursively compare objects (susceptible to call stack limits).
+ stack.set(object, other);
+ var result = equalArrays(convert(object), convert(other), equalFunc, customizer, bitmask, stack);
+ stack['delete'](object);
+ return result;
+
+ case symbolTag:
+ if (symbolValueOf) {
+ return symbolValueOf.call(object) == symbolValueOf.call(other);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A specialized version of `baseIsEqualDeep` for objects with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} customizer The function to customize comparisons.
+ * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
+ * for more details.
+ * @param {Object} stack Tracks traversed `object` and `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+ function equalObjects(object, other, equalFunc, customizer, bitmask, stack) {
+ var isPartial = bitmask & PARTIAL_COMPARE_FLAG,
+ objProps = keys(object),
+ objLength = objProps.length,
+ othProps = keys(other),
+ othLength = othProps.length;
+
+ if (objLength != othLength && !isPartial) {
+ return false;
+ }
+ var index = objLength;
+ while (index--) {
+ var key = objProps[index];
+ if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {
+ return false;
+ }
+ }
+ // Assume cyclic values are equal.
+ var stacked = stack.get(object);
+ if (stacked && stack.get(other)) {
+ return stacked == other;
+ }
+ var result = true;
+ stack.set(object, other);
+ stack.set(other, object);
+
+ var skipCtor = isPartial;
+ while (++index < objLength) {
+ key = objProps[index];
+ var objValue = object[key],
+ othValue = other[key];
+
+ if (customizer) {
+ var compared = isPartial
+ ? customizer(othValue, objValue, key, other, object, stack)
+ : customizer(objValue, othValue, key, object, other, stack);
+ }
+ // Recursively compare objects (susceptible to call stack limits).
+ if (!(compared === undefined
+ ? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stack))
+ : compared
+ )) {
+ result = false;
+ break;
+ }
+ skipCtor || (skipCtor = key == 'constructor');
+ }
+ if (result && !skipCtor) {
+ var objCtor = object.constructor,
+ othCtor = other.constructor;
+
+ // Non `Object` object instances with different constructors are not equal.
+ if (objCtor != othCtor &&
+ ('constructor' in object && 'constructor' in other) &&
+ !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
+ typeof othCtor == 'function' && othCtor instanceof othCtor)) {
+ result = false;
+ }
+ }
+ stack['delete'](object);
+ stack['delete'](other);
+ return result;
+ }
+
+ /**
+ * Gets the data for `map`.
+ *
+ * @private
+ * @param {Object} map The map to query.
+ * @param {string} key The reference key.
+ * @returns {*} Returns the map data.
+ */
+ function getMapData(map, key) {
+ var data = map.__data__;
+ return isKeyable(key)
+ ? data[typeof key == 'string' ? 'string' : 'hash']
+ : data.map;
+ }
+
+ /**
+ * Gets the native function at `key` of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the method to get.
+ * @returns {*} Returns the function if it's native, else `undefined`.
+ */
+ function getNative(object, key) {
+ var value = getValue(object, key);
+ return baseIsNative(value) ? value : undefined;
+ }
+
+ /**
+ * Gets the `toStringTag` of `value`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+ var getTag = baseGetTag;
+
+ // Fallback for data views, maps, sets, and weak maps in IE 11,
+ // for data views in Edge < 14, and promises in Node.js.
+ if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
+ (Map && getTag(new Map) != mapTag) ||
+ (Promise && getTag(Promise.resolve()) != promiseTag) ||
+ (Set && getTag(new Set) != setTag) ||
+ (WeakMap && getTag(new WeakMap) != weakMapTag)) {
+ getTag = function(value) {
+ var result = objectToString.call(value),
+ Ctor = result == objectTag ? value.constructor : undefined,
+ ctorString = Ctor ? toSource(Ctor) : undefined;
+
+ if (ctorString) {
+ switch (ctorString) {
+ case dataViewCtorString: return dataViewTag;
+ case mapCtorString: return mapTag;
+ case promiseCtorString: return promiseTag;
+ case setCtorString: return setTag;
+ case weakMapCtorString: return weakMapTag;
+ }
+ }
+ return result;
+ };
+ }
+
+ /**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+ function isIndex(value, length) {
+ length = length == null ? MAX_SAFE_INTEGER : length;
+ return !!length &&
+ (typeof value == 'number' || reIsUint.test(value)) &&
+ (value > -1 && value % 1 == 0 && value < length);
+ }
+
+ /**
+ * Checks if `value` is suitable for use as unique object key.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
+ */
+ function isKeyable(value) {
+ var type = typeof value;
+ return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
+ ? (value !== '__proto__')
+ : (value === null);
+ }
+
+ /**
+ * Checks if `func` has its source masked.
+ *
+ * @private
+ * @param {Function} func The function to check.
+ * @returns {boolean} Returns `true` if `func` is masked, else `false`.
+ */
+ function isMasked(func) {
+ return !!maskSrcKey && (maskSrcKey in func);
+ }
+
+ /**
+ * Checks if `value` is likely a prototype object.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
+ */
+ function isPrototype(value) {
+ var Ctor = value && value.constructor,
+ proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
+
+ return value === proto;
+ }
+
+ /**
+ * Converts `func` to its source code.
+ *
+ * @private
+ * @param {Function} func The function to process.
+ * @returns {string} Returns the source code.
+ */
+ function toSource(func) {
+ if (func != null) {
+ try {
+ return funcToString.call(func);
+ } catch (e) {}
+ try {
+ return (func + '');
+ } catch (e) {}
+ }
+ return '';
+ }
+
+ /**
+ * Performs a
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+ * comparison between two values to determine if they are equivalent.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'a': 1 };
+ * var other = { 'a': 1 };
+ *
+ * _.eq(object, object);
+ * // => true
+ *
+ * _.eq(object, other);
+ * // => false
+ *
+ * _.eq('a', 'a');
+ * // => true
+ *
+ * _.eq('a', Object('a'));
+ * // => false
+ *
+ * _.eq(NaN, NaN);
+ * // => true
+ */
+ function eq(value, other) {
+ return value === other || (value !== value && other !== other);
+ }
+
+ /**
+ * Checks if `value` is likely an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an `arguments` object,
+ * else `false`.
+ * @example
+ *
+ * _.isArguments(function() { return arguments; }());
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+ function isArguments(value) {
+ // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
+ return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&
+ (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);
+ }
+
+ /**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * _.isArray(document.body.children);
+ * // => false
+ *
+ * _.isArray('abc');
+ * // => false
+ *
+ * _.isArray(_.noop);
+ * // => false
+ */
+ var isArray = Array.isArray;
+
+ /**
+ * Checks if `value` is array-like. A value is considered array-like if it's
+ * not a function and has a `value.length` that's an integer greater than or
+ * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+ * @example
+ *
+ * _.isArrayLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLike(document.body.children);
+ * // => true
+ *
+ * _.isArrayLike('abc');
+ * // => true
+ *
+ * _.isArrayLike(_.noop);
+ * // => false
+ */
+ function isArrayLike(value) {
+ return value != null && isLength(value.length) && !isFunction(value);
+ }
+
+ /**
+ * This method is like `_.isArrayLike` except that it also checks if `value`
+ * is an object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array-like object,
+ * else `false`.
+ * @example
+ *
+ * _.isArrayLikeObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLikeObject(document.body.children);
+ * // => true
+ *
+ * _.isArrayLikeObject('abc');
+ * // => false
+ *
+ * _.isArrayLikeObject(_.noop);
+ * // => false
+ */
+ function isArrayLikeObject(value) {
+ return isObjectLike(value) && isArrayLike(value);
+ }
+
+ /**
+ * Performs a deep comparison between two values to determine if they are
+ * equivalent.
+ *
+ * **Note:** This method supports comparing arrays, array buffers, booleans,
+ * date objects, error objects, maps, numbers, `Object` objects, regexes,
+ * sets, strings, symbols, and typed arrays. `Object` objects are compared
+ * by their own, not inherited, enumerable properties. Functions and DOM
+ * nodes are **not** supported.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'a': 1 };
+ * var other = { 'a': 1 };
+ *
+ * _.isEqual(object, other);
+ * // => true
+ *
+ * object === other;
+ * // => false
+ */
+ function isEqual(value, other) {
+ return baseIsEqual(value, other);
+ }
+
+ /**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a function, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+ function isFunction(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in Safari 8-9 which returns 'object' for typed array and other constructors.
+ var tag = isObject(value) ? objectToString.call(value) : '';
+ return tag == funcTag || tag == genTag;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This method is loosely based on
+ * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ * @example
+ *
+ * _.isLength(3);
+ * // => true
+ *
+ * _.isLength(Number.MIN_VALUE);
+ * // => false
+ *
+ * _.isLength(Infinity);
+ * // => false
+ *
+ * _.isLength('3');
+ * // => false
+ */
+ function isLength(value) {
+ return typeof value == 'number' &&
+ value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+ }
+
+ /**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+ function isObject(value) {
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+ }
+
+ /**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+ function isObjectLike(value) {
+ return !!value && typeof value == 'object';
+ }
+
+ /**
+ * Checks if `value` is classified as a typed array.
+ *
+ * @static
+ * @memberOf _
+ * @since 3.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
+ * @example
+ *
+ * _.isTypedArray(new Uint8Array);
+ * // => true
+ *
+ * _.isTypedArray([]);
+ * // => false
+ */
+ var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;
+
+ /**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @since 0.1.0
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+ function keys(object) {
+ return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
+ }
+
+ module.exports = isEqual;
+
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(33)(module)))
+
+/***/ },
+/* 71 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(72);
+
+/***/ },
+/* 72 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ var _styler = __webpack_require__(15);
+
+ var _styler2 = _interopRequireDefault(_styler);
+
+ var _style = __webpack_require__(73);
+
+ var _style2 = _interopRequireDefault(_style);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var HTMLImg = function (_Playback) {
+ _inherits(HTMLImg, _Playback);
+
+ HTMLImg.prototype.getPlaybackType = function getPlaybackType() {
+ return _playback2.default.NO_OP;
+ };
+
+ _createClass(HTMLImg, [{
+ key: 'name',
+ get: function get() {
+ return 'html_img';
+ }
+ }, {
+ key: 'tagName',
+ get: function get() {
+ return 'img';
+ }
+ }, {
+ key: 'attributes',
+ get: function get() {
+ return {
+ 'data-html-img': ''
+ };
+ }
+ }, {
+ key: 'events',
+ get: function get() {
+ return {
+ 'load': '_onLoad',
+ 'abort': '_onError',
+ 'error': '_onError'
+ };
+ }
+ }]);
+
+ function HTMLImg(params) {
+ _classCallCheck(this, HTMLImg);
+
+ var _this = _possibleConstructorReturn(this, _Playback.call(this, params));
+
+ _this.el.src = params.src;
+ return _this;
+ }
+
+ HTMLImg.prototype.render = function render() {
+ var style = _styler2.default.getStyleFor(_style2.default);
+ this.$el.append(style);
+ this.trigger(_events2.default.PLAYBACK_READY, this.name);
+ return this;
+ };
+
+ HTMLImg.prototype._onLoad = function _onLoad() {
+ this.trigger(_events2.default.PLAYBACK_ENDED, this.name);
+ };
+
+ HTMLImg.prototype._onError = function _onError(evt) {
+ var m = evt.type === 'error' ? 'load error' : 'loading aborted';
+ this.trigger(_events2.default.PLAYBACK_ERROR, { message: m }, this.name);
+ };
+
+ return HTMLImg;
+ }(_playback2.default);
+
+ exports.default = HTMLImg;
+
+
+ HTMLImg.canPlay = function (resource) {
+ return (/\.(png|jpg|jpeg|gif|bmp|tiff|pgm|pnm|webp)(|\?.*)$/i.test(resource)
+ );
+ };
+ module.exports = exports['default'];
+
+/***/ },
+/* 73 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(25)();
+ // imports
+
+
+ // module
+ exports.push([module.id, "[data-html-img] {\n max-width: 100%;\n max-height: 100%; }\n", ""]);
+
+ // exports
+
+
+/***/ },
+/* 74 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(75);
+
+/***/ },
+/* 75 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _utils = __webpack_require__(2);
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ var _template = __webpack_require__(17);
+
+ var _template2 = _interopRequireDefault(_template);
+
+ var _styler = __webpack_require__(15);
+
+ var _styler2 = _interopRequireDefault(_styler);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _style = __webpack_require__(76);
+
+ var _style2 = _interopRequireDefault(_style);
+
+ var _error = __webpack_require__(77);
+
+ var _error2 = _interopRequireDefault(_error);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var NoOp = function (_Playback) {
+ _inherits(NoOp, _Playback);
+
+ _createClass(NoOp, [{
+ key: 'name',
+ get: function get() {
+ return 'no_op';
+ }
+ }, {
+ key: 'template',
+ get: function get() {
+ return (0, _template2.default)(_error2.default);
+ }
+ }, {
+ key: 'attributes',
+ get: function get() {
+ return { 'data-no-op': '' };
+ }
+ }]);
+
+ function NoOp() {
+ _classCallCheck(this, NoOp);
+
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ var _this = _possibleConstructorReturn(this, _Playback.call.apply(_Playback, [this].concat(args)));
+
+ _this._noiseFrameNum = -1;
+ _this._started = false;
+ return _this;
+ }
+
+ NoOp.prototype.render = function render() {
+ var style = _styler2.default.getStyleFor(_style2.default);
+ var playbackNotSupported = this.options.playbackNotSupportedMessage || this.i18n.t('playback_not_supported');
+ this.$el.html(this.template({ message: playbackNotSupported }));
+ this.$el.append(style);
+ this.trigger(_events2.default.PLAYBACK_READY, this.name);
+ var showForNoOp = !!(this.options.poster && this.options.poster.showForNoOp);
+ if (this.options.autoPlay || !showForNoOp) {
+ this.play();
+ }
+ return this;
+ };
+
+ NoOp.prototype.play = function play() {
+ if (!this._started) {
+ this._started = true;
+ this.trigger(_events2.default.PLAYBACK_PLAY);
+ this._animate();
+ }
+ };
+
+ NoOp.prototype._noise = function _noise() {
+ this._noiseFrameNum = (this._noiseFrameNum + 1) % 5;
+ if (this._noiseFrameNum) {
+ // only update noise every 5 frames to save cpu
+ return;
+ }
+
+ var idata = this.context.createImageData(this.context.canvas.width, this.context.canvas.height);
+ var buffer32 = void 0;
+ try {
+ buffer32 = new Uint32Array(idata.data.buffer);
+ } catch (err) {
+ buffer32 = new Uint32Array(this.context.canvas.width * this.context.canvas.height * 4);
+ var data = idata.data;
+ for (var i = 0; i < data.length; i++) {
+ buffer32[i] = data[i];
+ }
+ }
+
+ var len = buffer32.length,
+ m = Math.random() * 6 + 4;
+ var run = 0,
+ color = 0;
+ for (var _i = 0; _i < len;) {
+ if (run < 0) {
+ run = m * Math.random();
+ var p = Math.pow(Math.random(), 0.4);
+ color = 255 * p << 24;
+ }
+ run -= 1;
+ buffer32[_i++] = color;
+ }
+ this.context.putImageData(idata, 0, 0);
+ };
+
+ NoOp.prototype._loop = function _loop() {
+ var _this2 = this;
+
+ if (this._stop) {
+ return;
+ }
+ this._noise();
+ this._animationHandle = (0, _utils.requestAnimationFrame)(function () {
+ return _this2._loop();
+ });
+ };
+
+ NoOp.prototype.destroy = function destroy() {
+ if (this._animationHandle) {
+ (0, _utils.cancelAnimationFrame)(this._animationHandle);
+ this._stop = true;
+ }
+ };
+
+ NoOp.prototype._animate = function _animate() {
+ this.canvas = this.$el.find('canvas[data-no-op-canvas]')[0];
+ this.context = this.canvas.getContext('2d');
+ this._loop();
+ };
+
+ return NoOp;
+ }(_playback2.default);
+
+ exports.default = NoOp;
+
+
+ NoOp.canPlay = function (source) {
+ // eslint-disable-line no-unused-vars
+ return true;
+ };
+ module.exports = exports['default'];
+
+/***/ },
+/* 76 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(25)();
+ // imports
+
+
+ // module
+ exports.push([module.id, "[data-no-op] {\n position: absolute;\n height: 100%;\n width: 100%;\n text-align: center; }\n\n[data-no-op] p[data-no-op-msg] {\n position: absolute;\n text-align: center;\n font-size: 25px;\n left: 0;\n right: 0;\n color: white;\n padding: 10px;\n /* center vertically */\n top: 50%;\n -webkit-transform: translateY(-50%);\n -moz-transform: translateY(-50%);\n -ms-transform: translateY(-50%);\n -o-transform: translateY(-50%);\n transform: translateY(-50%);\n max-height: 100%;\n overflow: auto; }\n\n[data-no-op] canvas[data-no-op-canvas] {\n background-color: #777;\n height: 100%;\n width: 100%; }\n", ""]);
+
+ // exports
+
+
+/***/ },
+/* 77 */
+/***/ function(module, exports) {
+
+ module.exports = "<canvas data-no-op-canvas></canvas>\n<p data-no-op-msg><%=message%><p>\n";
+
+/***/ },
+/* 78 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(79);
+
+/***/ },
+/* 79 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _ui_container_plugin = __webpack_require__(80);
+
+ var _ui_container_plugin2 = _interopRequireDefault(_ui_container_plugin);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _styler = __webpack_require__(15);
+
+ var _styler2 = _interopRequireDefault(_styler);
+
+ var _template = __webpack_require__(17);
+
+ var _template2 = _interopRequireDefault(_template);
+
+ var _spinner = __webpack_require__(81);
+
+ var _spinner2 = _interopRequireDefault(_spinner);
+
+ var _spinner3 = __webpack_require__(82);
+
+ var _spinner4 = _interopRequireDefault(_spinner3);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var SpinnerThreeBouncePlugin = function (_UIContainerPlugin) {
+ _inherits(SpinnerThreeBouncePlugin, _UIContainerPlugin);
+
+ _createClass(SpinnerThreeBouncePlugin, [{
+ key: 'name',
+ get: function get() {
+ return 'spinner';
+ }
+ }, {
+ key: 'attributes',
+ get: function get() {
+ return {
+ 'data-spinner': '',
+ 'class': 'spinner-three-bounce'
+ };
+ }
+ }]);
+
+ function SpinnerThreeBouncePlugin(container) {
+ _classCallCheck(this, SpinnerThreeBouncePlugin);
+
+ var _this = _possibleConstructorReturn(this, _UIContainerPlugin.call(this, container));
+
+ _this.template = (0, _template2.default)(_spinner2.default);
+ _this.showTimeout = null;
+ _this.listenTo(_this.container, _events2.default.CONTAINER_STATE_BUFFERING, _this.onBuffering);
+ _this.listenTo(_this.container, _events2.default.CONTAINER_STATE_BUFFERFULL, _this.onBufferFull);
+ _this.listenTo(_this.container, _events2.default.CONTAINER_STOP, _this.onStop);
+ _this.listenTo(_this.container, _events2.default.CONTAINER_ENDED, _this.onStop);
+ _this.listenTo(_this.container, _events2.default.CONTAINER_ERROR, _this.onStop);
+ _this.render();
+ return _this;
+ }
+
+ SpinnerThreeBouncePlugin.prototype.onBuffering = function onBuffering() {
+ this.show();
+ };
+
+ SpinnerThreeBouncePlugin.prototype.onBufferFull = function onBufferFull() {
+ this.hide();
+ };
+
+ SpinnerThreeBouncePlugin.prototype.onStop = function onStop() {
+ this.hide();
+ };
+
+ SpinnerThreeBouncePlugin.prototype.show = function show() {
+ var _this2 = this;
+
+ if (this.showTimeout === null) {
+ this.showTimeout = setTimeout(function () {
+ return _this2.$el.show();
+ }, 300);
+ }
+ };
+
+ SpinnerThreeBouncePlugin.prototype.hide = function hide() {
+ if (this.showTimeout !== null) {
+ clearTimeout(this.showTimeout);
+ this.showTimeout = null;
+ }
+ this.$el.hide();
+ };
+
+ SpinnerThreeBouncePlugin.prototype.render = function render() {
+ this.$el.html(this.template());
+ var style = _styler2.default.getStyleFor(_spinner4.default);
+ this.container.$el.append(style);
+ this.container.$el.append(this.$el);
+ this.$el.hide();
+ if (this.container.buffering) {
+ this.onBuffering();
+ }
+ return this;
+ };
+
+ return SpinnerThreeBouncePlugin;
+ }(_ui_container_plugin2.default);
+
+ exports.default = SpinnerThreeBouncePlugin;
+ module.exports = exports['default'];
+
+/***/ },
+/* 80 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _utils = __webpack_require__(2);
+
+ var _ui_object = __webpack_require__(18);
+
+ var _ui_object2 = _interopRequireDefault(_ui_object);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ /**
+ * The base class for an ui container plugin
+ * @class UIContainerPlugin
+ * @constructor
+ * @extends UIObject
+ * @module base
+ */
+ var UIContainerPlugin = function (_UIObject) {
+ _inherits(UIContainerPlugin, _UIObject);
+
+ function UIContainerPlugin(container) {
+ _classCallCheck(this, UIContainerPlugin);
+
+ var _this = _possibleConstructorReturn(this, _UIObject.call(this, container.options));
+
+ _this.container = container;
+ _this.enabled = true;
+ _this.bindEvents();
+ return _this;
+ }
+
+ UIContainerPlugin.prototype.enable = function enable() {
+ if (!this.enabled) {
+ this.bindEvents();
+ this.$el.show();
+ this.enabled = true;
+ }
+ };
+
+ UIContainerPlugin.prototype.disable = function disable() {
+ this.stopListening();
+ this.$el.hide();
+ this.enabled = false;
+ };
+
+ UIContainerPlugin.prototype.bindEvents = function bindEvents() {};
+
+ UIContainerPlugin.prototype.destroy = function destroy() {
+ this.remove();
+ };
+
+ return UIContainerPlugin;
+ }(_ui_object2.default);
+
+ exports.default = UIContainerPlugin;
+
+
+ UIContainerPlugin.extend = function (properties) {
+ return (0, _utils.extend)(UIContainerPlugin, properties);
+ };
+
+ UIContainerPlugin.type = 'container';
+ module.exports = exports['default'];
+
+/***/ },
+/* 81 */
+/***/ function(module, exports) {
+
+ module.exports = "<div data-bounce1></div><div data-bounce2></div><div data-bounce3></div>\n";
+
+/***/ },
+/* 82 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(25)();
+ // imports
+
+
+ // module
+ exports.push([module.id, ".spinner-three-bounce[data-spinner] {\n position: absolute;\n margin: 0 auto;\n width: 70px;\n text-align: center;\n z-index: 999;\n left: 0;\n right: 0;\n margin-left: auto;\n margin-right: auto;\n /* center vertically */\n top: 50%;\n -webkit-transform: translateY(-50%);\n -moz-transform: translateY(-50%);\n -ms-transform: translateY(-50%);\n -o-transform: translateY(-50%);\n transform: translateY(-50%); }\n .spinner-three-bounce[data-spinner] > div {\n width: 18px;\n height: 18px;\n background-color: #FFFFFF;\n border-radius: 100%;\n display: inline-block;\n -webkit-animation: bouncedelay 1.4s infinite ease-in-out;\n -moz-animation: bouncedelay 1.4s infinite ease-in-out;\n animation: bouncedelay 1.4s infinite ease-in-out;\n /* Prevent first frame from flickering when animation starts */\n -webkit-animation-fill-mode: both;\n -moz-animation-fill-mode: both;\n animation-fill-mode: both; }\n .spinner-three-bounce[data-spinner] [data-bounce1] {\n -webkit-animation-delay: -0.32s;\n -moz-animation-delay: -0.32s;\n animation-delay: -0.32s; }\n .spinner-three-bounce[data-spinner] [data-bounce2] {\n -webkit-animation-delay: -0.16s;\n -moz-animation-delay: -0.16s;\n animation-delay: -0.16s; }\n\n@-webkit-keyframes bouncedelay {\n 0%, 80%, 100% {\n -webkit-transform: scale(0); }\n 40% {\n -webkit-transform: scale(1); } }\n\n@-moz-keyframes bouncedelay {\n 0%, 80%, 100% {\n -moz-transform: scale(0); }\n 40% {\n -moz-transform: scale(1); } }\n\n@keyframes bouncedelay {\n 0%, 80%, 100% {\n -webkit-transform: scale(0);\n -moz-transform: scale(0);\n -ms-transform: scale(0);\n -o-transform: scale(0);\n transform: scale(0); }\n 40% {\n -webkit-transform: scale(1);\n -moz-transform: scale(1);\n -ms-transform: scale(1);\n -o-transform: scale(1);\n transform: scale(1); } }\n", ""]);
+
+ // exports
+
+
+/***/ },
+/* 83 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(84);
+
+/***/ },
+/* 84 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _container_plugin = __webpack_require__(85);
+
+ var _container_plugin2 = _interopRequireDefault(_container_plugin);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _clapprZepto = __webpack_require__(16);
+
+ var _clapprZepto2 = _interopRequireDefault(_clapprZepto);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var StatsPlugin = function (_ContainerPlugin) {
+ _inherits(StatsPlugin, _ContainerPlugin);
+
+ _createClass(StatsPlugin, [{
+ key: 'name',
+ get: function get() {
+ return 'stats';
+ }
+ }]);
+
+ function StatsPlugin(container) {
+ _classCallCheck(this, StatsPlugin);
+
+ var _this = _possibleConstructorReturn(this, _ContainerPlugin.call(this, container));
+
+ _this.setInitialAttrs();
+ _this.reportInterval = _this.options.reportInterval || 5000;
+ _this.state = 'IDLE';
+ return _this;
+ }
+
+ StatsPlugin.prototype.bindEvents = function bindEvents() {
+ this.listenTo(this.container.playback, _events2.default.PLAYBACK_PLAY, this.onPlay);
+ this.listenTo(this.container, _events2.default.CONTAINER_STOP, this.onStop);
+ this.listenTo(this.container, _events2.default.CONTAINER_ENDED, this.onStop);
+ this.listenTo(this.container, _events2.default.CONTAINER_DESTROYED, this.onStop);
+ this.listenTo(this.container, _events2.default.CONTAINER_STATE_BUFFERING, this.onBuffering);
+ this.listenTo(this.container, _events2.default.CONTAINER_STATE_BUFFERFULL, this.onBufferFull);
+ this.listenTo(this.container, _events2.default.CONTAINER_STATS_ADD, this.onStatsAdd);
+ this.listenTo(this.container, _events2.default.CONTAINER_BITRATE, this.onStatsAdd);
+ this.listenTo(this.container.playback, _events2.default.PLAYBACK_STATS_ADD, this.onStatsAdd);
+ };
+
+ StatsPlugin.prototype.setInitialAttrs = function setInitialAttrs() {
+ this.firstPlay = true;
+ this.startupTime = 0;
+ this.rebufferingTime = 0;
+ this.watchingTime = 0;
+ this.rebuffers = 0;
+ this.externalMetrics = {};
+ };
+
+ StatsPlugin.prototype.onPlay = function onPlay() {
+ this.state = 'PLAYING';
+ this.watchingTimeInit = Date.now();
+ if (!this.intervalId) {
+ this.intervalId = setInterval(this.report.bind(this), this.reportInterval);
+ }
+ };
+
+ StatsPlugin.prototype.onStop = function onStop() {
+ clearInterval(this.intervalId);
+ this.report();
+ this.intervalId = undefined;
+ this.state = 'STOPPED';
+ };
+
+ StatsPlugin.prototype.onBuffering = function onBuffering() {
+ if (this.firstPlay) {
+ this.startupTimeInit = Date.now();
+ } else {
+ this.rebufferingTimeInit = Date.now();
+ }
+ this.state = 'BUFFERING';
+ this.rebuffers++;
+ };
+
+ StatsPlugin.prototype.onBufferFull = function onBufferFull() {
+ if (this.firstPlay && this.startupTimeInit) {
+ this.firstPlay = false;
+ this.startupTime = Date.now() - this.startupTimeInit;
+ this.watchingTimeInit = Date.now();
+ } else if (this.rebufferingTimeInit) {
+ this.rebufferingTime += this.getRebufferingTime();
+ }
+ this.rebufferingTimeInit = undefined;
+ this.state = 'PLAYING';
+ };
+
+ StatsPlugin.prototype.getRebufferingTime = function getRebufferingTime() {
+ return Date.now() - this.rebufferingTimeInit;
+ };
+
+ StatsPlugin.prototype.getWatchingTime = function getWatchingTime() {
+ var totalTime = Date.now() - this.watchingTimeInit;
+ return totalTime - this.rebufferingTime;
+ };
+
+ StatsPlugin.prototype.isRebuffering = function isRebuffering() {
+ return !!this.rebufferingTimeInit;
+ };
+
+ StatsPlugin.prototype.onStatsAdd = function onStatsAdd(metric) {
+ _clapprZepto2.default.extend(this.externalMetrics, metric);
+ };
+
+ StatsPlugin.prototype.getStats = function getStats() {
+ var metrics = {
+ startupTime: this.startupTime,
+ rebuffers: this.rebuffers,
+ rebufferingTime: this.isRebuffering() ? this.rebufferingTime + this.getRebufferingTime() : this.rebufferingTime,
+ watchingTime: this.isRebuffering() ? this.getWatchingTime() - this.getRebufferingTime() : this.getWatchingTime()
+ };
+ _clapprZepto2.default.extend(metrics, this.externalMetrics);
+ return metrics;
+ };
+
+ StatsPlugin.prototype.report = function report() {
+ this.container.statsReport(this.getStats());
+ };
+
+ return StatsPlugin;
+ }(_container_plugin2.default);
+
+ exports.default = StatsPlugin;
+ module.exports = exports['default'];
+
+/***/ },
+/* 85 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _base_object = __webpack_require__(4);
+
+ var _base_object2 = _interopRequireDefault(_base_object);
+
+ var _utils = __webpack_require__(2);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ /**
+ * The base class for a container plugin
+ * @class ContainerPlugin
+ * @constructor
+ * @extends UIObject
+ * @module base
+ */
+ var ContainerPlugin = function (_BaseObject) {
+ _inherits(ContainerPlugin, _BaseObject);
+
+ function ContainerPlugin(container) {
+ _classCallCheck(this, ContainerPlugin);
+
+ var _this = _possibleConstructorReturn(this, _BaseObject.call(this, container.options));
+
+ _this.container = container;
+ _this.enabled = true;
+ _this.bindEvents();
+ return _this;
+ }
+
+ ContainerPlugin.prototype.enable = function enable() {
+ if (!this.enabled) {
+ this.bindEvents();
+ this.enabled = true;
+ }
+ };
+
+ ContainerPlugin.prototype.disable = function disable() {
+ if (this.enabled) {
+ this.stopListening();
+ this.enabled = false;
+ }
+ };
+
+ ContainerPlugin.prototype.bindEvents = function bindEvents() {};
+
+ ContainerPlugin.prototype.destroy = function destroy() {
+ this.stopListening();
+ };
+
+ return ContainerPlugin;
+ }(_base_object2.default);
+
+ exports.default = ContainerPlugin;
+
+
+ ContainerPlugin.extend = function (properties) {
+ return (0, _utils.extend)(ContainerPlugin, properties);
+ };
+
+ ContainerPlugin.type = 'container';
+ module.exports = exports['default'];
+
+/***/ },
+/* 86 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(87);
+
+/***/ },
+/* 87 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _ui_container_plugin = __webpack_require__(80);
+
+ var _ui_container_plugin2 = _interopRequireDefault(_ui_container_plugin);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _styler = __webpack_require__(15);
+
+ var _styler2 = _interopRequireDefault(_styler);
+
+ var _template = __webpack_require__(17);
+
+ var _template2 = _interopRequireDefault(_template);
+
+ var _watermark = __webpack_require__(88);
+
+ var _watermark2 = _interopRequireDefault(_watermark);
+
+ var _watermark3 = __webpack_require__(89);
+
+ var _watermark4 = _interopRequireDefault(_watermark3);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var WaterMarkPlugin = function (_UIContainerPlugin) {
+ _inherits(WaterMarkPlugin, _UIContainerPlugin);
+
+ _createClass(WaterMarkPlugin, [{
+ key: 'name',
+ get: function get() {
+ return 'watermark';
+ }
+ }, {
+ key: 'template',
+ get: function get() {
+ return (0, _template2.default)(_watermark4.default);
+ }
+ }]);
+
+ function WaterMarkPlugin(container) {
+ _classCallCheck(this, WaterMarkPlugin);
+
+ var _this = _possibleConstructorReturn(this, _UIContainerPlugin.call(this, container));
+
+ _this.configure();
+ return _this;
+ }
+
+ WaterMarkPlugin.prototype.bindEvents = function bindEvents() {
+ this.listenTo(this.container, _events2.default.CONTAINER_PLAY, this.onPlay);
+ this.listenTo(this.container, _events2.default.CONTAINER_STOP, this.onStop);
+ this.listenTo(this.container, _events2.default.CONTAINER_OPTIONS_CHANGE, this.configure);
+ };
+
+ WaterMarkPlugin.prototype.configure = function configure() {
+ this.position = this.options.position || 'bottom-right';
+ if (this.options.watermark) {
+ this.imageUrl = this.options.watermark;
+ this.imageLink = this.options.watermarkLink;
+ this.render();
+ } else {
+ this.$el.remove();
+ }
+ };
+
+ WaterMarkPlugin.prototype.onPlay = function onPlay() {
+ if (!this.hidden) this.$el.show();
+ };
+
+ WaterMarkPlugin.prototype.onStop = function onStop() {
+ this.$el.hide();
+ };
+
+ WaterMarkPlugin.prototype.render = function render() {
+ this.$el.hide();
+ var templateOptions = { position: this.position, imageUrl: this.imageUrl, imageLink: this.imageLink };
+ this.$el.html(this.template(templateOptions));
+ var style = _styler2.default.getStyleFor(_watermark2.default);
+ this.container.$el.append(style);
+ this.container.$el.append(this.$el);
+ return this;
+ };
+
+ return WaterMarkPlugin;
+ }(_ui_container_plugin2.default);
+
+ exports.default = WaterMarkPlugin;
+ module.exports = exports['default'];
+
+/***/ },
+/* 88 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(25)();
+ // imports
+
+
+ // module
+ exports.push([module.id, "[data-watermark] {\n position: absolute;\n min-width: 70px;\n max-width: 200px;\n width: 12%;\n text-align: center;\n z-index: 10; }\n\n[data-watermark] a {\n outline: none;\n cursor: pointer; }\n\n[data-watermark] img {\n max-width: 100%; }\n\n[data-watermark-bottom-left] {\n bottom: 10px;\n left: 10px; }\n\n[data-watermark-bottom-right] {\n bottom: 10px;\n right: 42px; }\n\n[data-watermark-top-left] {\n top: 10px;\n left: 10px; }\n\n[data-watermark-top-right] {\n top: 10px;\n right: 37px; }\n", ""]);
+
+ // exports
+
+
+/***/ },
+/* 89 */
+/***/ function(module, exports) {
+
+ module.exports = "<div data-watermark data-watermark-<%=position %>>\n<% if(typeof imageLink !== 'undefined') { %>\n<a target=_blank href=\"<%= imageLink %>\">\n<% } %>\n<img src=\"<%= imageUrl %>\">\n<% if(typeof imageLink !== 'undefined') { %>\n</a>\n<% } %>\n</div>\n";
+
+/***/ },
+/* 90 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(91);
+
+/***/ },
+/* 91 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /* WEBPACK VAR INJECTION */(function(process) {'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _ui_container_plugin = __webpack_require__(80);
+
+ var _ui_container_plugin2 = _interopRequireDefault(_ui_container_plugin);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _styler = __webpack_require__(15);
+
+ var _styler2 = _interopRequireDefault(_styler);
+
+ var _template = __webpack_require__(17);
+
+ var _template2 = _interopRequireDefault(_template);
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ var _poster = __webpack_require__(92);
+
+ var _poster2 = _interopRequireDefault(_poster);
+
+ var _poster3 = __webpack_require__(93);
+
+ var _poster4 = _interopRequireDefault(_poster3);
+
+ var _play = __webpack_require__(37);
+
+ var _play2 = _interopRequireDefault(_play);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } //Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var PosterPlugin = function (_UIContainerPlugin) {
+ _inherits(PosterPlugin, _UIContainerPlugin);
+
+ _createClass(PosterPlugin, [{
+ key: 'name',
+ get: function get() {
+ return 'poster';
+ }
+ }, {
+ key: 'template',
+ get: function get() {
+ return (0, _template2.default)(_poster4.default);
+ }
+ }, {
+ key: 'shouldRender',
+ get: function get() {
+ var showForNoOp = !!(this.options.poster && this.options.poster.showForNoOp);
+ return this.container.playback.name !== 'html_img' && (this.container.playback.getPlaybackType() !== _playback2.default.NO_OP || showForNoOp);
+ }
+ }, {
+ key: 'attributes',
+ get: function get() {
+ return {
+ 'class': 'player-poster',
+ 'data-poster': ''
+ };
+ }
+ }, {
+ key: 'events',
+ get: function get() {
+ return {
+ 'click': 'clicked'
+ };
+ }
+ }, {
+ key: 'showOnVideoEnd',
+ get: function get() {
+ return !this.options.poster || this.options.poster.showOnVideoEnd || this.options.poster.showOnVideoEnd === undefined;
+ }
+ }]);
+
+ function PosterPlugin(container) {
+ _classCallCheck(this, PosterPlugin);
+
+ var _this = _possibleConstructorReturn(this, _UIContainerPlugin.call(this, container));
+
+ _this.hasStartedPlaying = false;
+ _this.playRequested = false;
+ _this.render();
+ process.nextTick(function () {
+ return _this.update();
+ });
+ return _this;
+ }
+
+ PosterPlugin.prototype.bindEvents = function bindEvents() {
+ this.listenTo(this.container, _events2.default.CONTAINER_STOP, this.onStop);
+ this.listenTo(this.container, _events2.default.CONTAINER_PLAY, this.onPlay);
+ this.listenTo(this.container, _events2.default.CONTAINER_STATE_BUFFERING, this.update);
+ this.listenTo(this.container, _events2.default.CONTAINER_STATE_BUFFERFULL, this.update);
+ this.listenTo(this.container, _events2.default.CONTAINER_OPTIONS_CHANGE, this.render);
+ this.showOnVideoEnd && this.listenTo(this.container, _events2.default.CONTAINER_ENDED, this.onStop);
+ };
+
+ PosterPlugin.prototype.stopListening = function stopListening() {
+ _UIContainerPlugin.prototype.stopListening.call(this);
+ };
+
+ PosterPlugin.prototype.onPlay = function onPlay() {
+ this.hasStartedPlaying = true;
+ this.update();
+ };
+
+ PosterPlugin.prototype.onStop = function onStop() {
+ this.hasStartedPlaying = false;
+ this.playRequested = false;
+ this.update();
+ };
+
+ PosterPlugin.prototype.showPlayButton = function showPlayButton(show) {
+ if (show && (!this.options.chromeless || this.options.allowUserInteraction)) {
+ this.$playButton.show();
+ this.$el.addClass('clickable');
+ } else {
+ this.$playButton.hide();
+ this.$el.removeClass('clickable');
+ }
+ };
+
+ PosterPlugin.prototype.clicked = function clicked() {
+ if (!this.options.chromeless || this.options.allowUserInteraction) {
+ this.playRequested = true;
+ this.update();
+ this.container.play();
+ }
+ return false;
+ };
+
+ PosterPlugin.prototype.shouldHideOnPlay = function shouldHideOnPlay() {
+ // Audio broadcasts should keep the poster up; video should hide poster while playing.
+ return !this.container.playback.isAudioOnly;
+ };
+
+ PosterPlugin.prototype.update = function update() {
+ if (!this.shouldRender) {
+ return;
+ }
+ var showPlayButton = !this.playRequested && !this.hasStartedPlaying && !this.container.buffering;
+ this.showPlayButton(showPlayButton);
+ if (!this.hasStartedPlaying) {
+ this.container.disableMediaControl();
+ this.$el.show();
+ } else {
+ this.container.enableMediaControl();
+ if (this.shouldHideOnPlay()) {
+ this.$el.hide();
+ }
+ }
+ };
+
+ PosterPlugin.prototype.render = function render() {
+ if (!this.shouldRender) {
+ return;
+ }
+ var style = _styler2.default.getStyleFor(_poster2.default, { baseUrl: this.options.baseUrl });
+ this.$el.html(this.template());
+ this.$el.append(style);
+ if (this.options.poster) {
+ var posterUrl = this.options.poster.url || this.options.poster;
+ this.$el.css({ 'background-image': 'url(' + posterUrl + ')' });
+ }
+ this.container.$el.append(this.el);
+ this.$playWrapper = this.$el.find('.play-wrapper');
+ this.$playWrapper.append(_play2.default);
+ this.$playButton = this.$playWrapper.find('svg');
+ this.$playButton.addClass('poster-icon');
+ this.$playButton.attr('data-poster', '');
+
+ var buttonsColor = this.options.mediacontrol && this.options.mediacontrol.buttons;
+ if (buttonsColor) {
+ this.$el.find('svg path').css('fill', buttonsColor);
+ }
+
+ if (this.options.mediacontrol && this.options.mediacontrol.buttons) {
+ buttonsColor = this.options.mediacontrol.buttons;
+ this.$playButton.css('color', buttonsColor);
+ }
+ this.update();
+ return this;
+ };
+
+ return PosterPlugin;
+ }(_ui_container_plugin2.default);
+
+ exports.default = PosterPlugin;
+ module.exports = exports['default'];
+ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(29)))
+
+/***/ },
+/* 92 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(25)();
+ // imports
+
+
+ // module
+ exports.push([module.id, ".player-poster[data-poster] {\n display: -webkit-box;\n display: -moz-box;\n display: box;\n display: -webkit-flex;\n display: -moz-flex;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-pack: center;\n -moz-box-pack: center;\n box-pack: center;\n -webkit-justify-content: center;\n -moz-justify-content: center;\n -ms-justify-content: center;\n -o-justify-content: center;\n justify-content: center;\n -ms-flex-pack: center;\n -webkit-box-align: center;\n -moz-box-align: center;\n box-align: center;\n -webkit-align-items: center;\n -moz-align-items: center;\n -ms-align-items: center;\n -o-align-items: center;\n align-items: center;\n -ms-flex-align: center;\n position: absolute;\n height: 100%;\n width: 100%;\n z-index: 998;\n top: 0;\n left: 0;\n background-color: #000;\n background-size: cover;\n background-repeat: no-repeat;\n background-position: 50% 50%; }\n .player-poster[data-poster].clickable {\n cursor: pointer; }\n .player-poster[data-poster]:hover .play-wrapper[data-poster] {\n opacity: 1; }\n .player-poster[data-poster] .play-wrapper[data-poster] {\n width: 100%;\n height: 25%;\n margin: 0 auto;\n opacity: 0.75;\n -webkit-transition: opacity 0.1s ease;\n -moz-transition: opacity 0.1s ease;\n transition: opacity 0.1s ease; }\n .player-poster[data-poster] .play-wrapper[data-poster] svg {\n height: 100%; }\n .player-poster[data-poster] .play-wrapper[data-poster] svg path {\n fill: #fff; }\n", ""]);
+
+ // exports
+
+
+/***/ },
+/* 93 */
+/***/ function(module, exports) {
+
+ module.exports = "<div class=\"play-wrapper\" data-poster></div>\n";
+
+/***/ },
+/* 94 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(95);
+
+/***/ },
+/* 95 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _container_plugin = __webpack_require__(85);
+
+ var _container_plugin2 = _interopRequireDefault(_container_plugin);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var GoogleAnalytics = function (_ContainerPlugin) {
+ _inherits(GoogleAnalytics, _ContainerPlugin);
+
+ _createClass(GoogleAnalytics, [{
+ key: 'name',
+ get: function get() {
+ return 'google_analytics';
+ }
+ }]);
+
+ function GoogleAnalytics(container) {
+ _classCallCheck(this, GoogleAnalytics);
+
+ var _this = _possibleConstructorReturn(this, _ContainerPlugin.call(this, container));
+
+ if (_this.container.options.gaAccount) {
+ _this.account = _this.container.options.gaAccount;
+ _this.trackerName = _this.container.options.gaTrackerName ? _this.container.options.gaTrackerName + '.' : 'Clappr.';
+ _this.domainName = _this.container.options.gaDomainName;
+ _this.currentHDState = undefined;
+ _this.embedScript();
+ }
+ return _this;
+ }
+
+ GoogleAnalytics.prototype.embedScript = function embedScript() {
+ var _this2 = this;
+
+ if (!window._gat) {
+ var script = document.createElement('script');
+ script.setAttribute('type', 'text/javascript');
+ script.setAttribute('async', 'async');
+ script.setAttribute('src', '//www.google-analytics.com/ga.js');
+ script.onload = function () {
+ return _this2.addEventListeners();
+ };
+ document.body.appendChild(script);
+ } else {
+ this.addEventListeners();
+ }
+ };
+
+ GoogleAnalytics.prototype.addEventListeners = function addEventListeners() {
+ var _this3 = this;
+
+ if (this.container) {
+ this.listenTo(this.container, _events2.default.CONTAINER_READY, this.onReady);
+ this.listenTo(this.container, _events2.default.CONTAINER_PLAY, this.onPlay);
+ this.listenTo(this.container, _events2.default.CONTAINER_STOP, this.onStop);
+ this.listenTo(this.container, _events2.default.CONTAINER_PAUSE, this.onPause);
+ this.listenTo(this.container, _events2.default.CONTAINER_ENDED, this.onEnded);
+ this.listenTo(this.container, _events2.default.CONTAINER_STATE_BUFFERING, this.onBuffering);
+ this.listenTo(this.container, _events2.default.CONTAINER_STATE_BUFFERFULL, this.onBufferFull);
+ this.listenTo(this.container, _events2.default.CONTAINER_ERROR, this.onError);
+ this.listenTo(this.container, _events2.default.CONTAINER_PLAYBACKSTATE, this.onPlaybackChanged);
+ this.listenTo(this.container, _events2.default.CONTAINER_VOLUME, function (event) {
+ return _this3.onVolumeChanged(event);
+ });
+ this.listenTo(this.container, _events2.default.CONTAINER_SEEK, function (event) {
+ return _this3.onSeek(event);
+ });
+ this.listenTo(this.container, _events2.default.CONTAINER_FULL_SCREEN, this.onFullscreen);
+ this.listenTo(this.container, _events2.default.CONTAINER_HIGHDEFINITIONUPDATE, this.onHD);
+ this.listenTo(this.container, _events2.default.CONTAINER_PLAYBACKDVRSTATECHANGED, this.onDVR);
+ }
+ _gaq.push([this.trackerName + '_setAccount', this.account]);
+ if (this.domainName) _gaq.push([this.trackerName + '_setDomainName', this.domainName]);
+ };
+
+ GoogleAnalytics.prototype.onReady = function onReady() {
+ this.push(['Video', 'Playback', this.container.playback.name]);
+ };
+
+ GoogleAnalytics.prototype.onPlay = function onPlay() {
+ this.push(['Video', 'Play', this.container.playback.src]);
+ };
+
+ GoogleAnalytics.prototype.onStop = function onStop() {
+ this.push(['Video', 'Stop', this.container.playback.src]);
+ };
+
+ GoogleAnalytics.prototype.onEnded = function onEnded() {
+ this.push(['Video', 'Ended', this.container.playback.src]);
+ };
+
+ GoogleAnalytics.prototype.onBuffering = function onBuffering() {
+ this.push(['Video', 'Buffering', this.container.playback.src]);
+ };
+
+ GoogleAnalytics.prototype.onBufferFull = function onBufferFull() {
+ this.push(['Video', 'Bufferfull', this.container.playback.src]);
+ };
+
+ GoogleAnalytics.prototype.onError = function onError() {
+ this.push(['Video', 'Error', this.container.playback.src]);
+ };
+
+ GoogleAnalytics.prototype.onHD = function onHD(isHD) {
+ var status = isHD ? 'ON' : 'OFF';
+ if (status !== this.currentHDState) {
+ this.currentHDState = status;
+ this.push(['Video', 'HD - ' + status, this.container.playback.src]);
+ }
+ };
+
+ GoogleAnalytics.prototype.onPlaybackChanged = function onPlaybackChanged(playbackState) {
+ if (playbackState.type !== null) {
+ this.push(['Video', 'Playback Type - ' + playbackState.type, this.container.playback.src]);
+ }
+ };
+
+ GoogleAnalytics.prototype.onDVR = function onDVR(dvrInUse) {
+ var status = dvrInUse ? 'ON' : 'OFF';
+ this.push(['Interaction', 'DVR - ' + status, this.container.playback.src]);
+ };
+
+ GoogleAnalytics.prototype.onPause = function onPause() {
+ this.push(['Video', 'Pause', this.container.playback.src]);
+ };
+
+ GoogleAnalytics.prototype.onSeek = function onSeek() {
+ this.push(['Video', 'Seek', this.container.playback.src]);
+ };
+
+ GoogleAnalytics.prototype.onVolumeChanged = function onVolumeChanged() {
+ this.push(['Interaction', 'Volume', this.container.playback.src]);
+ };
+
+ GoogleAnalytics.prototype.onFullscreen = function onFullscreen() {
+ this.push(['Interaction', 'Fullscreen', this.container.playback.src]);
+ };
+
+ GoogleAnalytics.prototype.push = function push(array) {
+ var res = [this.trackerName + '_trackEvent'].concat(array);
+ _gaq.push(res);
+ };
+
+ return GoogleAnalytics;
+ }(_container_plugin2.default);
+
+ exports.default = GoogleAnalytics;
+ module.exports = exports['default'];
+
+/***/ },
+/* 96 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(97);
+
+/***/ },
+/* 97 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _container_plugin = __webpack_require__(85);
+
+ var _container_plugin2 = _interopRequireDefault(_container_plugin);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } //Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var ClickToPausePlugin = function (_ContainerPlugin) {
+ _inherits(ClickToPausePlugin, _ContainerPlugin);
+
+ _createClass(ClickToPausePlugin, [{
+ key: 'name',
+ get: function get() {
+ return 'click_to_pause';
+ }
+ }]);
+
+ function ClickToPausePlugin(container) {
+ _classCallCheck(this, ClickToPausePlugin);
+
+ return _possibleConstructorReturn(this, _ContainerPlugin.call(this, container));
+ }
+
+ ClickToPausePlugin.prototype.bindEvents = function bindEvents() {
+ this.listenTo(this.container, _events2.default.CONTAINER_CLICK, this.click);
+ this.listenTo(this.container, _events2.default.CONTAINER_SETTINGSUPDATE, this.settingsUpdate);
+ };
+
+ ClickToPausePlugin.prototype.click = function click() {
+ if (this.container.getPlaybackType() !== _playback2.default.LIVE || this.container.isDvrEnabled()) {
+ if (this.container.isPlaying()) {
+ this.container.pause();
+ } else {
+ this.container.play();
+ }
+ }
+ };
+
+ ClickToPausePlugin.prototype.settingsUpdate = function settingsUpdate() {
+ this.container.$el.removeClass('pointer-enabled');
+ if (this.container.getPlaybackType() !== _playback2.default.LIVE || this.container.isDvrEnabled()) {
+ this.container.$el.addClass('pointer-enabled');
+ }
+ };
+
+ return ClickToPausePlugin;
+ }(_container_plugin2.default);
+
+ exports.default = ClickToPausePlugin;
+ module.exports = exports['default'];
+
+/***/ },
+/* 98 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(99);
+
+/***/ },
+/* 99 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _ui_core_plugin = __webpack_require__(100);
+
+ var _ui_core_plugin2 = _interopRequireDefault(_ui_core_plugin);
+
+ var _template = __webpack_require__(17);
+
+ var _template2 = _interopRequireDefault(_template);
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ var _styler = __webpack_require__(15);
+
+ var _styler2 = _interopRequireDefault(_styler);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _dvr_controls = __webpack_require__(101);
+
+ var _dvr_controls2 = _interopRequireDefault(_dvr_controls);
+
+ var _index = __webpack_require__(102);
+
+ var _index2 = _interopRequireDefault(_index);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var DVRControls = function (_UICorePlugin) {
+ _inherits(DVRControls, _UICorePlugin);
+
+ _createClass(DVRControls, [{
+ key: 'template',
+ get: function get() {
+ return (0, _template2.default)(_index2.default);
+ }
+ }, {
+ key: 'name',
+ get: function get() {
+ return 'dvr_controls';
+ }
+ }, {
+ key: 'events',
+ get: function get() {
+ return {
+ 'click .live-button': 'click'
+ };
+ }
+ }, {
+ key: 'attributes',
+ get: function get() {
+ return {
+ 'class': 'dvr-controls',
+ 'data-dvr-controls': ''
+ };
+ }
+ }]);
+
+ function DVRControls(core) {
+ _classCallCheck(this, DVRControls);
+
+ var _this = _possibleConstructorReturn(this, _UICorePlugin.call(this, core));
+
+ _this.settingsUpdate();
+ return _this;
+ }
+
+ DVRControls.prototype.bindEvents = function bindEvents() {
+ this.listenTo(this.core.mediaControl, _events2.default.MEDIACONTROL_CONTAINERCHANGED, this.containerChanged);
+ this.listenTo(this.core.mediaControl, _events2.default.MEDIACONTROL_RENDERED, this.settingsUpdate);
+ this.listenTo(this.core, _events2.default.CORE_OPTIONS_CHANGE, this.render);
+ if (this.core.getCurrentContainer()) {
+ this.listenToOnce(this.core.getCurrentContainer(), _events2.default.CONTAINER_TIMEUPDATE, this.render);
+ this.listenTo(this.core.getCurrentContainer(), _events2.default.CONTAINER_PLAYBACKDVRSTATECHANGED, this.dvrChanged);
+ }
+ };
+
+ DVRControls.prototype.containerChanged = function containerChanged() {
+ this.stopListening();
+ this.bindEvents();
+ };
+
+ DVRControls.prototype.dvrChanged = function dvrChanged(dvrEnabled) {
+ this.settingsUpdate();
+ this.core.mediaControl.$el.addClass('live');
+ if (dvrEnabled) {
+ this.core.mediaControl.$el.addClass('dvr');
+ this.core.mediaControl.$el.find('.media-control-indicator[data-position], .media-control-indicator[data-duration]').hide();
+ } else {
+ this.core.mediaControl.$el.removeClass('dvr');
+ }
+ };
+
+ DVRControls.prototype.click = function click() {
+ var mediaControl = this.core.mediaControl;
+ var container = mediaControl.container;
+ if (!container.isPlaying()) {
+ container.play();
+ }
+ if (mediaControl.$el.hasClass('dvr')) {
+ container.seek(container.getDuration());
+ }
+ };
+
+ DVRControls.prototype.settingsUpdate = function settingsUpdate() {
+ var _this2 = this;
+
+ this.stopListening();
+ if (this.shouldRender()) {
+ this.render();
+ this.$el.click(function () {
+ return _this2.click();
+ });
+ }
+ this.bindEvents();
+ };
+
+ DVRControls.prototype.shouldRender = function shouldRender() {
+ var useDvrControls = this.core.options.useDvrControls === undefined || !!this.core.options.useDvrControls;
+ return useDvrControls && this.core.getPlaybackType() === _playback2.default.LIVE;
+ };
+
+ DVRControls.prototype.render = function render() {
+ this.style = this.style || _styler2.default.getStyleFor(_dvr_controls2.default, { baseUrl: this.core.options.baseUrl });
+ this.$el.html(this.template({
+ live: this.core.i18n.t('live'),
+ backToLive: this.core.i18n.t('back_to_live')
+ }));
+ this.$el.append(this.style);
+ if (this.shouldRender()) {
+ this.core.mediaControl.$el.addClass('live');
+ this.core.mediaControl.$('.media-control-left-panel[data-media-control]').append(this.$el);
+ }
+ return this;
+ };
+
+ return DVRControls;
+ }(_ui_core_plugin2.default);
+
+ exports.default = DVRControls;
+ module.exports = exports['default'];
+
+/***/ },
+/* 100 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _utils = __webpack_require__(2);
+
+ var _ui_object = __webpack_require__(18);
+
+ var _ui_object2 = _interopRequireDefault(_ui_object);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var UICorePlugin = function (_UIObject) {
+ _inherits(UICorePlugin, _UIObject);
+
+ function UICorePlugin(core) {
+ _classCallCheck(this, UICorePlugin);
+
+ var _this = _possibleConstructorReturn(this, _UIObject.call(this, core.options));
+
+ _this.core = core;
+ _this.enabled = true;
+ _this.bindEvents();
+ _this.render();
+ return _this;
+ }
+
+ UICorePlugin.prototype.bindEvents = function bindEvents() {};
+
+ UICorePlugin.prototype.getExternalInterface = function getExternalInterface() {
+ return {};
+ };
+
+ UICorePlugin.prototype.enable = function enable() {
+ if (!this.enabled) {
+ this.bindEvents();
+ this.$el.show();
+ this.enabled = true;
+ }
+ };
+
+ UICorePlugin.prototype.disable = function disable() {
+ this.stopListening();
+ this.$el.hide();
+ this.enabled = false;
+ };
+
+ UICorePlugin.prototype.destroy = function destroy() {
+ this.remove();
+ };
+
+ UICorePlugin.prototype.render = function render() {
+ return this;
+ };
+
+ return UICorePlugin;
+ }(_ui_object2.default);
+
+ exports.default = UICorePlugin;
+
+
+ UICorePlugin.extend = function (properties) {
+ return (0, _utils.extend)(UICorePlugin, properties);
+ };
+
+ UICorePlugin.type = 'core';
+ module.exports = exports['default'];
+
+/***/ },
+/* 101 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(25)();
+ // imports
+
+
+ // module
+ exports.push([module.id, ".dvr-controls[data-dvr-controls] {\n display: inline-block;\n float: left;\n color: #fff;\n line-height: 32px;\n font-size: 10px;\n font-weight: bold;\n margin-left: 6px; }\n .dvr-controls[data-dvr-controls] .live-info {\n cursor: default;\n font-family: \"Roboto\", \"Open Sans\", Arial, sans-serif;\n text-transform: uppercase; }\n .dvr-controls[data-dvr-controls] .live-info:before {\n content: \"\";\n display: inline-block;\n position: relative;\n width: 7px;\n height: 7px;\n border-radius: 3.5px;\n margin-right: 3.5px;\n background-color: #ff0101; }\n .dvr-controls[data-dvr-controls] .live-info.disabled {\n opacity: 0.3; }\n .dvr-controls[data-dvr-controls] .live-info.disabled:before {\n background-color: #fff; }\n .dvr-controls[data-dvr-controls] .live-button {\n cursor: pointer;\n outline: none;\n display: none;\n border: 0;\n color: #fff;\n background-color: transparent;\n height: 32px;\n padding: 0;\n opacity: 0.7;\n font-family: \"Roboto\", \"Open Sans\", Arial, sans-serif;\n text-transform: uppercase;\n -webkit-transition: all 0.1s ease;\n -moz-transition: all 0.1s ease;\n transition: all 0.1s ease; }\n .dvr-controls[data-dvr-controls] .live-button:before {\n content: \"\";\n display: inline-block;\n position: relative;\n width: 7px;\n height: 7px;\n border-radius: 3.5px;\n margin-right: 3.5px;\n background-color: #fff; }\n .dvr-controls[data-dvr-controls] .live-button:hover {\n opacity: 1;\n text-shadow: rgba(255, 255, 255, 0.75) 0 0 5px; }\n\n.dvr .dvr-controls[data-dvr-controls] .live-info {\n display: none; }\n\n.dvr .dvr-controls[data-dvr-controls] .live-button {\n display: block; }\n\n.dvr.media-control.live[data-media-control] .media-control-layer[data-controls] .bar-container[data-seekbar] .bar-background[data-seekbar] .bar-fill-2[data-seekbar] {\n background-color: #005aff; }\n\n.media-control.live[data-media-control] .media-control-layer[data-controls] .bar-container[data-seekbar] .bar-background[data-seekbar] .bar-fill-2[data-seekbar] {\n background-color: #ff0101; }\n", ""]);
+
+ // exports
+
+
+/***/ },
+/* 102 */
+/***/ function(module, exports) {
+
+ module.exports = "<div class=\"live-info\"><%= live %></div>\n<button type=\"button\" class=\"live-button\"><%= backToLive %></button>\n";
+
+/***/ },
+/* 103 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(104);
+
+/***/ },
+/* 104 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _core_plugin = __webpack_require__(105);
+
+ var _core_plugin2 = _interopRequireDefault(_core_plugin);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _clapprZepto = __webpack_require__(16);
+
+ var _clapprZepto2 = _interopRequireDefault(_clapprZepto);
+
+ var _play = __webpack_require__(37);
+
+ var _play2 = _interopRequireDefault(_play);
+
+ var _pause = __webpack_require__(38);
+
+ var _pause2 = _interopRequireDefault(_pause);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var oldIcon = (0, _clapprZepto2.default)('link[rel="shortcut icon"]');
+
+ var Favicon = function (_CorePlugin) {
+ _inherits(Favicon, _CorePlugin);
+
+ _createClass(Favicon, [{
+ key: 'name',
+ get: function get() {
+ return 'favicon';
+ }
+ }, {
+ key: 'oldIcon',
+ get: function get() {
+ return oldIcon;
+ }
+ }]);
+
+ function Favicon(core) {
+ _classCallCheck(this, Favicon);
+
+ var _this = _possibleConstructorReturn(this, _CorePlugin.call(this, core));
+
+ _this._container = null;
+ _this.configure();
+ return _this;
+ }
+
+ Favicon.prototype.configure = function configure() {
+ if (this.core.options.changeFavicon) {
+ if (!this.enabled) {
+ this.stopListening(this.core, _events2.default.CORE_OPTIONS_CHANGE);
+ this.enable();
+ }
+ } else if (this.enabled) {
+ this.disable();
+ this.listenTo(this.core, _events2.default.CORE_OPTIONS_CHANGE, this.configure);
+ }
+ };
+
+ Favicon.prototype.bindEvents = function bindEvents() {
+ this.listenTo(this.core, _events2.default.CORE_OPTIONS_CHANGE, this.configure);
+ this.listenTo(this.core.mediaControl, _events2.default.MEDIACONTROL_CONTAINERCHANGED, this.containerChanged);
+ if (this.core.mediaControl.container) {
+ this.containerChanged();
+ }
+ };
+
+ Favicon.prototype.containerChanged = function containerChanged() {
+ this._container && this.stopListening(this._container);
+ this._container = this.core.mediaControl.container;
+ this.listenTo(this._container, _events2.default.CONTAINER_PLAY, this.setPlayIcon);
+ this.listenTo(this._container, _events2.default.CONTAINER_PAUSE, this.setPauseIcon);
+ this.listenTo(this._container, _events2.default.CONTAINER_STOP, this.resetIcon);
+ this.listenTo(this._container, _events2.default.CONTAINER_ENDED, this.resetIcon);
+ this.listenTo(this._container, _events2.default.CONTAINER_ERROR, this.resetIcon);
+ this.resetIcon();
+ };
+
+ Favicon.prototype.disable = function disable() {
+ _CorePlugin.prototype.disable.call(this);
+ this.resetIcon();
+ };
+
+ Favicon.prototype.destroy = function destroy() {
+ _CorePlugin.prototype.destroy.call(this);
+ this.resetIcon();
+ };
+
+ Favicon.prototype.createIcon = function createIcon(svg) {
+ var canvas = (0, _clapprZepto2.default)('<canvas/>');
+ canvas[0].width = 16;
+ canvas[0].height = 16;
+ var ctx = canvas[0].getContext('2d');
+ ctx.fillStyle = '#000';
+ var d = (0, _clapprZepto2.default)(svg).find('path').attr('d');
+ var path = new Path2D(d);
+ ctx.fill(path);
+ var icon = (0, _clapprZepto2.default)('<link rel="shortcut icon" type="image/png"/>');
+ icon.attr('href', canvas[0].toDataURL('image/png'));
+ return icon;
+ };
+
+ Favicon.prototype.setPlayIcon = function setPlayIcon() {
+ if (!this.playIcon) {
+ this.playIcon = this.createIcon(_play2.default);
+ }
+ this.changeIcon(this.playIcon);
+ };
+
+ Favicon.prototype.setPauseIcon = function setPauseIcon() {
+ if (!this.pauseIcon) {
+ this.pauseIcon = this.createIcon(_pause2.default);
+ }
+ this.changeIcon(this.pauseIcon);
+ };
+
+ Favicon.prototype.resetIcon = function resetIcon() {
+ (0, _clapprZepto2.default)('link[rel="shortcut icon"]').remove();
+ (0, _clapprZepto2.default)('head').append(this.oldIcon);
+ };
+
+ Favicon.prototype.changeIcon = function changeIcon(icon) {
+ if (icon) {
+ (0, _clapprZepto2.default)('link[rel="shortcut icon"]').remove();
+ (0, _clapprZepto2.default)('head').append(icon);
+ }
+ };
+
+ return Favicon;
+ }(_core_plugin2.default);
+
+ exports.default = Favicon;
+ module.exports = exports['default'];
+
+/***/ },
+/* 105 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _utils = __webpack_require__(2);
+
+ var _base_object = __webpack_require__(4);
+
+ var _base_object2 = _interopRequireDefault(_base_object);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var CorePlugin = function (_BaseObject) {
+ _inherits(CorePlugin, _BaseObject);
+
+ function CorePlugin(core) {
+ _classCallCheck(this, CorePlugin);
+
+ var _this = _possibleConstructorReturn(this, _BaseObject.call(this, core.options));
+
+ _this.core = core;
+ _this.enabled = true;
+ _this.bindEvents();
+ return _this;
+ }
+
+ CorePlugin.prototype.bindEvents = function bindEvents() {};
+
+ CorePlugin.prototype.enable = function enable() {
+ if (!this.enabled) {
+ this.bindEvents();
+ this.enabled = true;
+ }
+ };
+
+ CorePlugin.prototype.disable = function disable() {
+ if (this.enabled) {
+ this.stopListening();
+ this.enabled = false;
+ }
+ };
+
+ CorePlugin.prototype.getExternalInterface = function getExternalInterface() {
+ return {};
+ };
+
+ CorePlugin.prototype.destroy = function destroy() {
+ this.stopListening();
+ };
+
+ return CorePlugin;
+ }(_base_object2.default);
+
+ exports.default = CorePlugin;
+
+
+ CorePlugin.extend = function (properties) {
+ return (0, _utils.extend)(CorePlugin, properties);
+ };
+
+ CorePlugin.type = 'core';
+ module.exports = exports['default'];
+
+/***/ },
+/* 106 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ module.exports = __webpack_require__(107);
+
+/***/ },
+/* 107 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _utils = __webpack_require__(2);
+
+ var _ui_core_plugin = __webpack_require__(100);
+
+ var _ui_core_plugin2 = _interopRequireDefault(_ui_core_plugin);
+
+ var _styler = __webpack_require__(15);
+
+ var _styler2 = _interopRequireDefault(_styler);
+
+ var _template = __webpack_require__(17);
+
+ var _template2 = _interopRequireDefault(_template);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _playback = __webpack_require__(31);
+
+ var _playback2 = _interopRequireDefault(_playback);
+
+ var _seek_time = __webpack_require__(108);
+
+ var _seek_time2 = _interopRequireDefault(_seek_time);
+
+ var _seek_time3 = __webpack_require__(109);
+
+ var _seek_time4 = _interopRequireDefault(_seek_time3);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Copyright 2014 Globo.com Player authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style
+ // license that can be found in the LICENSE file.
+
+ var SeekTime = function (_UICorePlugin) {
+ _inherits(SeekTime, _UICorePlugin);
+
+ _createClass(SeekTime, [{
+ key: 'name',
+ get: function get() {
+ return 'seek_time';
+ }
+ }, {
+ key: 'template',
+ get: function get() {
+ return (0, _template2.default)(_seek_time4.default);
+ }
+ }, {
+ key: 'attributes',
+ get: function get() {
+ return {
+ 'class': 'seek-time',
+ 'data-seek-time': ''
+ };
+ }
+ }, {
+ key: 'mediaControl',
+ get: function get() {
+ return this.core.mediaControl;
+ }
+ }, {
+ key: 'mediaControlContainer',
+ get: function get() {
+ return this.mediaControl.container;
+ }
+ }, {
+ key: 'isLiveStreamWithDvr',
+ get: function get() {
+ return this.mediaControlContainer && this.mediaControlContainer.getPlaybackType() === _playback2.default.LIVE && this.mediaControlContainer.isDvrEnabled();
+ }
+ }, {
+ key: 'durationShown',
+ get: function get() {
+ return this.isLiveStreamWithDvr && !this.useActualLiveTime;
+ }
+ }, {
+ key: 'useActualLiveTime',
+ get: function get() {
+ return this.actualLiveTime && this.isLiveStreamWithDvr;
+ }
+ }]);
+
+ function SeekTime(core) {
+ _classCallCheck(this, SeekTime);
+
+ var _this = _possibleConstructorReturn(this, _UICorePlugin.call(this, core));
+
+ _this.hoveringOverSeekBar = false;
+ _this.hoverPosition = null;
+ _this.duration = null;
+ _this.actualLiveTime = !!_this.mediaControl.options.actualLiveTime;
+ if (_this.actualLiveTime) {
+ if (_this.mediaControl.options.actualLiveServerTime) {
+ _this.actualLiveServerTimeDiff = new Date().getTime() - new Date(_this.mediaControl.options.actualLiveServerTime).getTime();
+ } else {
+ _this.actualLiveServerTimeDiff = 0;
+ }
+ }
+ return _this;
+ }
+
+ SeekTime.prototype.bindEvents = function bindEvents() {
+ this.listenTo(this.mediaControl, _events2.default.MEDIACONTROL_RENDERED, this.render);
+ this.listenTo(this.mediaControl, _events2.default.MEDIACONTROL_MOUSEMOVE_SEEKBAR, this.showTime);
+ this.listenTo(this.mediaControl, _events2.default.MEDIACONTROL_MOUSELEAVE_SEEKBAR, this.hideTime);
+ this.listenTo(this.mediaControl, _events2.default.MEDIACONTROL_CONTAINERCHANGED, this.onContainerChanged);
+ if (this.mediaControlContainer) {
+ this.listenTo(this.mediaControlContainer, _events2.default.CONTAINER_PLAYBACKDVRSTATECHANGED, this.update);
+ this.listenTo(this.mediaControlContainer, _events2.default.CONTAINER_TIMEUPDATE, this.updateDuration);
+ }
+ };
+
+ SeekTime.prototype.onContainerChanged = function onContainerChanged() {
+ this.stopListening();
+ this.bindEvents();
+ };
+
+ SeekTime.prototype.updateDuration = function updateDuration(timeProgress) {
+ this.duration = timeProgress.total;
+ this.update();
+ };
+
+ SeekTime.prototype.showTime = function showTime(event) {
+ this.hoveringOverSeekBar = true;
+ this.calculateHoverPosition(event);
+ this.update();
+ };
+
+ SeekTime.prototype.hideTime = function hideTime() {
+ this.hoveringOverSeekBar = false;
+ this.update();
+ };
+
+ SeekTime.prototype.calculateHoverPosition = function calculateHoverPosition(event) {
+ var offset = event.pageX - this.mediaControl.$seekBarContainer.offset().left;
+ // proportion into the seek bar that the mouse is hovered over 0-1
+ this.hoverPosition = Math.min(1, Math.max(offset / this.mediaControl.$seekBarContainer.width(), 0));
+ };
+
+ SeekTime.prototype.getSeekTime = function getSeekTime() {
+ var seekTime = void 0,
+ secondsSinceMidnight = void 0;
+ if (this.useActualLiveTime) {
+ var d = new Date(new Date().getTime() - this.actualLiveServerTimeDiff),
+ e = new Date(d);
+ secondsSinceMidnight = (e - d.setHours(0, 0, 0, 0)) / 1000;
+ seekTime = secondsSinceMidnight - this.duration + this.hoverPosition * this.duration;
+ if (seekTime < 0) {
+ seekTime += 86400;
+ }
+ } else {
+ seekTime = this.hoverPosition * this.duration;
+ }
+ return { seekTime: seekTime, secondsSinceMidnight: secondsSinceMidnight };
+ };
+
+ SeekTime.prototype.update = function update() {
+ if (!this.rendered) {
+ // update() is always called after a render
+ return;
+ }
+ if (!this.shouldBeVisible()) {
+ this.$el.hide();
+ this.$el.css('left', '-100%');
+ } else {
+ var seekTime = this.getSeekTime();
+ var currentSeekTime = (0, _utils.formatTime)(seekTime.seekTime, this.useActualLiveTime);
+ // only update dom if necessary, ie time actually changed
+ if (currentSeekTime !== this.displayedSeekTime) {
+ this.$seekTimeEl.text(currentSeekTime);
+ this.displayedSeekTime = currentSeekTime;
+ }
+
+ if (this.durationShown) {
+ this.$durationEl.show();
+ var currentDuration = (0, _utils.formatTime)(this.actualLiveTime ? seekTime.secondsSinceMidnight : this.duration, this.actualLiveTime);
+ if (currentDuration !== this.displayedDuration) {
+ this.$durationEl.text(currentDuration);
+ this.displayedDuration = currentDuration;
+ }
+ } else {
+ this.$durationEl.hide();
+ }
+
+ // the element must be unhidden before its width is requested, otherwise it's width will be reported as 0
+ this.$el.show();
+ var containerWidth = this.mediaControl.$seekBarContainer.width();
+ var elWidth = this.$el.width();
+ var elLeftPos = this.hoverPosition * containerWidth;
+ elLeftPos -= elWidth / 2;
+ elLeftPos = Math.max(0, Math.min(elLeftPos, containerWidth - elWidth));
+ this.$el.css('left', elLeftPos);
+ }
+ };
+
+ SeekTime.prototype.shouldBeVisible = function shouldBeVisible() {
+ return this.mediaControlContainer && this.mediaControlContainer.settings.seekEnabled && this.hoveringOverSeekBar && this.hoverPosition !== null && this.duration !== null;
+ };
+
+ SeekTime.prototype.render = function render() {
+ this.rendered = true;
+ this.displayedDuration = null;
+ this.displayedSeekTime = null;
+ var style = _styler2.default.getStyleFor(_seek_time2.default);
+ this.$el.html(this.template());
+ this.$el.append(style);
+ this.$el.hide();
+ this.mediaControl.$el.append(this.el);
+ this.$seekTimeEl = this.$el.find('[data-seek-time]');
+ this.$durationEl = this.$el.find('[data-duration]');
+ this.$durationEl.hide();
+ this.update();
+ };
+
+ return SeekTime;
+ }(_ui_core_plugin2.default);
+
+ exports.default = SeekTime;
+ module.exports = exports['default'];
+
+/***/ },
+/* 108 */
+/***/ function(module, exports, __webpack_require__) {
+
+ exports = module.exports = __webpack_require__(25)();
+ // imports
+
+
+ // module
+ exports.push([module.id, ".seek-time[data-seek-time] {\n position: absolute;\n white-space: nowrap;\n height: 20px;\n line-height: 20px;\n font-size: 0;\n left: -100%;\n bottom: 55px;\n background-color: rgba(2, 2, 2, 0.5);\n z-index: 9999;\n -webkit-transition: opacity 0.1s ease;\n -moz-transition: opacity 0.1s ease;\n transition: opacity 0.1s ease; }\n .seek-time[data-seek-time].hidden[data-seek-time] {\n opacity: 0; }\n .seek-time[data-seek-time] [data-seek-time] {\n display: inline-block;\n color: white;\n font-size: 10px;\n padding-left: 7px;\n padding-right: 7px;\n vertical-align: top; }\n .seek-time[data-seek-time] [data-duration] {\n display: inline-block;\n color: rgba(255, 255, 255, 0.5);\n font-size: 10px;\n padding-right: 7px;\n vertical-align: top; }\n .seek-time[data-seek-time] [data-duration]:before {\n content: \"|\";\n margin-right: 7px; }\n", ""]);
+
+ // exports
+
+
+/***/ },
+/* 109 */
+/***/ function(module, exports) {
+
+ module.exports = "<span data-seek-time></span>\n<span data-duration></span>\n";
+
+/***/ },
+/* 110 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _core_plugin = __webpack_require__(105);
+
+ var _core_plugin2 = _interopRequireDefault(_core_plugin);
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var SourcesPlugin = function (_CorePlugin) {
+ _inherits(SourcesPlugin, _CorePlugin);
+
+ function SourcesPlugin() {
+ _classCallCheck(this, SourcesPlugin);
+
+ return _possibleConstructorReturn(this, _CorePlugin.apply(this, arguments));
+ }
+
+ SourcesPlugin.prototype.bindEvents = function bindEvents() {
+ this.listenTo(this.core, _events2.default.CORE_CONTAINERS_CREATED, this.onContainersCreated);
+ };
+
+ SourcesPlugin.prototype.onContainersCreated = function onContainersCreated() {
+ var firstValidSource = this.core.containers.filter(function (container) {
+ return container.playback.name !== 'no_op';
+ })[0] || this.core.containers[0];
+ if (firstValidSource) {
+ this.core.containers.forEach(function (container) {
+ if (container !== firstValidSource) {
+ container.destroy();
+ }
+ });
+ }
+ };
+
+ _createClass(SourcesPlugin, [{
+ key: 'name',
+ get: function get() {
+ return 'sources';
+ }
+ }]);
+
+ return SourcesPlugin;
+ }(_core_plugin2.default);
+
+ exports.default = SourcesPlugin;
+ module.exports = exports['default'];
+
+/***/ },
+/* 111 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _events = __webpack_require__(5);
+
+ var _events2 = _interopRequireDefault(_events);
+
+ var _core_plugin = __webpack_require__(105);
+
+ var _core_plugin2 = _interopRequireDefault(_core_plugin);
+
+ var _utils = __webpack_require__(2);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var EndVideo = function (_CorePlugin) {
+ _inherits(EndVideo, _CorePlugin);
+
+ function EndVideo() {
+ _classCallCheck(this, EndVideo);
+
+ return _possibleConstructorReturn(this, _CorePlugin.apply(this, arguments));
+ }
+
+ EndVideo.prototype.bindEvents = function bindEvents() {
+ this.listenTo(this.core.mediaControl, _events2.default.MEDIACONTROL_CONTAINERCHANGED, this.containerChanged);
+ var container = this.core.getCurrentContainer();
+ if (container) {
+ this.listenTo(container, _events2.default.CONTAINER_ENDED, this.ended);
+ this.listenTo(container, _events2.default.CONTAINER_STOP, this.ended);
+ }
+ };
+
+ EndVideo.prototype.containerChanged = function containerChanged() {
+ this.stopListening();
+ this.bindEvents();
+ };
+
+ EndVideo.prototype.ended = function ended() {
+ var exitOnEnd = typeof this.core.options.exitFullscreenOnEnd === 'undefined' || this.core.options.exitFullscreenOnEnd;
+ if (exitOnEnd && _utils.Fullscreen.isFullscreen()) {
+ this.core.toggleFullscreen();
+ }
+ };
+
+ _createClass(EndVideo, [{
+ key: 'name',
+ get: function get() {
+ return 'end_video';
+ }
+ }]);
+
+ return EndVideo;
+ }(_core_plugin2.default);
+
+ exports.default = EndVideo;
+ module.exports = exports['default'];
+
+/***/ },
+/* 112 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+ var _utils = __webpack_require__(2);
+
+ var _core_plugin = __webpack_require__(105);
+
+ var _core_plugin2 = _interopRequireDefault(_core_plugin);
+
+ var _lodash = __webpack_require__(32);
+
+ var _lodash2 = _interopRequireDefault(_lodash);
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ /**
+ * The internationalization (i18n) plugin
+ * @class Strings
+ * @constructor
+ * @extends CorePlugin
+ * @module plugins
+ */
+ var Strings = function (_CorePlugin) {
+ _inherits(Strings, _CorePlugin);
+
+ _createClass(Strings, [{
+ key: 'name',
+ get: function get() {
+ return 'strings';
+ }
+ }]);
+
+ function Strings(core) {
+ _classCallCheck(this, Strings);
+
+ var _this = _possibleConstructorReturn(this, _CorePlugin.call(this, core));
+
+ _this._initializeMessages();
+ return _this;
+ }
+ /**
+ * Gets a translated string for the given key.
+ * @method t
+ * @param {String} key the key to all messages
+ * @return {String} translated label
+ */
+
+
+ Strings.prototype.t = function t(key) {
+ var lang = this._language();
+ var i18n = lang && this._messages[lang] || this._messages['en'];
+ return i18n[key] || key;
+ };
+
+ Strings.prototype._language = function _language() {
+ return this.core.options.language || (0, _utils.getBrowserLanguage)();
+ };
+
+ Strings.prototype._initializeMessages = function _initializeMessages() {
+ this._messages = (0, _lodash2.default)({
+ 'en': {
+ 'live': 'live',
+ 'back_to_live': 'back to live',
+ 'playback_not_supported': 'Your browser does not support the playback of this video. Please try using a different browser.'
+ },
+ 'pt': {
+ 'live': 'ao vivo',
+ 'back_to_live': 'voltar para o ao vivo',
+ 'playback_not_supported': 'Seu navegador não supporta a reprodução deste video. Por favor, tente usar um navegador diferente.'
+ },
+ 'es': {
+ 'live': 'vivo',
+ 'back_to_live': 'volver en vivo',
+ 'playback_not_supported': 'Su navegador no soporta la reproducción de un video. Por favor, trate de usar un navegador diferente.'
+ },
+ 'ru': {
+ 'live': 'прямой эфир',
+ 'back_to_live': 'к прямому эфиру',
+ 'playback_not_supported': 'Ваш браузер не поддерживает воспроизведение этого видео. Пожалуйста, попробуйте другой браузер.'
+ }
+ }, this.core.options.strings || {});
+
+ this._messages['pt-BR'] = this._messages['pt'];
+ this._messages['en-US'] = this._messages['en'];
+ this._messages['es-419'] = this._messages['es'];
+ };
+
+ return Strings;
+ }(_core_plugin2.default);
+
+ exports.default = Strings;
+ module.exports = exports['default'];
+
+/***/ }
+/******/ ])
+});
+; \ No newline at end of file