PageSourceSearch

https://www.scientology-madrid.es/theme/js/_combined_script.js?_=9…&p=%2Ftheme%2Fjs%2Fjquery.easing.1.3.js

js scientology-madrid.es collected 2026-09-26 16:14:58 UTC 1,830,325 bytes, 52,728 lines download raw bytes

1/**
2 * @license
3 * Video.js 5.20.2 <http://videojs.com/>
4 * Copyright Brightcove, Inc. <https://www.brightcove.com/>
5 * Available under Apache License Version 2.0
6 * <https://github.com/videojs/video.js/blob/master/LICENSE>
7 *
8 * Includes vtt.js <https://github.com/mozilla/vtt.js>
9 * Available under Apache License Version 2.0
10 * <https://github.com/mozilla/vtt.js/blob/master/LICENSE>
11 */
12
13(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.videojs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
14'use strict';
15
16exports.__esModule = true;
17
18var _button = _dereq_(2);
19
20var _button2 = _interopRequireDefault(_button);
21
22var _component = _dereq_(5);
23
24var _component2 = _interopRequireDefault(_component);
25
26function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
27
28function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
29
30function _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; }
31
32function _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; } /**
33                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file big-play-button.js
34                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
35
36
37/**
38 * The initial play button that shows before the video has played. The hiding of the
39 * `BigPlayButton` get done via CSS and `Player` states.
40 *
41 * @extends Button
42 */
43var BigPlayButton = function (_Button) {
44  _inherits(BigPlayButton, _Button);
45
46  function BigPlayButton(player, options) {
47    _classCallCheck(this, BigPlayButton);
48
49    var _this = _possibleConstructorReturn(this, _Button.call(this, player, options));
50
51    _this.mouseused_ = false;
52
53    _this.on('mousedown', _this.handleMouseDown);
54    return _this;
55  }
56
57  /**
58   * Builds the default DOM `className`.
59   *
60   * @return {string}
61   *         The DOM `className` for this object. Always returns 'vjs-big-play-button'.
62   */
63
64
65  BigPlayButton.prototype.buildCSSClass = function buildCSSClass() {
66    return 'vjs-big-play-button';
67  };
68
69  /**
70   * This gets called when a `BigPlayButton` "clicked". See {@link ClickableComponent}
71   * for more detailed information on what a click can be.
72   *
73   * @param {EventTarget~Event} event
74   *        The `keydown`, `tap`, or `click` event that caused this function to be
75   *        called.
76   *
77   * @listens tap
78   * @listens click
79   */
80
81
82  BigPlayButton.prototype.handleClick = function handleClick(event) {
83    var playPromise = this.player_.play();
84
85    // exit early if clicked via the mouse
86    if (this.mouseused_ && event.clientX && event.clientY) {
87      return;
88    }
89
90    var cb = this.player_.getChild('controlBar');
91    var playToggle = cb && cb.getChild('playToggle');
92
93    if (!playToggle) {
94      this.player_.focus();
95      return;
96    }
97
98    var playFocus = function playFocus() {
99      return playToggle.focus();
100    };
101
102    if (playPromise && playPromise.then) {
103      var ignoreRejectedPlayPromise = function ignoreRejectedPlayPromise() {};
104
105      playPromise.then(playFocus, ignoreRejectedPlayPromise);
106    } else {
107      this.setTimeout(playFocus, 1);
108    }
109  };
110
111  BigPlayButton.prototype.handleKeyPress = function handleKeyPress(event) {
112    this.mouseused_ = false;
113
114    _Button.prototype.handleKeyPress.call(this, event);
115  };
116
117  BigPlayButton.prototype.handleMouseDown = function handleMouseDown(event) {
118    this.mouseused_ = true;
119  };
120
121  return BigPlayButton;
122}(_button2['default']);
123
124/**
125 * The text that should display over the `BigPlayButton`s controls. Added to for localization.
126 *
127 * @type {string}
128 * @private
129 */
130
131
132BigPlayButton.prototype.controlText_ = 'Play Video';
133
134_component2['default'].registerComponent('BigPlayButton', BigPlayButton);
135exports['default'] = BigPlayButton;
136
137},{"2":2,"5":5}],2:[function(_dereq_,module,exports){
138'use strict';
139
140exports.__esModule = true;
141
142var _clickableComponent = _dereq_(3);
143
144var _clickableComponent2 = _interopRequireDefault(_clickableComponent);
145
146var _component = _dereq_(5);
147
148var _component2 = _interopRequireDefault(_component);
149
150var _log = _dereq_(86);
151
152var _log2 = _interopRequireDefault(_log);
153
154var _obj = _dereq_(88);
155
156function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
157
158function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
159
160function _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; }
161
162function _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; } /**
163                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file button.js
164                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
165
166
167/**
168 * Base class for all buttons.
169 *
170 * @extends ClickableComponent
171 */
172var Button = function (_ClickableComponent) {
173  _inherits(Button, _ClickableComponent);
174
175  function Button() {
176    _classCallCheck(this, Button);
177
178    return _possibleConstructorReturn(this, _ClickableComponent.apply(this, arguments));
179  }
180
181  /**
182   * Create the `Button`s DOM element.
183   *
184   * @param {string} [tag=button]
185   *        Element's node type. e.g. 'button'
186   *
187   * @param {Object} [props={}]
188   *        An object of properties that should be set on the element.
189   *
190   * @param {Object} [attributes={}]
191   *        An object of attributes that should be set on the element.
192   *
193   * @return {Element}
194   *         The element that gets created.
195   */
196  Button.prototype.createEl = function createEl() {
197    var tag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'button';
198    var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
199    var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
200
201    props = (0, _obj.assign)({
202      className: this.buildCSSClass()
203    }, props);
204
205    if (tag !== 'button') {
206      _log2['default'].warn('Creating a Button with an HTML element of ' + tag + ' is deprecated; use ClickableComponent instead.');
207
208      // Add properties for clickable element which is not a native HTML button
209      props = (0, _obj.assign)({
210        tabIndex: 0
211      }, props);
212
213      // Add ARIA attributes for clickable element which is not a native HTML button
214      attributes = (0, _obj.assign)({
215        role: 'button'
216      }, attributes);
217    }
218
219    // Add attributes for button element
220    attributes = (0, _obj.assign)({
221
222      // Necessary since the default button type is "submit"
223      'type': 'button',
224
225      // let the screen reader user know that the text of the button may change
226      'aria-live': 'polite'
227    }, attributes);
228
229    var el = _component2['default'].prototype.createEl.call(this, tag, props, attributes);
230
231    this.createControlTextEl(el);
232
233    return el;
234  };
235
236  /**
237   * Add a child `Component` inside of this `Button`.
238   *
239   * @param {string|Component} child
240   *        The name or instance of a child to add.
241   *
242   * @param {Object} [options={}]
243   *        The key/value store of options that will get passed to children of
244   *        the child.
245   *
246   * @return {Component}
247   *         The `Component` that gets added as a child. When using a string the
248   *         `Component` will get created by this process.
249   *
250   * @deprecated since version 5
251   */
252
253
254  Button.prototype.addChild = function addChild(child) {
255    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
256
257    var className = this.constructor.name;
258
259    _log2['default'].warn('Adding an actionable (user controllable) child to a Button (' + className + ') is not supported; use a ClickableComponent instead.');
260
261    // Avoid the error message generated by ClickableComponent's addChild method
262    return _component2['default'].prototype.addChild.call(this, child, options);
263  };
264
265  /**
266   * Enable the `Button` element so that it can be activated or clicked. Use this with
267   * {@link Button#disable}.
268   */
269
270
271  Button.prototype.enable = function enable() {
272    _ClickableComponent.prototype.enable.call(this);
273    this.el_.removeAttribute('disabled');
274  };
275
276  /**
277   * Enable the `Button` element so that it cannot be activated or clicked. Use this with
278   * {@link Button#enable}.
279   */
280
281
282  Button.prototype.disable = function disable() {
283    _ClickableComponent.prototype.disable.call(this);
284    this.el_.setAttribute('disabled', 'disabled');
285  };
286
287  /**
288   * This gets called when a `Button` has focus and `keydown` is triggered via a key
289   * press.
290   *
291   * @param {EventTarget~Event} event
292   *        The event that caused this function to get called.
293   *
294   * @listens keydown
295   */
296
297
298  Button.prototype.handleKeyPress = function handleKeyPress(event) {
299
300    // Ignore Space (32) or Enter (13) key operation, which is handled by the browser for a button.
301    if (event.which === 32 || event.which === 13) {
302      return;
303    }
304
305    // Pass keypress handling up for unsupported keys
306    _ClickableComponent.prototype.handleKeyPress.call(this, event);
307  };
308
309  return Button;
310}(_clickableComponent2['default']);
311
312_component2['default'].registerComponent('Button', Button);
313exports['default'] = Button;
314
315},{"3":3,"5":5,"86":86,"88":88}],3:[function(_dereq_,module,exports){
316'use strict';
317
318exports.__esModule = true;
319
320var _component = _dereq_(5);
321
322var _component2 = _interopRequireDefault(_component);
323
324var _dom = _dereq_(81);
325
326var Dom = _interopRequireWildcard(_dom);
327
328var _events = _dereq_(82);
329
330var Events = _interopRequireWildcard(_events);
331
332var _fn = _dereq_(83);
333
334var Fn = _interopRequireWildcard(_fn);
335
336var _log = _dereq_(86);
337
338var _log2 = _interopRequireDefault(_log);
339
340var _document = _dereq_(94);
341
342var _document2 = _interopRequireDefault(_document);
343
344var _obj = _dereq_(88);
345
346function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
347
348function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
349
350function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
351
352function _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; }
353
354function _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, { c
354onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
355                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file button.js
356                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
357
358
359/**
360 * Clickable Component which is clickable or keyboard actionable,
361 * but is not a native HTML button.
362 *
363 * @extends Component
364 */
365var ClickableComponent = function (_Component) {
366  _inherits(ClickableComponent, _Component);
367
368  /**
369   * Creates an instance of this class.
370   *
371   * @param  {Player} player
372   *         The `Player` that this class should be attached to.
373   *
374   * @param  {Object} [options]
375   *         The key/value store of player options.
376   */
377  function ClickableComponent(player, options) {
378    _classCallCheck(this, ClickableComponent);
379
380    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
381
382    _this.emitTapEvents();
383
384    _this.enable();
385    return _this;
386  }
387
388  /**
389   * Create the `Component`s DOM element.
390   *
391   * @param {string} [tag=div]
392   *        The element's node type.
393   *
394   * @param {Object} [props={}]
395   *        An object of properties that should be set on the element.
396   *
397   * @param {Object} [attributes={}]
398   *        An object of attributes that should be set on the element.
399   *
400   * @return {Element}
401   *         The element that gets created.
402   */
403
404
405  ClickableComponent.prototype.createEl = function createEl() {
406    var tag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div';
407    var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
408    var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
409
410    props = (0, _obj.assign)({
411      className: this.buildCSSClass(),
412      tabIndex: 0
413    }, props);
414
415    if (tag === 'button') {
416      _log2['default'].error('Creating a ClickableComponent with an HTML element of ' + tag + ' is not supported; use a Button instead.');
417    }
418
419    // Add ARIA attributes for clickable element which is not a native HTML button
420    attributes = (0, _obj.assign)({
421      'role': 'button',
422
423      // let the screen reader user know that the text of the element may change
424      'aria-live': 'polite'
425    }, attributes);
426
427    this.tabIndex_ = props.tabIndex;
428
429    var el = _Component.prototype.createEl.call(this, tag, props, attributes);
430
431    this.createControlTextEl(el);
432
433    return el;
434  };
435
436  /**
437   * Create a control text element on this `Component`
438   *
439   * @param {Element} [el]
440   *        Parent element for the control text.
441   *
442   * @return {Element}
443   *         The control text element that gets created.
444   */
445
446
447  ClickableComponent.prototype.createControlTextEl = function createControlTextEl(el) {
448    this.controlTextEl_ = Dom.createEl('span', {
449      className: 'vjs-control-text'
450    });
451
452    if (el) {
453      el.appendChild(this.controlTextEl_);
454    }
455
456    this.controlText(this.controlText_, el);
457
458    return this.controlTextEl_;
459  };
460
461  /**
462   * Get or set the localize text to use for the controls on the `Component`.
463   *
464   * @param {string} [text]
465   *        Control text for element.
466   *
467   * @param {Element} [el=this.el()]
468   *        Element to set the title on.
469   *
470   * @return {string|ClickableComponent}
471   *         - The control text when getting
472   *         - Returns itself when setting; method can be chained.
473   */
474
475
476  ClickableComponent.prototype.controlText = function controlText(text) {
477    var el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.el();
478
479    if (!text) {
480      return this.controlText_ || 'Need Text';
481    }
482
483    var localizedText = this.localize(text);
484
485    this.controlText_ = text;
486    this.controlTextEl_.innerHTML = localizedText;
487
488    if (!this.nonIconControl) {
489      // Set title attribute if only an icon is shown
490      el.setAttribute('title', localizedText);
491    }
492
493    return this;
494  };
495
496  /**
497   * Builds the default DOM `className`.
498   *
499   * @return {string}
500   *         The DOM `className` for this object.
501   */
502
503
504  ClickableComponent.prototype.buildCSSClass = function buildCSSClass() {
505    return 'vjs-control vjs-button ' + _Component.prototype.buildCSSClass.call(this);
506  };
507
508  /**
509   * Enable this `Component`s element.
510   *
511   * @return {ClickableComponent}
512   *         Returns itself; method can be chained.
513   */
514
515
516  ClickableComponent.prototype.enable = function enable() {
517    this.removeClass('vjs-disabled');
518    this.el_.setAttribute('aria-disabled', 'false');
519    if (typeof this.tabIndex_ !== 'undefined') {
520      this.el_.setAttribute('tabIndex', this.tabIndex_);
521    }
522    this.off(['tap', 'click'], this.handleClick);
523    this.off('focus', this.handleFocus);
524    this.off('blur', this.handleBlur);
525    this.on(['tap', 'click'], this.handleClick);
526    this.on('focus', this.handleFocus);
527    this.on('blur', this.handleBlur);
528    return this;
529  };
530
531  /**
532   * Disable this `Component`s element.
533   *
534   * @return {ClickableComponent}
535   *         Returns itself; method can be chained.
536   */
537
538
539  ClickableComponent.prototype.disable = function disable() {
540    this.addClass('vjs-disabled');
541    this.el_.setAttribute('aria-disabled', 'true');
542    if (typeof this.tabIndex_ !== 'undefined') {
543      this.el_.removeAttribute('tabIndex');
544    }
545    this.off(['tap', 'click'], this.handleClick);
546    this.off('focus', this.handleFocus);
547    this.off('blur', this.handleBlur);
548    return this;
549  };
550
551  /**
552   * This gets called when a `ClickableComponent` gets:
553   * - Clicked (via the `click` event, listening starts in the constructor)
554   * - Tapped (via the `tap` event, listening starts in the constructor)
555   * - The following things happen in order:
556   *   1. {@link ClickableComponent#handleFocus} is called via a `focus` event on the
557   *      `ClickableComponent`.
558   *   2. {@link ClickableComponent#handleFocus} adds a listener for `keydown` on using
559   *      {@link ClickableComponent#handleKeyPress}.
560   *   3. `ClickableComponent` has not had a `blur` event (`blur` means that focus was lost). The user presses
561   *      the space or enter key.
562   *   4. {@link ClickableComponent#handleKeyPress} calls this function with the `keydown`
563   *      event as a parameter.
564   *
565   * @param {EventTarget~Event} event
566   *        The `keydown`, `tap`, or `click` event that caused this function to be
567   *        called.
568   *
569   * @listens tap
570   * @listens click
571   * @abstract
572   */
573
574
575  ClickableComponent.prototype.handleClick = function handleClick(event) {};
576
577  /**
578   * This gets called when a `ClickableComponent` gains focus via a `focus` event.
579   * Turns on listening for `keydown` events. When they happen it
580   * calls `this.handleKeyPress`.
581   *
582   * @param {EventTarget~Event} event
583   *        The `focus` event that caused this function to be called.
584   *
585   * @listens focus
586   */
587
588
589  ClickableComponent.prototype.handleFocus = function handleFocus(event) {
590    Events.on(_document2['default'], 'keydown', Fn.bind(this, this.handleKeyPress));
591  };
592
593  /**
594   * Called when this ClickableComponent has focus and a key gets pressed down. By
595   * default it will call `this.handleClick` when the key is space or enter.
596   *
597   * @param {EventTarget~Event} event
598   *        The `keydown` event that caused this function to be called.
599   *
600   * @listens keydown
601   */
602
603
604  ClickableComponent.prototype.handleKeyPress = function handleKeyPress(event) {
605
606    // Support Space (32) or Enter (13) key operation to fire a click event
607    if (event.which === 32 || event.which === 13) {
608      event.preventDefault();
609      this.handleClick(event);
610    } else if (_Component.prototype.handleKeyPress) {
611
612      // Pass keypress handling up for unsupported keys
613      _Component.prototype.handleKeyPress.call(this, event);
614    }
615  };
616
617  /**
618   * Called when a `ClickableComponent` loses focus. Turns off the listener for
619   * `keydown` events. Which Stops `this.handleKeyPress` from getting called.
620   *
621   * @param {EventTarget~Event} event
622   *        The `blur` event that caused this function to be called.
623   *
624   * @listens blur
625   */
626
627
628  ClickableComponent.prototype.handleBlur = function handleBlur(event) {
629    Events.off(_document2['default'], 'keydown', Fn.bind(this, this.handleKeyPress));
630  };
631
632  return ClickableComponent;
633}(_component2['default']);
634
635_component2['default'].registerComponent('ClickableComponent', ClickableComponent);
636exports['default'] = ClickableComponent;
637
638},{"5":5,"81":81,"82":82,"83":83,"86":86,"88":88,"94":94}],4:[function(_dereq_,module,exports){
639'use strict';
640
641exports.__esModule = true;
642
643var _button = _dereq_(2);
644
645var _button2 = _interopRequireDefault(_button);
646
647var _component = _dereq_(5);
648
649var _component2 = _interopRequireDefault(_component);
650
651function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
652
653function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
654
655function _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; }
656
657function _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; } /**
658                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file close-button.js
659                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
660
661
662/**
663 * The `CloseButton` is a `{@link Button}` that fires a `close` event when
664 * it gets clicked.
665 *
666 * @extends Button
667 */
668var CloseButton = function (_Button) {
669  _inherits(CloseButton, _Button);
670
671  /**
672   * Creates an instance of the this class.
673   *
674   * @param  {Player} player
675   *         The `Player` that this class should be attached to.
676   *
677   * @param  {Object} [options]
678   *         The key/value store of player options.
679   */
680  function CloseButton(player, options) {
681    _classCallCheck(this, CloseButton);
682
683    var _this = _possibleConstructorReturn(this, _Button.call(this, player, options));
684
685    _this.controlText(options && options.controlText || _this.localize('Close'));
686    return _this;
687  }
688
689  /**
690   * Builds the default DOM `className`.
691   *
692   * @return {string}
693   *         The DOM `className` for this object.
694   */
695
696
697  CloseButton.prototype.buildCSSClass = function buildCSSClass() {
698    return 'vjs-close-button ' + _Button.prototype.buildCSSClass.call(this);
699  };
700
701  /**
702   * This gets called when a `CloseButton` gets clicked. See
703   * {@link ClickableComponent#handleClick} for more information on when this will be
704   * triggered
705   *
706   * @param {EventTarget~Event} event
707   *        The `keydown`, `tap`, or `click` event that caused this function to be
708   *        called.
709   *
710   * @listens tap
711   * @listens click
712   * @fires CloseButton#close
713   */
714
715
716  CloseButton.prototype.handleClick = function handleClick(event) {
717
718    /**
719     * Triggered when the a `CloseButton` is clicked.
720     *
721     * @event CloseButton#close
722     * @type {EventTarget~Event}
723     *
724     * @property {boolean} [bubbles=false]
725     *           set to false so that the close event does not
726     *           bubble up to parents if there is no listener
727     */
728    this.trigger({ type: 'close', bubbles: false });
729  };
730
731  return CloseButton;
732}(_button2['default']);
733
734_component2['default'].registerComponent('CloseButton', CloseButton);
735exports['default'] = CloseButton;
736
737},{"2":2,"5":5}],5:[function(_dereq_,module,exports){
738'use strict';
739
740exports.__esModule = true;
741
742var _window = _dereq_(95);
743
744var _window2 = _interopRequireDefault(_window);
745
746var _dom = _dereq_(81);
747
748var Dom = _interopRequireWildcard(_dom);
749
750var _fn = _dereq_(83);
751
752var Fn = _interopRequireWildcard(_fn);
753
754var _guid = _dereq_(85);
755
756var Guid = _interopRequireWildcard(_guid);
757
758var _events = _dereq_(82);
759
760var Events = _interopRequireWildcard(_events);
761
762var _log = _dereq_(86);
763
764var _log2 = _interopRequireDefault(_log);
765
766var _toTitleCase = _dereq_(91);
767
768var _toTitleCase2 = _interopRequireDefault(_toTitleCase);
769
770var _mergeOptions = _dereq_(87);
771
772var _mergeOptions2 = _interopRequireDefault(_mergeOptions);
773
774function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
775
776function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
777
778function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /**
779                                                                                                                                                           * Player Component - Base class for all UI objects
780                                                                                                                                                           *
781                                                                                                                                                           * @file component.js
782                                                                                                                                                           */
783
784
785/**
786 * Base class for all UI Components.
787 * Components are UI objects which represent both a javascript object and an element
788 * in the DOM. They can be children of other components, and can have
789 * children themselves.
790 *
791 * Components can also use methods from {@link EventTarget}
792 */
793var Component = function () {
794
795  /**
796   * A callback that is called when a component is ready. Does not have any
797   * paramters and any callback value will be ignored.
798   *
799   * @callback Component~ReadyCallback
800   * @this Component
801   */
802
803  /**
804   * Creates an instance of this class.
805   *
806   * @param {Player} player
807   *        The `Player` that this class should be attached to.
808   *
809   * @param {Object} [options]
810   *        The key/value store of player options.
811   #
812   * @param {Object[]} [options.children]
813   *        An array of children objects to intialize this component with. Children objects have
814   *        a name property that will be used if more than one component of the same type needs to be
815   *        added.
816   *
817   * @param {Component~ReadyCallback} [ready]
818   *        Function that gets called when the `Component` is ready.
819   */
820  function Component(player, options, ready) {
821    _classCallCheck(this, Component);
822
823    // The component might be the player itself and we can't pass `this` to super
824    if (!player && this.play) {
825      this.player_ = player = this; // eslint-disable-line
826    } else {
827      this.player_ = player;
828    }
829
830    // Make a copy of prototype.options_ to protect against overriding defaults
831    this.options_ = (0, _mergeOptions2['default'])({}, this.options_);
832
833    // Updated options with supplied options
834    options = this.options_ = (0, _mergeOptions2['default'])(this.options_, options);
835
836    // Get ID from options or options element if one is supplied
837    this.id_ = options.id || options.el && options.el.id;
838
839    // If there was no ID from the options, generate one
840    if (!this.id_) {
841      // Don't require the player ID function in the case of mock players
842      var id = player && player.id && player.id() || 'no_player';
843
844      this.id_ = id + '_component_' + Guid.newGUID();
845    }
846
847    this.name_ = options.name || null;
848
849    // Create element if one wasn't provided in options
850    if (options.el) {
851      this.el_ = options.el;
852    } else if (options.createEl !== false) {
853      this.el_ = this.createEl();
854    }
855
856    this.children_ = [];
857    this.childIndex_ = {};
858    this.childNameIndex_ = {};
859
860    // Add any child components in options
861    if (options.initChildren !== false) {
862      this.initChildren();
863    }
864
865    this.ready(ready);
866    // Don't want to trigger ready here or it will before init is actually
867    // finished for all children that run this constructor
868
869    if (options.reportTouchActivity !== false) {
870      this.enableTouchActivity();
871    }
872  }
873
874  /**
875   * Dispose of the `Component` and all child components.
876   *
877   * @fires Component#dispose
878   */
879
880
881  Component.prototype.dispose = function dispose() {
882
883    /**
884     * Triggered when a `Component` is disposed.
885     *
886     * @event Component#dispose
887     * @type {EventTarget~Event}
888     *
889     * @property {boolean} [bubbles=false]
890     *           set to false so that the close event does not
891     *           bubble up
892     */
893    this.trigger({ type: 'dispose', bubbles: false });
894
895    // Dispose all children.
896    if (this.children_) {
897      for (var i = this.children_.length - 1; i >= 0; i--) {
898        if (this.children_[i].dispose) {
899          this.children_[i].dispose();
900        }
901      }
902    }
903
904    // Delete child references
905    this.children_ = null;
906    this.childIndex_ = null;
907    this.childNameIndex_ = null;
908
909    // Remove all event listeners.
910    this.off();
911
912    // Remove element from DOM
913    if (this.el_.parentNode) {
914      this.el_.parentNode.removeChild(this.el_);
915    }
916
917    Dom.removeElData(this.el_);
918    this.el_ = null;
919  };
920
921  /**
922   * Return the {@link Player}
922 that the `Component` has attached to.
923   *
924   * @return {Player}
925   *         The player that this `Component` has attached to.
926   */
927
928
929  Component.prototype.player = function player() {
930    return this.player_;
931  };
932
933  /**
934   * Deep merge of options objects with new options.
935   * > Note: When both `obj` and `options` contain properties whose values are objects.
936   *         The two properties get merged using {@link module:mergeOptions}
937   *
938   * @param {Object} obj
939   *        The object that contains new options.
940   *
941   * @return {Object}
942   *         A new object of `this.options_` and `obj` merged together.
943   *
944   * @deprecated since version 5
945   */
946
947
948  Component.prototype.options = function options(obj) {
949    _log2['default'].warn('this.options() has been deprecated and will be moved to the constructor in 6.0');
950
951    if (!obj) {
952      return this.options_;
953    }
954
955    this.options_ = (0, _mergeOptions2['default'])(this.options_, obj);
956    return this.options_;
957  };
958
959  /**
960   * Get the `Component`s DOM element
961   *
962   * @return {Element}
963   *         The DOM element for this `Component`.
964   */
965
966
967  Component.prototype.el = function el() {
968    return this.el_;
969  };
970
971  /**
972   * Create the `Component`s DOM element.
973   *
974   * @param {string} [tagName]
975   *        Element's DOM node type. e.g. 'div'
976   *
977   * @param {Object} [properties]
978   *        An object of properties that should be set.
979   *
980   * @param {Object} [attributes]
981   *        An object of attributes that should be set.
982   *
983   * @return {Element}
984   *         The element that gets created.
985   */
986
987
988  Component.prototype.createEl = function createEl(tagName, properties, attributes) {
989    return Dom.createEl(tagName, properties, attributes);
990  };
991
992  /**
993   * Localize a string given the string in english.
994   *
995   * @param {string} string
996   *        The string to localize.
997   *
998   * @return {string}
999   *         The localized string or if no localization exists the english string.
1000   */
1001
1002
1003  Component.prototype.localize = function localize(string) {
1004    var code = this.player_.language && this.player_.language();
1005    var languages = this.player_.languages && this.player_.languages();
1006
1007    if (!code || !languages) {
1008      return string;
1009    }
1010
1011    var language = languages[code];
1012
1013    if (language && language[string]) {
1014      return language[string];
1015    }
1016
1017    var primaryCode = code.split('-')[0];
1018    var primaryLang = languages[primaryCode];
1019
1020    if (primaryLang && primaryLang[string]) {
1021      return primaryLang[string];
1022    }
1023
1024    return string;
1025  };
1026
1027  /**
1028   * Return the `Component`s DOM element. This is where children get inserted.
1029   * This will usually be the the same as the element returned in {@link Component#el}.
1030   *
1031   * @return {Element}
1032   *         The content element for this `Component`.
1033   */
1034
1035
1036  Component.prototype.contentEl = function contentEl() {
1037    return this.contentEl_ || this.el_;
1038  };
1039
1040  /**
1041   * Get this `Component`s ID
1042   *
1043   * @return {string}
1044   *         The id of this `Component`
1045   */
1046
1047
1048  Component.prototype.id = function id() {
1049    return this.id_;
1050  };
1051
1052  /**
1053   * Get the `Component`s name. The name gets used to reference the `Component`
1054   * and is set during registration.
1055   *
1056   * @return {string}
1057   *         The name of this `Component`.
1058   */
1059
1060
1061  Component.prototype.name = function name() {
1062    return this.name_;
1063  };
1064
1065  /**
1066   * Get an array of all child components
1067   *
1068   * @return {Array}
1069   *         The children
1070   */
1071
1072
1073  Component.prototype.children = function children() {
1074    return this.children_;
1075  };
1076
1077  /**
1078   * Returns the child `Component` with the given `id`.
1079   *
1080   * @param {string} id
1081   *        The id of the child `Component` to get.
1082   *
1083   * @return {Component|undefined}
1084   *         The child `Component` with the given `id` or undefined.
1085   */
1086
1087
1088  Component.prototype.getChildById = function getChildById(id) {
1089    return this.childIndex_[id];
1090  };
1091
1092  /**
1093   * Returns the child `Component` with the given `name`.
1094   *
1095   * @param {string} name
1096   *        The name of the child `Component` to get.
1097   *
1098   * @return {Component|undefined}
1099   *         The child `Component` with the given `name` or undefined.
1100   */
1101
1102
1103  Component.prototype.getChild = function getChild(name) {
1104    if (!name) {
1105      return;
1106    }
1107
1108    name = (0, _toTitleCase2['default'])(name);
1109
1110    return this.childNameIndex_[name];
1111  };
1112
1113  /**
1114   * Add a child `Component` inside the current `Component`.
1115   *
1116   *
1117   * @param {string|Component} child
1118   *        The name or instance of a child to add.
1119   *
1120   * @param {Object} [options={}]
1121   *        The key/value store of options that will get passed to children of
1122   *        the child.
1123   *
1124   * @param {number} [index=this.children_.length]
1125   *        The index to attempt to add a child into.
1126   *
1127   * @return {Component}
1128   *         The `Component` that gets added as a child. When using a string the
1129   *         `Component` will get created by this process.
1130   */
1131
1132
1133  Component.prototype.addChild = function addChild(child) {
1134    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1135    var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.children_.length;
1136
1137    var component = void 0;
1138    var componentName = void 0;
1139
1140    // If child is a string, create component with options
1141    if (typeof child === 'string') {
1142      componentName = (0, _toTitleCase2['default'])(child);
1143
1144      // Options can also be specified as a boolean,
1145      // so convert to an empty object if false.
1146      if (!options) {
1147        options = {};
1148      }
1149
1150      // Same as above, but true is deprecated so show a warning.
1151      if (options === true) {
1152        _log2['default'].warn('Initializing a child component with `true` is deprecated.' + 'Children should be defined in an array when possible, ' + 'but if necessary use an object instead of `true`.');
1153        options = {};
1154      }
1155
1156      var componentClassName = options.componentClass || componentName;
1157
1158      // Set name through options
1159      options.name = componentName;
1160
1161      // Create a new object & element for this controls set
1162      // If there's no .player_, this is a player
1163      var ComponentClass = Component.getComponent(componentClassName);
1164
1165      if (!ComponentClass) {
1166        throw new Error('Component ' + componentClassName + ' does not exist');
1167      }
1168
1169      // data stored directly on the videojs object may be
1170      // misidentified as a component to retain
1171      // backwards-compatibility with 4.x. check to make sure the
1172      // component class can be instantiated.
1173      if (typeof ComponentClass !== 'function') {
1174        return null;
1175      }
1176
1177      component = new ComponentClass(this.player_ || this, options);
1178
1179      // child is a component instance
1180    } else {
1181      component = child;
1182    }
1183
1184    this.children_.splice(index, 0, component);
1185
1186    if (typeof component.id === 'function') {
1187      this.childIndex_[component.id()] = component;
1188    }
1189
1190    // If a name wasn't used to create the component, check if we can use the
1191    // name function of the component
1192    componentName = componentName || component.name && (0, _toTitleCase2['default'])(component.name());
1193
1194    if (componentName) {
1195      this.childNameIndex_[componentName] = component;
1196    }
1197
1198    // Add the UI object's element to the container div (box)
1199    // Having an element is not required
1200    if (typeof component.el === 'function' && component.el()) {
1201      var childNodes = this.contentEl().children;
vendor: 4,344 bytes, lines 1202-1346
1202      var refNode = childNodes[index] || null;
1203
1204      this.contentEl().insertBefore(component.el(), refNode);
1205    }
1206
1207    // Return so it can stored on parent object if desired.
1208    return component;
1209  };
1210
1211  /**
1212   * Remove a child `Component` from this `Component`s list of children. Also removes
1213   * the child `Component`s element from this `Component`s element.
1214   *
1215   * @param {Component} component
1216   *        The child `Component` to remove.
1217   */
1218
1219
1220  Component.prototype.removeChild = function removeChild(component) {
1221    if (typeof component === 'string') {
1222      component = this.getChild(component);
1223    }
1224
1225    if (!component || !this.children_) {
1226      return;
1227    }
1228
1229    var childFound = false;
1230
1231    for (var i = this.children_.length - 1; i >= 0; i--) {
1232      if (this.children_[i] === component) {
1233        childFound = true;
1234        this.children_.splice(i, 1);
1235        break;
1236      }
1237    }
1238
1239    if (!childFound) {
1240      return;
1241    }
1242
1243    this.childIndex_[component.id()] = null;
1244    this.childNameIndex_[component.name()] = null;
1245
1246    var compEl = component.el();
1247
1248    if (compEl && compEl.parentNode === this.contentEl()) {
1249      this.contentEl().removeChild(component.el());
1250    }
1251  };
1252
1253  /**
1254   * Add and initialize default child `Component`s based upon options.
1255   */
1256
1257
1258  Component.prototype.initChildren = function initChildren() {
1259    var _this = this;
1260
1261    var children = this.options_.children;
1262
1263    if (children) {
1264      // `this` is `parent`
1265      var parentOptions = this.options_;
1266
1267      var handleAdd = function handleAdd(child) {
1268        var name = child.name;
1269        var opts = child.opts;
1270
1271        // Allow options for children to be set at the parent options
1272        // e.g. videojs(id, { controlBar: false });
1273        // instead of videojs(id, { children: { controlBar: false });
1274        if (parentOptions[name] !== undefined) {
1275          opts = parentOptions[name];
1276        }
1277
1278        // Allow for disabling default components
1279        // e.g. options['children']['posterImage'] = false
1280        if (opts === false) {
1281          return;
1282        }
1283
1284        // Allow options to be passed as a simple boolean if no configuration
1285        // is necessary.
1286        if (opts === true) {
1287          opts = {};
1288        }
1289
1290        // We also want to pass the original player options
1291        // to each component as well so they don't need to
1292        // reach back into the player for options later.
1293        opts.playerOptions = _this.options_.playerOptions;
1294
1295        // Create and add the child component.
1296        // Add a direct reference to the child by name on the parent instance.
1297        // If two of the same component are used, different names should be supplied
1298        // for each
1299        var newChild = _this.addChild(name, opts);
1300
1301        if (newChild) {
1302          _this[name] = newChild;
1303        }
1304      };
1305
1306      // Allow for an array of children details to passed in the options
1307      var workingChildren = void 0;
1308      var Tech = Component.getComponent('Tech');
1309
1310      if (Array.isArray(children)) {
1311        workingChildren = children;
1312      } else {
1313        workingChildren = Object.keys(children);
1314      }
1315
1316      workingChildren
1317      // children that are in this.options_ but also in workingChildren  would
1318      // give us extra children we do not want. So, we want to filter them out.
1319      .concat(Object.keys(this.options_).filter(function (child) {
1320        return !workingChildren.some(function (wchild) {
1321          if (typeof wchild === 'string') {
1322            return child === wchild;
1323          }
1324          return child === wchild.name;
1325        });
1326      })).map(function (child) {
1327        var name = void 0;
1328        var opts = void 0;
1329
1330        if (typeof child === 'string') {
1331          name = child;
1332          opts = children[name] || _this.options_[name] || {};
1333        } else {
1334          name = child.name;
1335          opts = child;
1336        }
1337
1338        return { name: name, opts: opts };
1339      }).filter(function (child) {
1340        // we have to make sure that child.name isn't in the techOrder since
1341        // techs are registerd as Components but can't aren't compatible
1342        // See https://github.com/videojs/video.js/issues/2772
1343        var c = Component.getComponent(child.opts.componentClass || (0, _toTitleCase2['default'])(child.name));
1344
1345        return c && !Tech.isTech(c);
1346      }
1346).forEach(handleAdd);
1347    }
1348  };
1349
1350  /**
1351   * Builds the default DOM class name. Should be overriden by sub-components.
1352   *
1353   * @return {string}
1354   *         The DOM class name for this object.
1355   *
1356   * @abstract
1357   */
1358
1359
1360  Component.prototype.buildCSSClass = function buildCSSClass() {
1361    // Child classes can include a function that does:
1362    // return 'CLASS NAME' + this._super();
1363    return '';
1364  };
1365
1366  /**
1367   * Add an `event listener` to this `Component`s element.
1368   *
1369   * The benefit of using this over the following:
1370   * - `VjsEvents.on(otherElement, 'eventName', myFunc)`
1371   * - `otherComponent.on('eventName', myFunc)`
1372   *
1373   * 1. Is that the listeners will get cleaned up when either component gets disposed.
1374   * 1. It will also bind `myComponent` as the context of `myFunc`.
1375   * > NOTE: If you remove the element from the DOM that has used `on` you need to
1376   *         clean up references using: `myComponent.trigger(el, 'dispose')`
1377   *         This will also allow the browser to garbage collect it. In special
1378   *         cases such as with `window` and `document`, which are both permanent,
1379   *         this is not necessary.
1380   *
1381   * @param {string|Component|string[]} [first]
1382   *        The event name, and array of event names, or another `Component`.
1383   *
1384   * @param {EventTarget~EventListener|string|string[]} [second]
1385   *        The listener function, an event name, or an Array of events names.
1386   *
1387   * @param {EventTarget~EventListener} [third]
1388   *        The event handler if `first` is a `Component` and `second` is an event name
1389   *        or an Array of event names.
1390   *
1391   * @return {Component}
1392   *         Returns itself; method can be chained.
1393   *
1394   * @listens Component#dispose
1395   */
1396
1397
1398  Component.prototype.on = function on(first, second, third) {
1399    var _this2 = this;
1400
1401    if (typeof first === 'string' || Array.isArray(first)) {
1402      Events.on(this.el_, first, Fn.bind(this, second));
1403
1404      // Targeting another component or element
1405    } else {
1406      var target = first;
1407      var type = second;
1408      var fn = Fn.bind(this, third);
1409
1410      // When this component is disposed, remove the listener from the other component
1411      var removeOnDispose = function removeOnDispose() {
1412        return _this2.off(target, type, fn);
1413      };
1414
1415      // Use the same function ID so we can remove it later it using the ID
1416      // of the original listener
1417      removeOnDispose.guid = fn.guid;
1418      this.on('dispose', removeOnDispose);
1419
1420      // If the other component is disposed first we need to clean the reference
1421      // to the other component in this component's removeOnDispose listener
1422      // Otherwise we create a memory leak.
1423      var cleanRemover = function cleanRemover() {
1424        return _this2.off('dispose', removeOnDispose);
1425      };
1426
1427      // Add the same function ID so we can easily remove it later
1428      cleanRemover.guid = fn.guid;
1429
1430      // Check if this is a DOM node
1431      if (first.nodeName) {
1432        // Add the listener to the other element
1433        Events.on(target, type, fn);
1434        Events.on(target, 'dispose', cleanRemover);
1435
1436        // Should be a component
1437        // Not using `instanceof Component` because it makes mock players difficult
1438      } else if (typeof first.on === 'function') {
1439        // Add the listener to the other component
1440        target.on(type, fn);
1441        target.on('dispose', cleanRemover);
1442      }
1443    }
1444
1445    return this;
1446  };
1447
1448  /**
1449   * Remove an event listener from this `Component`s element. If the second argument is
1450   * exluded all listeners for the type passed in as the first argument will be removed.
1451   *
1452   * @param {string|Component|string[]} [first]
1453   *        The event name, and array of event names, or another `Component`.
1454   *
1455   * @param {EventTarget~EventListener|string|string[]} [second]
1456   *        The listener function, an event name, or an Array of events names.
1457   *
1458   * @param {EventTarget~EventListener} [third]
1459   *        The event handler if `first` is a `Component` and `second` is an event name
1460   *        or an Array of event names.
1461   *
1462   * @return {Component}
1463   *         Returns itself; method can be chained.
1464   */
1465
1466
1467  Component.prototype.off = function off(first, second, third) {
1468    if (!first || typeof first === 'string' || Array.isArray(first)) {
1469      Events.off(this.el_, first, second);
1470    } else {
1471      var target = first;
1472      var type = second;
1473      // Ensure there's at least a guid, even if the function hasn't been used
1474      var fn = Fn.bind(this, third);
1475
1476      // Remove the dispose listener on this component,
1477      // which was given the same guid as the event listener
1478      this.off('dispose', fn);
1479
1480      if (first.nodeName) {
1481        // Remove the listener
1482        Events.off(target, type, fn);
1483        // Remove the listener for cleaning the dispose listener
1484        Events.off(target, 'dispose', fn);
1485      } else {
1486        target.off(type, fn);
1487        target.off('dispose', fn);
1488      }
1489    }
1490
1491    return this;
1492  };
1493
1494  /**
1495   * Add an event listener that gets triggered only once and then gets removed.
1496   *
1497   * @param {string|Component|string[]} [first]
1498   *        The event name, and array of event names, or another `Component`.
1499   *
1500   * @param {EventTarget~EventListener|string|string[]} [second]
1501   *        The listener function, an event name, or an Array of events names.
1502   *
1503   * @param {EventTarget~EventListener} [third]
1504   *        The event handler if `first` is a `Component` and `second` is an event name
1505   *        or an Array of event names.
1506   *
1507   * @return {Component}
1508   *         Returns itself; method can be chained.
1509   */
1510
1511
1512  Component.prototype.one = function one(first, second, third) {
1513    var _this3 = this,
1514        _arguments = arguments;
1515
1516    if (typeof first === 'string' || Array.isArray(first)) {
1517      Events.one(this.el_, first, Fn.bind(this, second));
1518    } else {
1519      var target = first;
1520      var type = second;
1521      var fn = Fn.bind(this, third);
1522
1523      var newFunc = function newFunc() {
1524        _this3.off(target, type, newFunc);
1525        fn.apply(null, _arguments);
1526      };
1527
1528      // Keep the same function ID so we can remove it later
1529      newFunc.guid = fn.guid;
1530
1531      this.on(target, type, newFunc);
1532    }
1533
1534    return this;
1535  };
1536
1537  /**
1538   * Trigger an event on an element.
1539   *
1540   * @param {EventTarget~Event|Object|string} event
1541   *        The event name, and Event, or an event-like object with a type attribute
1542   *        set to the event name.
1543   *
1544   * @param {Object} [hash]
1545   *        Data hash to pass along with the event
1546   *
1547   * @return {Component}
1548   *         Returns itself; method can be chained.
1549   */
1550
1551
1552  Component.prototype.trigger = function trigger(event, hash) {
1553    Events.trigger(this.el_, event, hash);
1554    return this;
1555  };
1556
1557  /**
1558   * Bind a listener to the component's ready state. If the ready event has already
1559   * happened it will trigger the function immediately.
1560   *
1561   * @param  {Component~ReadyCallback} fn
1562   *         A function to call when ready is triggered.
1563   *
1564   * @param  {boolean} [sync=false]
1565   *         Execute the listener synchronously if `Component` is ready.
1566   *
1567   * @return {Component}
1568   *         Returns itself; method can be chained.
1569   */
1570
1571
1572  Component.prototype.ready = function ready(fn) {
1573    var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1574
1575    if (fn) {
1576      if (this.isReady_) {
1577        if (sync) {
1578          fn.call(this);
1579        } else {
1580          // Call the function asynchronously by default for consistency
1581          this.setTimeout(fn, 1);
1582        }
1583      } else {
1584        this.readyQueue_ = this.readyQueue_ || [];
1585        this.readyQueue_.push(fn);
1586      }
1587    }
1588    return this;
1589  };
1590
1591  /**
1592   * Trigger all the ready listeners for this `Component`.
1593   *
1594   * @fires Component#ready
1595   */
1596
1597
1598  Component.prototype.triggerReady = function triggerReady() {
1599    this.isReady_ = true;
1600
1601    // Ensure ready is triggerd asynchronously
1602    this.setTimeout(function () {
1603      var readyQueue = this.readyQueue_;
1604
1605      // Reset Ready Queue
1606      this.readyQueue_ = [];
1607
1608      if (readyQueue && readyQueue.length > 0) {
1609        readyQueue.forEach(function (fn) {
1610          fn.call(this);
1611        }, this);
1612      }
1613
1614      // Allow for using event listeners also
1615      /**
1616       * Triggered when a `Component` is ready.
1617       *
1618       * @event Component#ready
1619       * @type {EventTarget~Event}
1620       */
1621      this.trigger('ready');
1622    }, 1);
1623  };
1624
1625  /**
1626   * Find a single DOM element matching a `selector`. This can be within the `Component`s
1627   * `contentEl()` or another custom context.
1628   *
1629   * @param {string} selector
1630   *        A valid CSS selector, which will be passed to `querySelector`.
1631   *
1632   * @param {Element|string} [context=this.contentEl()]
1633   *        A DOM element within which to query. Can also be a selector string in
1634   *        which case the first matching element will get used as context. If
1635   *        missing `this.contentEl()` gets used. If  `this.contentEl()` returns
1636   *        nothing it falls back to `document`.
1637   *
1638   * @return {Element|null}
1639   *         the dom element that was found, or null
1640   *
1641   * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)
1642   */
1643
1644
1645  Component.prototype.$ = function $(selector, context) {
1646    return Dom.$(selector, context || this.contentEl());
1647  };
1648
1649  /**
1650   * Finds all DOM element matching a `selector`. This can be within the `Component`s
1651   * `contentEl()` or another custom context.
1652   *
1653   * @param {string} selector
1654   *        A valid CSS selector, which will be passed to `querySelectorAll`.
1655   *
1656   * @param {Element|string} [context=this.contentEl()]
1657   *        A DOM element within which to query. Can also be a selector string in
1658   *        which case the first matching element will get used as context. If
1659   *        missing `this.contentEl()` gets used. If  `this.contentEl()` returns
1660   *        nothing it falls back to `document`.
1661   *
1662   * @return {NodeList}
1663   *         a list of dom elements that were found
1664   *
1665   * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)
1666   */
1667
1668
1669  Component.prototype.$$ = function $$(selector, context) {
1670    return Dom.$$(selector, context || this.contentEl());
1671  };
1672
1673  /**
1674   * Check if a component's element has a CSS class name.
1675   *
1676   * @param {string} classToCheck
1677   *        CSS class name to check.
1678   *
1679   * @return {boolean}
1680   *         - True if the `Component` has the class.
1681   *         - False if the `Component` does not have the class`
1682   */
1683
1684
1685  Component.prototype.hasClass = function hasClass(classToCheck) {
1686    return Dom.hasElClass(this.el_, classToCheck);
1687  };
1688
1689  /**
1690   * Add a CSS class name to the `Component`s element.
1691   *
1692   * @param {string} classToAdd
1693   *        CSS class name to add
1694   *
1695   * @return {Component}
1696   *         Returns itself; method can be chained.
1697   */
1698
1699
1700  Component.prototype.addClass = function addClass(classToAdd) {
1701    Dom.addElClass(this.el_, classToAdd);
1702    return this;
1703  };
1704
1705  /**
1706   * Remove a CSS class name from the `Component`s element.
1707   *
1708   * @param {string} classToRemove
1709   *        CSS class name to remove
1710   *
1711   * @return {Component}
1712   *         Returns itself; method can be chained.
1713   */
1714
1715
1716  Component.prototype.removeClass = function removeClass(classToRemove) {
1717    Dom.removeElClass(this.el_, classToRemove);
1718    return this;
1719  };
1720
1721  /**
1722   * Add or remove a CSS class name from the component's element.
1723   * - `classToToggle` gets added when {@link Component#hasClass} would return false.
1724   * - `classToToggle` gets removed when {@link Component#hasClass} would return true.
1725   *
1726   * @param  {string} classToToggle
1727   *         The class to add or remove based on (@link Component#hasClass}
1728   *
1729   * @param  {boolean|Dom~predicate} [predicate]
1730   *         An {@link Dom~predicate} function or a boolean
1731   *
1732   * @return {Component}
1733   *         Returns itself; method can be chained.
1734   */
1735
1736
1737  Component.prototype.toggleClass = function toggleClass(classToToggle, predicate) {
1738    Dom.toggleElClass(this.el_, classToToggle, predicate);
1739    return this;
1740  };
1741
1742  /**
1743   * Show the `Component`s element if it is hidden by removing the
1744   * 'vjs-hidden' class name from it.
1745   *
1746   * @return {Component}
1747   *         Returns itself; method can be chained.
1748   */
1749
1750
1751  Component.prototype.show = function show() {
1752    this.removeClass('vjs-hidden');
1753    return this;
1754  };
1755
1756  /**
1757   * Hide the `Component`s element if it is currently showing by adding the
1758   * 'vjs-hidden` class name to it.
1759   *
1760   * @return {Component}
1761   *         Returns itself; method can be chained.
1762   */
1763
1764
1765  Component.prototype.hide = function hide() {
1766    this.addClass('vjs-hidden');
1767    return this;
1768  };
1769
1770  /**
1771   * Lock a `Component`s element in its visible state by adding the 'vjs-lock-showing'
1772   * class name to it. Used during fadeIn/fadeOut.
1773   *
1774   * @return {Component}
1775   *         Returns itself; method can be chained.
1776   *
1777   * @private
1778   */
1779
1780
1781  Component.prototype.lockShowing = function lockShowing() {
1782    this.addClass('vjs-lock-showing');
1783    return this;
1784  };
1785
1786  /**
1787   * Unlock a `Component`s element from its visible state by removing the 'vjs-lock-showing'
1788   * class name from it. Used during fadeIn/fadeOut.
1789   *
1790   * @return {Component}
1791   *         Returns itself; method can be chained.
1792   *
1793   * @private
1794   */
1795
1796
1797  Component.prototype.unlockShowing = function unlockShowing() {
1798    this.removeClass('vjs-lock-showing');
1799    return this;
1800  };
1801
1802  /**
1803   * Get the value of an attribute on the `Component`s element.
1804   *
1805   * @param {string} attribute
1806   *        Name of the attribute to get the value from.
1807   *
1808   * @return {string|null}
1809   *         - The value of the attribute that was asked for.
1810   *         - Can be an empty string on some browsers if the attribute does not exist
1811   *           or has no value
1812   *         - Most browsers will return null if the attibute does not exist or has
1813   *           no value.
1814   *
1815   * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute}
1816   */
1817
1818
1819  Component.prototype.getAttribute = function getAttribute(attribute) {
1820    return Dom.getAttribute(this.el_, attribute);
1821  };
1822
1823  /**
1824   * Set the value of an attribute on the `Component`'s element
1825   *
1826   * @param {string} attribute
1827   *        Name of the attribute to set.
1828   *
1829   * @param {string} value
1830   *        Value to set the attribute to.
1831   *
1832   * @return {Component}
1833   *         Returns itself; method can be chained.
1834   *
1835   * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute}
1836   */
1837
1838
1839  Component.prototype.setAttribute = function setAttribute(attribute, value) {
1840    Dom.setAttribute(this.el_, attribute, value);
1841    return this;
1842  };
1843
1844  /**
1845   * Remove an attribute from the `Component`s element.
1846   *
1847   * @param {string} attribute
1848   *        Name of the attribute to remove.
1849   *
1850   * @return {Component}
1851   *         Returns itself; method can be chained.
1852   *
1853   * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute}
1854   */
1855
1856
1857  Component.prototype.removeAttribute = function removeAttribute(attribute) {
1858    Dom.removeAttribute(this.el_, attribute);
1859    return this;
1860  };
1861
1862  /**
1863   * Get or set the width of the component based upon the CSS styles.
1864   * See {@link Component#dimension} for more detailed information.
1865   *
1866   * @param {number|string} [num]
1867   *        The width that you want to set postfixed with '%', 'px' or nothing.
1868   *
1869   * @param {boolean} [skipListeners]
1870   *        Skip the resize event trigger
1871   *
1872   * @return {Component|number|string}
1873   *         - The width when getting, zero if there is no width. Can be a string
1874   *           postpixed with '%' or 'px'.
1875   *         - Returns itself when setting; method can be chained.
1876   */
1877
1878
1879  Component.prototype.width = function width(num, skipListeners) {
1880    return this.dimension('width', num, skipListeners);
1881  };
1882
1883  /**
1884   * Get or set the height of the component based upon the CSS styles.
1885   * See {@link Component#dimension} for more detailed information.
1886   *
1887   * @param {number|string} [num]
1888   *        The height that you want to set postfixed with '%', 'px' or nothing.
1889   *
1890   * @param {boolean} [skipListeners]
1891   *        Skip the resize event trigger
1892   *
1893   * @return {Component|number|string}
1894   *         - The width when getting, zero if there is no width. Can be a string
1895   *           postpixed with '%' or 'px'.
1896   *         - Returns itself when setting; method can be chained.
1897   */
1898
1899
1900  Component.prototype.height = function height(num, skipListeners) {
1901    return this.dimension('height', num, skipListeners);
1902  };
1903
1904  /**
1905   * Set both the width and height of the `Component` element at the same time.
1906   *
1907   * @param  {number|string} width
1908   *         Width to set the `Component`s element to.
1909   *
1910   * @param  {number|string} height
1911   *         Height to set the `Component`s element to.
1912   *
1913   * @return {Component}
1914   *         Returns itself; method can be chained.
1915   */
1916
1917
1918  Component.prototype.dimensions = function dimensions(width, height) {
1919    // Skip resize listeners on width for optimization
1920    return this.width(width, true).height(height);
1921  };
1922
1923  /**
1924   * Get or set width or height of the `Component` element. This is the shared code
1925   * for the {@link Component#width} and {@link Component#height}.
1926   *
1927   * Things to know:
1928   * - If the width or height in an number this will return the number postfixed with 'px'.
1929   * - If the width/height is a percent this will return the percent postfixed with '%'
1930   * - Hidden elements have a width of 0 with `window.getComputedStyle`. This function
1931   *   defaults to the `Component`s `style.width` and falls back to `window.getComputedStyle`.
1932   *   See [this]{@link http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-u
1932sing-width/}
1933   *   for more information
1934   * - If you want the computed style of the component, use {@link Component#currentWidth}
1935   *   and {@link {Component#currentHeight}
1936   *
1937   * @fires Component#resize
1938   *
1939   * @param {string} widthOrHeight
1940   8        'width' or 'height'
1941   *
1942   * @param  {number|string} [num]
1943   8         New dimension
1944   *
1945   * @param  {boolean} [skipListeners]
1946   *         Skip resize event trigger
1947   *
1948   * @return {Component}
1949   *         - the dimension when getting or 0 if unset
1950   *         - Returns itself when setting; method can be chained.
1951   */
1952
1953
1954  Component.prototype.dimension = function dimension(widthOrHeight, num, skipListeners) {
1955    if (num !== undefined) {
1956      // Set to zero if null or literally NaN (NaN !== NaN)
1957      if (num === null || num !== num) {
1958        num = 0;
1959      }
1960
1961      // Check if using css width/height (% or px) and adjust
1962      if (('' + num).indexOf('%') !== -1 || ('' + num).indexOf('px') !== -1) {
1963        this.el_.style[widthOrHeight] = num;
1964      } else if (num === 'auto') {
1965        this.el_.style[widthOrHeight] = '';
1966      } else {
1967        this.el_.style[widthOrHeight] = num + 'px';
1968      }
1969
1970      // skipListeners allows us to avoid triggering the resize event when setting both width and height
1971      if (!skipListeners) {
1972        /**
1973         * Triggered when a component is resized.
1974         *
1975         * @event Component#resize
1976         * @type {EventTarget~Event}
1977         */
1978        this.trigger('resize');
1979      }
1980
1981      // Return component
1982      return this;
1983    }
1984
1985    // Not setting a value, so getting it
1986    // Make sure element exists
1987    if (!this.el_) {
1988      return 0;
1989    }
1990
1991    // Get dimension value from style
1992    var val = this.el_.style[widthOrHeight];
1993    var pxIndex = val.indexOf('px');
1994
1995    if (pxIndex !== -1) {
1996      // Return the pixel value with no 'px'
1997      return parseInt(val.slice(0, pxIndex), 10);
1998    }
1999
2000    // No px so using % or no style was set, so falling back to offsetWidth/height
2001    // If component has display:none, offset will return 0
2002    // TODO: handle display:none and no dimension style using px
2003    return parseInt(this.el_['offset' + (0, _toTitleCase2['default'])(widthOrHeight)], 10);
2004  };
2005
2006  /**
2007   * Get the width or the height of the `Component` elements computed style. Uses
2008   * `window.getComputedStyle`.
2009   *
2010   * @param {string} widthOrHeight
2011   *        A string containing 'width' or 'height'. Whichever one you want to get.
2012   *
2013   * @return {number}
2014   *         The dimension that gets asked for or 0 if nothing was set
2015   *         for that dimension.
2016   */
2017
2018
2019  Component.prototype.currentDimension = function currentDimension(widthOrHeight) {
2020    var computedWidthOrHeight = 0;
2021
2022    if (widthOrHeight !== 'width' && widthOrHeight !== 'height') {
2023      throw new Error('currentDimension only accepts width or height value');
2024    }
2025
2026    if (typeof _window2['default'].getComputedStyle === 'function') {
2027      var computedStyle = _window2['default'].getComputedStyle(this.el_);
2028
2029      computedWidthOrHeight = computedStyle.getPropertyValue(widthOrHeight) || computedStyle[widthOrHeight];
2030    }
2031
2032    // remove 'px' from variable and parse as integer
2033    computedWidthOrHeight = parseFloat(computedWidthOrHeight);
2034
2035    // if the computed value is still 0, it's possible that the browser is lying
2036    // and we want to check the offset values.
2037    // This code also runs on IE8 and wherever getComputedStyle doesn't exist.
2038    if (computedWidthOrHeight === 0) {
2039      var rule = 'offset' + (0, _toTitleCase2['default'])(widthOrHeight);
2040
2041      computedWidthOrHeight = this.el_[rule];
2042    }
2043
2044    return computedWidthOrHeight;
2045  };
2046
2047  /**
2048   * An object that contains width and height values of the `Component`s
2049   * computed style. Uses `window.getComputedStyle`.
2050   *
2051   * @typedef {Object} Component~DimensionObject
2052   *
2053   * @property {number} width
2054   *           The width of the `Component`s computed style.
2055   *
2056   * @property {number} height
2057   *           The height of the `Component`s computed style.
2058   */
2059
2060  /**
2061   * Get an object that contains width and height values of the `Component`s
2062   * computed style.
2063   *
2064   * @return {Component~DimensionObject}
2065   *         The dimensions of the components element
2066   */
2067
2068
2069  Component.prototype.currentDimensions = function currentDimensions() {
2070    return {
2071      width: this.currentDimension('width'),
2072      height: this.currentDimension('height')
2073    };
2074  };
2075
2076  /**
2077   * Get the width of the `Component`s computed style. Uses `window.getComputedStyle`.
2078   *
2079   * @return {number} width
2080   *           The width of the `Component`s computed style.
2081   */
2082
2083
2084  Component.prototype.currentWidth = function currentWidth() {
2085    return this.currentDimension('width');
2086  };
2087
2088  /**
2089   * Get the height of the `Component`s computed style. Uses `window.getComputedStyle`.
2090   *
2091   * @return {number} height
2092   *           The height of the `Component`s computed style.
2093   */
2094
2095
2096  Component.prototype.currentHeight = function currentHeight() {
2097    return this.currentDimension('height');
2098  };
2099
2100  /**
2101   * Set the focus to this component
2102   */
2103
2104
vendor: 9,394 bytes, lines 2105-2365
2105  Component.prototype.focus = function focus() {
2106    this.el_.focus();
2107  };
2108
2109  /**
2110   * Remove the focus from this component
2111   */
2112
2113
2114  Component.prototype.blur = function blur() {
2115    this.el_.blur();
2116  };
2117
2118  /**
2119   * Emit a 'tap' events when touch event support gets detected. This gets used to
2120   * support toggling the controls through a tap on the video. They get enabled
2121   * because every sub-component would have extra overhead otherwise.
2122   *
2123   * @private
2124   * @fires Component#tap
2125   * @listens Component#touchstart
2126   * @listens Component#touchmove
2127   * @listens Component#touchleave
2128   * @listens Component#touchcancel
2129   * @listens Component#touchend
2130    */
2131
2132
2133  Component.prototype.emitTapEvents = function emitTapEvents() {
2134    // Track the start time so we can determine how long the touch lasted
2135    var touchStart = 0;
2136    var firstTouch = null;
2137
2138    // Maximum movement allowed during a touch event to still be considered a tap
2139    // Other popular libs use anywhere from 2 (hammer.js) to 15,
2140    // so 10 seems like a nice, round number.
2141    var tapMovementThreshold = 10;
2142
2143    // The maximum length a touch can be while still being considered a tap
2144    var touchTimeThreshold = 200;
2145
2146    var couldBeTap = void 0;
2147
2148    this.on('touchstart', function (event) {
2149      // If more than one finger, don't consider treating this as a click
2150      if (event.touches.length === 1) {
2151        // Copy pageX/pageY from the object
2152        firstTouch = {
2153          pageX: event.touches[0].pageX,
2154          pageY: event.touches[0].pageY
2155        };
2156        // Record start time so we can detect a tap vs. "touch and hold"
2157        touchStart = new Date().getTime();
2158        // Reset couldBeTap tracking
2159        couldBeTap = true;
2160      }
2161    });
2162
2163    this.on('touchmove', function (event) {
2164      // If more than one finger, don't consider treating this as a click
2165      if (event.touches.length > 1) {
2166        couldBeTap = false;
2167      } else if (firstTouch) {
2168        // Some devices will throw touchmoves for all but the slightest of taps.
2169        // So, if we moved only a small distance, this could still be a tap
2170        var xdiff = event.touches[0].pageX - firstTouch.pageX;
2171        var ydiff = event.touches[0].pageY - firstTouch.pageY;
2172        var touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
2173
2174        if (touchDistance > tapMovementThreshold) {
2175          couldBeTap = false;
2176        }
2177      }
2178    });
2179
2180    var noTap = function noTap() {
2181      couldBeTap = false;
2182    };
2183
2184    // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s
2185    this.on('touchleave', noTap);
2186    this.on('touchcancel', noTap);
2187
2188    // When the touch ends, measure how long it took and trigger the appropriate
2189    // event
2190    this.on('touchend', function (event) {
2191      firstTouch = null;
2192      // Proceed only if the touchmove/leave/cancel event didn't happen
2193      if (couldBeTap === true) {
2194        // Measure how long the touch lasted
2195        var touchTime = new Date().getTime() - touchStart;
2196
2197        // Make sure the touch was less than the threshold to be considered a tap
2198        if (touchTime < touchTimeThreshold) {
2199          // Don't let browser turn this into a click
2200          event.preventDefault();
2201          /**
2202           * Triggered when a `Component` is tapped.
2203           *
2204           * @event Component#tap
2205           * @type {EventTarget~Event}
2206           */
2207          this.trigger('tap');
2208          // It may be good to copy the touchend event object and change the
2209          // type to tap, if the other event properties aren't exact after
2210          // Events.fixEvent runs (e.g. event.target)
2211        }
2212      }
2213    });
2214  };
2215
2216  /**
2217   * This function reports user activity whenever touch events happen. This can get
2218   * turned off by any sub-components that wants touch events to act another way.
2219   *
2220   * Report user touch activity when touch events occur. User activity gets used to
2221   * determine when controls should show/hide. It is simple when it comes to mouse
2222   * events, because any mouse event should show the controls. So we capture mouse
2223   * events that bubble up to the player and report activity when that happens.
2224   * With touch events it isn't as easy as `touchstart` and `touchend` toggle player
2225   * controls. So touch events can't help us at the player level either.
2226   *
2227   * User activity gets checked asynchronously. So what could happen is a tap event
2228   * on the video turns the controls off. Then the `touchend` event bubbles up to
2229   * the player. Which, if it reported user activity, would turn the controls right
2230   * back on. We also don't want to completely block touch events from bubbling up.
2231   * Furthermore a `touchmove` event and anything other than a tap, should not turn
2232   * controls back on.
2233   *
2234   * @listens Component#touchstart
2235   * @listens Component#touchmove
2236   * @listens Component#touchend
2237   * @listens Component#touchcancel
2238   */
2239
2240
2241  Component.prototype.enableTouchActivity = function enableTouchActivity() {
2242    // Don't continue if the root player doesn't support reporting user activity
2243    if (!this.player() || !this.player().reportUserActivity) {
2244      return;
2245    }
2246
2247    // listener for reporting that the user is active
2248    var report = Fn.bind(this.player(), this.player().reportUserActivity);
2249
2250    var touchHolding = void 0;
2251
2252    this.on('touchstart', function () {
2253      report();
2254      // For as long as the they are touching the device or have their mouse down,
2255      // we consider them active even if they're not moving their finger or mouse.
2256      // So we want to continue to update that they are active
2257      this.clearInterval(touchHolding);
2258      // report at the same interval as activityCheck
2259      touchHolding = this.setInterval(report, 250);
2260    });
2261
2262    var touchEnd = function touchEnd(event) {
2263      report();
2264      // stop the interval that maintains activity if the touch is holding
2265      this.clearInterval(touchHolding);
2266    };
2267
2268    this.on('touchmove', report);
2269    this.on('touchend', touchEnd);
2270    this.on('touchcancel', touchEnd);
2271  };
2272
2273  /**
2274   * A callback that has no parameters and is bound into `Component`s context.
2275   *
2276   * @callback Component~GenericCallback
2277   * @this Component
2278   */
2279
2280  /**
2281   * Creates a function that runs after an `x` millisecond timeout. This function is a
2282   * wrapper around `window.setTimeout`. There are a few reasons to use this one
2283   * instead though:
2284   * 1. It gets cleared via  {@link Component#clearTimeout} when
2285   *    {@link Component#dispose} gets called.
2286   * 2. The function callback will gets turned into a {@link Component~GenericCallback}
2287   *
2288   * > Note: You can use `window.clearTimeout` on the id returned by this function. This
2289   *         will cause its dispose listener not to get cleaned up! Please use
2290   *         {@link Component#clearTimeout} or {@link Component#dispose}.
2291   *
2292   * @param {Component~GenericCallback} fn
2293   *        The function that will be run after `timeout`.
2294   *
2295   * @param {number} timeout
2296   *        Timeout in milliseconds to delay before executing the specified function.
2297   *
2298   * @return {number}
2299   *         Returns a timeout ID that gets used to identify the timeout. It can also
2300   *         get used in {@link Component#clearTimeout} to clear the timeout that
2301   *         was set.
2302   *
2303   * @listens Component#dispose
2304   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout}
2305   */
2306
2307
2308  Component.prototype.setTimeout = function setTimeout(fn, timeout) {
2309    fn = Fn.bind(this, fn);
2310
2311    var timeoutId = _window2['default'].setTimeout(fn, timeout);
2312    var disposeFn = function disposeFn() {
2313      this.clearTimeout(timeoutId);
2314    };
2315
2316    disposeFn.guid = 'vjs-timeout-' + timeoutId;
2317
2318    this.on('dispose', disposeFn);
2319
2320    return timeoutId;
2321  };
2322
2323  /**
2324   * Clears a timeout that gets created via `window.setTimeout` or
2325   * {@link Component#setTimeout}. If you set a timeout via {@link Component#setTimeout}
2326   * use this function instead of `window.clearTimout`. If you don't your dispose
2327   * listener will not get cleaned up until {@link Component#dispose}!
2328   *
2329   * @param {number} timeoutId
2330   *        The id of the timeout to clear. The return value of
2331   *        {@link Component#setTimeout} or `window.setTimeout`.
2332   *
2333   * @return {number}
2334   *         Returns the timeout id that was cleared.
2335   *
2336   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout}
2337   */
2338
2339
2340  Component.prototype.clearTimeout = function clearTimeout(timeoutId) {
2341    _window2['default'].clearTimeout(timeoutId);
2342
2343    var disposeFn = function disposeFn() {};
2344
2345    disposeFn.guid = 'vjs-timeout-' + timeoutId;
2346
2347    this.off('dispose', disposeFn);
2348
2349    return timeoutId;
2350  };
2351
2352  /**
2353   * Creates a function that gets run every `x` milliseconds. This function is a wrapper
2354   * around `window.setInterval`. There are a few reasons to use this one instead though.
2355   * 1. It gets cleared via  {@link Component#clearInterval} when
2356   *    {@link Component#dispose} gets called.
2357   * 2. The function callback will be a {@link Component~GenericCallback}
2358   *
2359   * @param {Component~GenericCallback} fn
2360   *        The function to run every `x` seconds.
2361   *
2362   * @param {number} interval
2363   *        Execute the specified function every `x` milliseconds.
2364   *
2365   * @return {number}
2366   *         Returns an id that can be used to identify the interval. It can also be be used in
2367   *         {@link Component#clearInterval} to clear the interval.
2368   *
2369   * @listens Component#dispose
2370   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval}
2371   */
2372
2373
2374  Component.prototype.setInterval = function setInterval(fn, interval) {
2375    fn = Fn.bind(this, fn);
2376
2377    var intervalId = _window2['default'].setInterval(fn, interval);
2378
2379    var disposeFn = function disposeFn() {
2380      this.clearInterval(intervalId);
2381    };
2382
2383    disposeFn.guid = 'vjs-interval-' + intervalId;
2384
2385    this.on('dispose', disposeFn);
2386
2387    return intervalId;
2388  };
2389
2390  /**
2391   * Clears an interval that gets created via `window.setInterval` or
2392   * {@link Component#setInterval}. If you set an inteval via {@link Component#setInterval}
2393   * use this function instead of `window.clearInterval`. If you don't your dispose
2394   * listener will not get cleaned up until {@link Component#dispose}!
2395   *
2396   * @param {number} intervalId
2397   *        The id of the interval to clear. The return value of
2398   *        {@link Component#setInterval} or `window.setInterval`.
2399   *
2400   * @return {number}
2401   *         Returns the interval id that was cleared.
2402   *
2403   * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval}
2404   */
2405
2406
2407  Component.prototype.clearInterval = function clearInterval(intervalId) {
2408    _window2['default'].clearInterval(intervalId);
2409
2410    var disposeFn = function disposeFn() {};
2411
2412    disposeFn.guid = 'vjs-interval-' + intervalId;
2413
2414    this.off('dispose', disposeFn);
2415
2416    return intervalId;
2417  };
2418
2419  /**
2420   * Register a `Component` with `videojs` given the name and the component.
2421   *
2422   * > NOTE: {@link Tech}s should not be registered as a `Component`. {@link Tech}s
2423   *         should be registered using {@link Tech.registerTech} or
2424   *         {@link videojs:videojs.registerTech}.
2425   *
2426   * > NOTE: This function can also be seen on videojs as
2427   *         {@link videojs:videojs.registerComponent}.
2428   *
2429   * @param {string} name
2430   *        The name of the `Component` to register.
2431   *
2432   * @param {Component} comp
2433   *        The `Component` class to register.
2434   *
2435   * @return {Component}
2436   *         The `Component` that was registered.
2437   */
2438
2439
2440  Component.registerComponent = function registerComponent(name, comp) {
2441    if (!name) {
2442      return;
2443    }
2444
2445    name = (0, _toTitleCase2['default'])(name);
2446
2447    if (!Component.components_) {
2448      Component.components_ = {};
2449    }
2450
2451    if (name === 'Player' && Component.components_[name]) {
2452      var Player = Component.components_[name];
2453
2454      // If we have players that were disposed, then their name will still be
2455      // in Players.players. So, we must loop through and verify that the value
2456      // for each item is not null. This allows registration of the Player component
2457      // after all players have been disposed or before any were created.
2458      if (Player.players && Object.keys(Player.players).length > 0 && Object.keys(Player.players).map(function (playerName) {
2459        return Player.players[playerName];
2460      }).every(Boolean)) {
2461        throw new Error('Can not register Player component after player has been created');
2462      }
2463    }
2464
2465    Component.components_[name] = comp;
2466
2467    return comp;
2468  };
2469
2470  /**
2471   * Get a `Component` based on the name it was registered with.
2472   *
2473   * @param {string} name
2474   *        The Name of the component to get.
2475   *
2476   * @return {Component}
2477   *         The `Component` that got registered under the given name.
2478   *
2479   * @deprecated In `videojs` 6 this will not return `Component`s that were not
2480   *             registered using {@link Component.registerComponent}. Currently we
2481   *             check the global `videojs` object for a `Component` name and
2482   *             return that if it exists.
2483   */
2484
2485
2486  Component.getComponent = function getComponent(name) {
2487    if (!name) {
2488      return;
2489    }
2490
2491    name = (0, _toTitleCase2['default'])(name);
2492
2493    if (Component.components_ && Component.components_[name]) {
2494      return Component.components_[name];
2495    }
2496
2497    if (_window2['default'] && _window2['default'].videojs && _window2['default'].videojs[name]) {
2498      _log2['default'].warn('The ' + name + ' component was added to the videojs object when it should be registered using videojs.registerComponent(name, component)');
2499
2500      return _window2['default'].videojs[name];
2501    }
2502  };
2503
2504  /**
2505   * Sets up the constructor using the supplied init method or uses the init of the
2506   * parent object.
2507   *
2508   * @param {Object} [props={}]
2509   *        An object of properties.
2510   *
2511   * @return {Object}
2512   *         the extended object.
2513   *
2514   * @deprecated since version 5
2515   */
2516
2517
2518  Component.extend = function extend(props) {
2519    props = props || {};
2520
2521    _log2['default'].warn('Component.extend({}) has been deprecated, ' + ' use videojs.extend(Component, {}) instead');
2522
2523    // Set up the constructor using the supplied init method
2524    // or using the init of the parent object
2525    // Make sure to check the unobfuscated version for external libs
2526    var init = props.init || props.init || this.prototype.init || this.prototype.init || function () {};
2527    // In Resig's simple class inheritance (previously used) the constructor
2528    //  is a function that calls `this.init.apply(arguments)`
2529    // However that would prevent us from using `ParentObject.call(this);`
2530    //  in a Child constructor because the `this` in `this.init`
2531    //  would still refer to the Child and cause an infinite loop.
2532    // We would instead have to do
2533    //    `ParentObject.prototype.init.apply(this, arguments);`
2534    //  Bleh. We're not creating a _super() function, so it's good to keep
2535    //  the parent constructor reference simple.
2536    var subObj = function subObj() {
2537      init.apply(this, arguments);
2538    };
2539
2540    // Inherit from this object's prototype
2541    subObj.prototype = Object.create(this.prototype);
2542    // Reset the constructor property for subObj otherwise
2543    // instances of subObj would have the constructor of the parent Object
2544    subObj.prototype.constructor = subObj;
2545
2546    // Make the class extendable
2547    subObj.extend = Component.extend;
2548
2549    // Extend subObj's prototype with functions and other properties from props
2550    for (var name in props) {
2551      if (props.hasOwnProperty(name)) {
2552        subObj.prototype[name] = props[name];
2553      }
2554    }
2555
2556    return subObj;
2557  };
2558
2559  return Component;
2560}();
2561
2562Component.registerComponent('Component', Component);
2563exports['default'] = Component;
2564
2565},{"81":81,"82":82,"83":83,"85":85,"86":86,"87":87,"91":91,"95":95}],6:[function(_dereq_,module,exports){
2566'use strict';
2567
2568exports.__esModule = true;
2569
2570var _trackButton = _dereq_(36);
2571
2572var _trackButton2 = _interopRequireDefault(_trackButton);
2573
2574var _component = _dereq_(5);
2575
2576var _component2 = _interopRequireDefault(_component);
2577
2578var _audioTrackMenuItem = _dereq_(7);
2579
2580var _audioTrackMenuItem2 = _interopRequireDefault(_audioTrackMenuItem);
2581
2582function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
2583
2584function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2585
2586function _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; }
2587
2588function _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; } /**
2589                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file audio-track-button.js
2590                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
2591
2592
2593/**
2594 * The base class for buttons that toggle specific {@link AudioTrack} types.
2595 *
2596 * @extends TrackButton
2597 */
2598var AudioTrackButton = function (_TrackButton) {
2599  _inherits(AudioTrackButton, _TrackButton);
2600
2601  /**
2602   * Creates an instance of this class.
2603   *
2604   * @param {Player} player
2605   *        The `Player` that this class should be attached to.
2606   *
2607   * @param {Object} [options={}]
2608   *        The key/value store of player options.
2609   */
2610  function AudioTrackButton(player) {
2611    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
2612
2613    _classCallCheck(this, AudioTrackButton);
2614
2615    options.tracks = player.audioTracks && player.audioTracks();
2616
2617    var _this = _possibleConstructorReturn(this, _TrackButton.call(this, player, options));
2618
2619    _this.el_.setAttribute('aria-label', 'Audio Menu');
2620    return _this;
2621  }
2622
2623  /**
2624   * Builds the default DOM `className`.
2625   *
2626   * @return {string}
2627   *         The DOM `className` for this object.
2628   */
2629
2630
2631  AudioTrackButton.prototype.buildCSSClass = function buildCSSClass() {
2632    return 'vjs-audio-button ' + _TrackButton.prototype.buildCSSClass.call(this);
2633  };
2634
2635  /**
2636   * Create a menu item for each audio track
2637   *
2638   * @param {AudioTrackMenuItem[]} [items=[]]
2639   *        An array of existing menu items to use.
2640   *
2641   * @return {AudioTrackMenuItem[]}
2642   *         An array of menu items
2643   */
2644
2645
2646  AudioTrackButton.prototype.createItems = function createItems() {
2647    var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
2648
2649    // if there's only one audio track, there no point in showing it
2650    this.hideThreshold_ = 1;
2651
2652    var tracks = this.player_.audioTracks && this.player_.audioTracks();
2653
2654    if (!tracks) {
2655      return items;
2656    }
2657
2658    for (var i = 0; i < tracks.length; i++) {
2659      var track = tracks[i];
2660
2661      items.push(new _audioTrackMenuItem2['default'](this.player_, {
2662        track: track,
2663        // MenuItem is selectable
2664        selectable: true
2665      }));
2666    }
2667
2668    return items;
2669  };
2670
2671  return AudioTrackButton;
2672}(_trackButton2['default']);
2673
2674/**
2675 * The text that should display over the `AudioTrackButton`s controls. Added for localization.
2676 *
2677 * @type {string}
2678 * @private
2679 */
2680
2681
2682AudioTrackButton.prototype.controlText_ = 'Audio Track';
2683_component2['default'].registerComponent('AudioTrackButton', AudioTrackButton);
2684exports['default'] = AudioTrackButton;
2685
2686},{"36":36,"5":5,"7":7}],7:[function(_dereq_,module,exports){
2687'use strict';
2688
2689exports.__esModule = true;
2690
2691var _menuItem = _dereq_(48);
2692
2693var _menuItem2 = _interopRequireDefault(_menuItem);
2694
2695var _component = _dereq_(5);
2696
2697var _component2 = _interopRequireDefault(_component);
2698
2699var _fn = _dereq_(83);
2700
2701var Fn = _interopRequireWildcard(_fn);
2702
2703function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
2704
2705function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
2706
2707function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2708
2709function _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; }
2710
2711function _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, { c
2711onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
2712                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file audio-track-menu-item.js
2713                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
2714
2715
2716/**
2717 * An {@link AudioTrack} {@link MenuItem}
2718 *
2719 * @extends MenuItem
2720 */
2721var AudioTrackMenuItem = function (_MenuItem) {
2722  _inherits(AudioTrackMenuItem, _MenuItem);
2723
2724  /**
2725   * Creates an instance of this class.
2726   *
2727   * @param {Player} player
2728   *        The `Player` that this class should be attached to.
2729   *
2730   * @param {Object} [options]
2731   *        The key/value store of player options.
2732   */
2733  function AudioTrackMenuItem(player, options) {
2734    _classCallCheck(this, AudioTrackMenuItem);
2735
2736    var track = options.track;
2737    var tracks = player.audioTracks();
2738
2739    // Modify options for parent MenuItem class's init.
2740    options.label = track.label || track.language || 'Unknown';
2741    options.selected = track.enabled;
2742
2743    var _this = _possibleConstructorReturn(this, _MenuItem.call(this, player, options));
2744
2745    _this.track = track;
2746
2747    if (tracks) {
2748      var changeHandler = Fn.bind(_this, _this.handleTracksChange);
2749
2750      tracks.addEventListener('change', changeHandler);
2751      _this.on('dispose', function () {
2752        tracks.removeEventListener('change', changeHandler);
2753      });
2754    }
2755    return _this;
2756  }
2757
2758  /**
2759   * This gets called when an `AudioTrackMenuItem is "clicked". See {@link ClickableComponent}
2760   * for more detailed information on what a click can be.
2761   *
2762   * @param {EventTarget~Event} [event]
2763   *        The `keydown`, `tap`, or `click` event that caused this function to be
2764   *        called.
2765   *
2766   * @listens tap
2767   * @listens click
2768   */
2769
2770
2771  AudioTrackMenuItem.prototype.handleClick = function handleClick(event) {
2772    var tracks = this.player_.audioTracks();
2773
2774    _MenuItem.prototype.handleClick.call(this, event);
2775
2776    if (!tracks) {
2777      return;
2778    }
2779
2780    for (var i = 0; i < tracks.length; i++) {
2781      var track = tracks[i];
2782
2783      track.enabled = track === this.track;
2784    }
2785  };
2786
2787  /**
2788   * Handle any {@link AudioTrack} change.
2789   *
2790   * @param {EventTarget~Event} [event]
2791   *        The {@link AudioTrackList#change} event that caused this to run.
2792   *
2793   * @listens AudioTrackList#change
2794   */
2795
2796
2797  AudioTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) {
2798    this.selected(this.track.enabled);
2799  };
2800
2801  return AudioTrackMenuItem;
2802}(_menuItem2['default']);
2803
2804_component2['default'].registerComponent('AudioTrackMenuItem', AudioTrackMenuItem);
2805exports['default'] = AudioTrackMenuItem;
2806
2807},{"48":48,"5":5,"83":83}],8:[function(_dereq_,module,exports){
2808'use strict';
2809
2810exports.__esModule = true;
2811
2812var _component = _dereq_(5);
2813
2814var _component2 = _interopRequireDefault(_component);
2815
2816_dereq_(12);
2817
2818_dereq_(32);
2819
2820_dereq_(33);
2821
2822_dereq_(35);
2823
2824_dereq_(34);
2825
2826_dereq_(10);
2827
2828_dereq_(18);
2829
2830_dereq_(9);
2831
2832_dereq_(38);
2833
2834_dereq_(40);
2835
2836_dereq_(11);
2837
2838_dereq_(25);
2839
2840_dereq_(27);
2841
2842_dereq_(29);
2843
2844_dereq_(24);
2845
2846_dereq_(6);
2847
2848_dereq_(13);
2849
2850_dereq_(21);
2851
2852function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
2853
2854function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2855
2856function _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; }
2857
2858function _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, { c
2858onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
2859                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file control-bar.js
2860                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
2861
2862
2863// Required children
2864
2865
2866/**
2867 * Container of main controls.
2868 *
2869 * @extends Component
2870 */
2871var ControlBar = function (_Component) {
2872  _inherits(ControlBar, _Component);
2873
2874  function ControlBar() {
2875    _classCallCheck(this, ControlBar);
2876
2877    return _possibleConstructorReturn(this, _Component.apply(this, arguments));
2878  }
2879
2880  /**
2881   * Create the `Component`'s DOM element
2882   *
2883   * @return {Element}
2884   *         The element that was created.
2885   */
2886  ControlBar.prototype.createEl = function createEl() {
2887    return _Component.prototype.createEl.call(this, 'div', {
2888      className: 'vjs-control-bar',
2889      dir: 'ltr'
2890    }, {
2891      // The control bar is a group, so it can contain menuitems
2892      role: 'group'
2893    });
2894  };
2895
2896  return ControlBar;
2897}(_component2['default']);
2898
2899/**
2900 * Default options for `ControlBar`
2901 *
2902 * @type {Object}
2903 * @private
2904 */
2905
2906
2907ControlBar.prototype.options_ = {
2908  children: ['playToggle', 'volumeMenuButton', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'descriptionsButton', 'subtitlesButton', 'captionsButton', 'audioTrackButton', 'fullscreenToggle']
2909};
2910
2911_component2['default'].registerComponent('ControlBar', ControlBar);
2912exports['default'] = ControlBar;
2913
2914},{"10":10,"11":11,"12":12,"13":13,"18":18,"21":21,"24":24,"25":25,"27":27,"29":29,"32":32,"33":33,"34":34,"35":35,"38":38,"40":40,"5":5,"6":6,"9":9}],9:[function(_dereq_,module,exports){
2915'use strict';
2916
2917exports.__esModule = true;
2918
2919var _button = _dereq_(2);
2920
2921var _button2 = _interopRequireDefault(_button);
2922
2923var _component = _dereq_(5);
2924
2925var _component2 = _interopRequireDefault(_component);
2926
2927function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
2928
2929function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2930
2931function _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; }
2932
2933function _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; } /**
2934                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file fullscreen-toggle.js
2935                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
2936
2937
2938/**
2939 * Toggle fullscreen video
2940 *
2941 * @extends Button
2942 */
2943var FullscreenToggle = function (_Button) {
2944  _inherits(FullscreenToggle, _Button);
2945
2946  /**
2947   * Creates an instance of this class.
2948   *
2949   * @param {Player} player
2950   *        The `Player` that this class should be attached to.
2951   *
2952   * @param {Object} [options]
2953   *        The key/value store of player options.
2954   */
2955  function FullscreenToggle(player, options) {
2956    _classCallCheck(this, FullscreenToggle);
2957
2958    var _this = _possibleConstructorReturn(this, _Button.call(this, player, options));
2959
2960    _this.on(player, 'fullscreenchange', _this.handleFullscreenChange);
2961    return _this;
2962  }
2963
2964  /**
2965   * Builds the default DOM `className`.
2966   *
2967   * @return {string}
2968   *         The DOM `className` for this object.
2969   */
2970
2971
2972  FullscreenToggle.prototype.buildCSSClass = function buildCSSClass() {
2973    return 'vjs-fullscreen-control ' + _Button.prototype.buildCSSClass.call(this);
2974  };
2975
2976  /**
2977   * Handles fullscreenchange on the player and change control text accordingly.
2978   *
2979   * @param {EventTarget~Event} [event]
2980   *        The {@link Player#fullscreenchange} event that caused this function to be
2981   *        called.
2982   *
2983   * @listens Player#fullscreenchange
2984   */
2985
2986
2987  FullscreenToggle.prototype.handleFullscreenChange = function handleFullscreenChange(event) {
2988    if (this.player_.isFullscreen()) {
2989      this.controlText('Non-Fullscreen');
2990    } else {
2991      this.controlText('Fullscreen');
2992    }
2993  };
2994
2995  /**
2996   * This gets called when an `FullscreenToggle` is "clicked". See
2997   * {@link ClickableComponent} for more detailed information on what a click can be.
2998   *
2999   * @param {EventTarget~Event} [event]
3000   *        The `keydown`, `tap`, or `click` event that caused this function to be
3001   *        called.
3002   *
3003   * @listens tap
3004   * @listens click
3005   */
3006
3007
3008  FullscreenToggle.prototype.handleClick = function handleClick(event) {
3009    if (!this.player_.isFullscreen()) {
3010      this.player_.requestFullscreen();
3011    } else {
3012      this.player_.exitFullscreen();
3013    }
3014  };
3015
3016  return FullscreenToggle;
3017}(_button2['default']);
3018
3019/**
3020 * The text that should display over the `FullscreenToggle`s controls. Added for localization.
3021 *
3022 * @type {string}
3023 * @private
3024 */
3025
3026
3027FullscreenToggle.prototype.controlText_ = 'Fullscreen';
3028
3029_component2['default'].registerComponent('FullscreenToggle', FullscreenToggle);
3030exports['default'] = FullscreenToggle;
3031
3032},{"2":2,"5":5}],10:[function(_dereq_,module,exports){
3033'use strict';
3034
3035exports.__esModule = true;
3036
3037var _component = _dereq_(5);
3038
3039var _component2 = _interopRequireDefault(_component);
3040
3041var _dom = _dereq_(81);
3042
3043var Dom = _interopRequireWildcard(_dom);
3044
3045function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
3046
3047function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
3048
3049function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
3050
3051function _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; }
3052
3053function _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; } /**
3054                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file live-display.js
3055                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
3056
3057
3058// TODO - Future make it click to snap to live
3059
3060/**
3061 * Displays the live indicator when duration is Infinity.
3062 *
3063 * @extends Component
3064 */
3065var LiveDisplay = function (_Component) {
3066  _inherits(LiveDisplay, _Component);
3067
3068  /**
3069   * Creates an instance of this class.
3070   *
3071   * @param {Player} player
3072   *        The `Player` that this class should be attached to.
3073   *
3074   * @param {Object} [options]
3075   *        The key/value store of player options.
3076   */
3077  function LiveDisplay(player, options) {
3078    _classCallCheck(this, LiveDisplay);
3079
3080    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
3081
3082    _this.updateShowing();
3083    _this.on(_this.player(), 'durationchange', _this.updateShowing);
3084    return _this;
3085  }
3086
3087  /**
3088   * Create the `Component`'s DOM element
3089   *
3090   * @return {Element}
3091   *         The element that was created.
3092   */
3093
3094
3095  LiveDisplay.prototype.createEl = function createEl() {
3096    var el = _Component.prototype.createEl.call(this, 'div', {
3097      className: 'vjs-live-control vjs-control'
3098    });
3099
3100    this.contentEl_ = Dom.createEl('div', {
3101      className: 'vjs-live-display',
3102      innerHTML: '<span class="vjs-control-text">' + this.localize('Stream Type') + '</span>' + this.localize('LIVE')
3103    }, {
3104      'aria-live': 'off'
3105    });
3106
3107    el.appendChild(this.contentEl_);
3108    return el;
3109  };
3110
3111  /**
3112   * Check the duration to see if the LiveDisplay should be showing or not. Then show/hide
3113   * it accordingly
3114   *
3115   * @param {EventTarget~Event} [event]
3116   *        The {@link Player#durationchange} event that caused this function to run.
3117   *
3118   * @listens Player#durationchange
3119   */
3120
3121
3122  LiveDisplay.prototype.updateShowing = function updateShowing(event) {
3123    if (this.player().duration() === Infinity) {
3124      this.show();
3125    } else {
3126      this.hide();
3127    }
3128  };
3129
3130  return LiveDisplay;
3131}(_component2['default']);
3132
3133_component2['default'].registerComponent('LiveDisplay', LiveDisplay);
3134exports['default'] = LiveDisplay;
3135
3136},{"5":5,"81":81}],11:[function(_dereq_,module,exports){
3137'use strict';
3138
3139exports.__esModule = true;
3140
3141var _button = _dereq_(2);
3142
3143var _button2 = _interopRequireDefault(_button);
3144
3145var _component = _dereq_(5);
3146
3147var _component2 = _interopRequireDefault(_component);
3148
3149var _dom = _dereq_(81);
3150
3151var Dom = _interopRequireWildcard(_dom);
3152
3153function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
3154
3155function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
3156
3157function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
3158
3159function _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; }
3160
3161function _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; } /**
3162                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file mute-toggle.js
3163                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
3164
3165
3166/**
3167 * A button component for muting the audio.
3168 *
3169 * @extends Button
3170 */
3171var MuteToggle = function (_Button) {
3172  _inherits(MuteToggle, _Button);
3173
3174  /**
3175   * Creates an instance of this class.
3176   *
3177   * @param {Player} player
3178   *        The `Player` that this class should be attached to.
3179   *
3180   * @param {Object} [options]
3181   *        The key/value store of player options.
3182   */
3183  function MuteToggle(player, options) {
3184    _classCallCheck(this, MuteToggle);
3185
3186    var _this = _possibleConstructorReturn(this, _Button.call(this, player, options));
3187
3188    _this.on(player, 'volumechange', _this.update);
3189
3190    // hide mute toggle if the current tech doesn't support volume control
3191    if (player.tech_ && player.tech_.featuresVolumeControl === false) {
3192      _this.addClass('vjs-hidden');
3193    }
3194
3195    _this.on(player, 'loadstart', function () {
3196      // We need to update the button to account for a default muted state.
3197      this.update();
3198
3199      if (player.tech_.featuresVolumeControl === false) {
3200        this.addClass('vjs-hidden');
3201      } else {
3202        this.removeClass('vjs-hidden');
3203      }
3204    });
3205    return _this;
3206  }
3207
3208  /**
3209   * Builds the default DOM `className`.
3210   *
3211   * @return {string}
3212   *         The DOM `className` for this object.
3213   */
3214
3215
3216  MuteToggle.prototype.buildCSSClass = function buildCSSClass() {
3217    return 'vjs-mute-control ' + _Button.prototype.buildCSSClass.call(this);
3218  };
3219
3220  /**
3221   * This gets called when an `MuteToggle` is "clicked". See
3222   * {@link ClickableComponent} for more detailed information on what a click can be.
3223   *
3224   * @param {EventTarget~Event} [event]
3225   *        The `keydown`, `tap`, or `click` event that caused this function to be
3226   *        called.
3227   *
3228   * @listens tap
3229   * @listens click
3230   */
3231
3232
3233  MuteToggle.prototype.handleClick = function handleClick(event) {
3234    this.player_.muted(this.player_.muted() ? false : true);
3235  };
3236
3237  /**
3238   * Update the state of volume.
3239   *
3240   * @param {EventTarget~Event} [event]
3241   *        The {@link Player#loadstart} event if this function was called through an
3242   *        event.
3243   *
3244   * @listens Player#loadstart
3245   */
3246
3247
3248  MuteToggle.prototype.update = function update(event) {
3249    var vol = this.player_.volume();
3250    var level = 3;
3251
3252    if (this.player_.muted()) {
3253      level = 0;
3254    } else if (vol < 0.33) {
3255      level = 1;
3256    } else if (vol < 0.67) {
3257      level = 2;
3258    }
3259
3260    // Don't rewrite the button text if the actual text doesn't change.
3261    // This causes unnecessary and confusing information for screen reader users.
3262    // This check is needed because this function gets called every time the volume level is changed.
3263    var toMute = this.player_.muted() ? 'Unmute' : 'Mute';
3264
3265    if (this.controlText() !== toMute) {
3266      this.controlText(toMute);
3267    }
3268
3269    // TODO improve muted icon classes
3270    for (var i = 0; i < 4; i++) {
3271      Dom.removeElClass(this.el_, 'vjs-vol-' + i);
3272    }
3273    Dom.addElClass(this.el_, 'vjs-vol-' + level);
3274  };
3275
3276  return MuteToggle;
3277}(_button2['default']);
3278
3279/**
3280 * The text that should display over the `MuteToggle`s controls. Added for localization.
3281 *
3282 * @type {string}
3283 * @private
3284 */
3285
3286
3287MuteToggle.prototype.controlText_ = 'Mute';
3288
3289_component2['default'].registerComponent('MuteToggle', MuteToggle);
3290exports['default'] = MuteToggle;
3291
3292},{"2":2,"5":5,"81":81}],12:[function(_dereq_,module,exports){
3293'use strict';
3294
3295exports.__esModule = true;
3296
3297var _button = _dereq_(2);
3298
3299var _button2 = _interopRequireDefault(_button);
3300
3301var _component = _dereq_(5);
3302
3303var _component2 = _interopRequireDefault(_component);
3304
3305function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
3306
3307function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
3308
3309function _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; }
3310
3311function _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; } /**
3312                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file play-toggle.js
3313                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
3314
3315
3316/**
3317 * Button to toggle between play and pause.
3318 *
3319 * @extends Button
3320 */
3321var PlayToggle = function (_Button) {
3322  _inherits(PlayToggle, _Button);
3323
3324  /**
3325   * Creates an instance of this class.
3326   *
3327   * @param {Player} player
3328   *        The `Player` that this class should be attached to.
3329   *
3330   * @param {Object} [options]
3331   *        The key/value store of player options.
3332   */
3333  function PlayToggle(player, options) {
3334    _classCallCheck(this, PlayToggle);
3335
3336    var _this = _possibleConstructorReturn(this, _Button.call(this, player, options));
3337
3338    _this.on(player, 'play', _this.handlePlay);
3339    _this.on(player, 'pause', _this.handlePause);
3340    return _this;
3341  }
3342
3343  /**
3344   * Builds the default DOM `className`.
3345   *
3346   * @return {string}
3347   *         The DOM `className` for this object.
3348   */
3349
3350
3351  PlayToggle.prototype.buildCSSClass = function buildCSSClass() {
3352    return 'vjs-play-control ' + _Button.prototype.buildCSSClass.call(this);
3353  };
3354
3355  /**
3356   * This gets called when an `PlayToggle` is "clicked". See
3357   * {@link ClickableComponent} for more detailed information on what a click can be.
3358   *
3359   * @param {EventTarget~Event} [event]
3360   *        The `keydown`, `tap`, or `click` event that caused this function to be
3361   *        called.
3362   *
3363   * @listens tap
3364   * @listens click
3365   */
3366
3367
3368  PlayToggle.prototype.handleClick = function handleClick(event) {
3369    if (this.player_.paused()) {
3370      this.player_.play();
3371    } else {
3372      this.player_.pause();
3373    }
3374  };
3375
3376  /**
3377   * Add the vjs-playing class to the element so it can change appearance.
3378   *
3379   * @param {EventTarget~Event} [event]
3380   *        The event that caused this function to run.
3381   *
3382   * @listens Player#play
3383   */
3384
3385
3386  PlayToggle.prototype.handlePlay = function handlePlay(event) {
3387    this.removeClass('vjs-paused');
3388    this.addClass('vjs-playing');
3389    // change the button text to "Pause"
3390    this.controlText('Pause');
3391  };
3392
3393  /**
3394   * Add the vjs-paused class to the element so it can change appearance.
3395   *
3396   * @param {EventTarget~Event} [event]
3397   *        The event that caused this function to run.
3398   *
3399   * @listens Player#pause
3400   */
3401
3402
3403  PlayToggle.prototype.handlePause = function handlePause(event) {
3404    this.removeClass('vjs-playing');
3405    this.addClass('vjs-paused');
3406    // change the button text to "Play"
3407    this.controlText('Play');
3408  };
3409
3410  return PlayToggle;
3411}(_button2['default']);
3412
3413/**
3414 * The text that should display over the `PlayToggle`s controls. Added for localization.
3415 *
3416 * @type {string}
3417 * @private
3418 */
3419
3420
3421PlayToggle.prototype.controlText_ = 'Play';
3422
3423_component2['default'].registerComponent('PlayToggle', PlayToggle);
3424exports['default'] = PlayToggle;
3425
3426},{"2":2,"5":5}],13:[function(_dereq_,module,exports){
3427'use strict';
3428
3429exports.__esModule = true;
3430
3431var _menuButton = _dereq_(47);
3432
3433var _menuButton2 = _interopRequireDefault(_menuButton);
3434
3435var _menu = _dereq_(49);
3436
3437var _menu2 = _interopRequireDefault(_menu);
3438
3439var _playbackRateMenuItem = _dereq_(14);
3440
3441var _playbackRateMenuItem2 = _interopRequireDefault(_playbackRateMenuItem);
3442
3443var _component = _dereq_(5);
3444
3445var _component2 = _interopRequireDefault(_component);
3446
3447var _dom = _dereq_(81);
3448
3449var Dom = _interopRequireWildcard(_dom);
3450
3451function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
3452
3453function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
3454
3455function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
3456
3457function _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; }
3458
3459function _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; } /**
3460                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file playback-rate-menu-button.js
3461                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
3462
3463
3464/**
3465 * The component for controlling the playback rate.
3466 *
3467 * @extends MenuButton
3468 */
3469var PlaybackRateMenuButton = function (_MenuButton) {
3470  _inherits(PlaybackRateMenuButton, _MenuButton);
3471
3472  /**
3473   * Creates an instance of this class.
3474   *
3475   * @param {Player} player
3476   *        The `Player` that this class should be attached to.
3477   *
3478   * @param {Object} [options]
3479   *        The key/value store of player options.
3480   */
3481  function PlaybackRateMenuButton(player, options) {
3482    _classCallCheck(this, PlaybackRateMenuButton);
3483
3484    var _this = _possibleConstructorReturn(this, _MenuButton.call(this, player, options));
3485
3486    _this.updateVisibility();
3487    _this.updateLabel();
3488
3489    _this.on(player, 'loadstart', _this.updateVisibility);
3490    _this.on(player, 'ratechange', _this.updateLabel);
3491    return _this;
3492  }
3493
3494  /**
3495   * Create the `Component`'s DOM element
3496   *
3497   * @return {Element}
3498   *         The element that was created.
3499   */
3500
3501
3502  PlaybackRateMenuButton.prototype.createEl = function createEl() {
3503    var el = _MenuButton.prototype.createEl.call(this);
3504
3505    this.labelEl_ = Dom.createEl('div', {
3506      className: 'vjs-playback-rate-value',
3507      innerHTML: 1.0
3508    });
3509
3510    el.appendChild(this.labelEl_);
3511
3512    return el;
3513  };
3514
3515  /**
3516   * Builds the default DOM `className`.
3517   *
3518   * @return {string}
3519   *         The DOM `className` for this object.
3520   */
3521
3522
3523  PlaybackRateMenuButton.prototype.buildCSSClass = function buildCSSClass() {
3524    return 'vjs-playback-rate ' + _MenuButton.prototype.buildCSSClass.call(this);
3525  };
3526
3527  /**
3528   * Create the playback rate menu
3529   *
3530   * @return {Menu}
3531   *         Menu object populated with {@link PlaybackRateMenuItem}s
3532   */
3533
3534
3535  PlaybackRateMenuButton.prototype.createMenu = function createMenu() {
3536    var menu = new _menu2['default'](this.player());
3537    var rates = this.playbackRates();
3538
3539    if (rates) {
3540      for (var i = rates.length - 1; i >= 0; i--) {
3541        menu.addChild(new _playbackRateMenuItem2['default'](this.player(), { rate: rates[i] + 'x' }));
3542      }
3543    }
3544
3545    return menu;
3546  };
3547
3548  /**
3549   * Updates ARIA accessibility attributes
3550   */
3551
3552
3553  PlaybackRateMenuButton.prototype.updateARIAAttributes = function updateARIAAttributes() {
3554    // Current playback rate
3555    this.el().setAttribute('aria-valuenow', this.player().playbackRate());
3556  };
3557
3558  /**
3559   * This gets called when an `PlaybackRateMenuButton` is "clicked". See
3560   * {@link ClickableComponent} for more detailed information on what a click can be.
3561   *
3562   * @param {EventTarget~Event} [event]
3563   *        The `keydown`, `tap`, or `click` event that caused this function to be
3564   *        called.
3565   *
3566   * @listens tap
3567   * @listens click
3568   */
3569
3570
3571  PlaybackRateMenuButton.prototype.handleClick = function handleClick(event) {
3572    // select next rate option
3573    var currentRate = this.player().playbackRate();
3574    var rates = this.playbackRates();
3575
3576    // this will select first one if the last one currently selected
3577    var newRate = rates[0];
3578
3579    for (var i = 0; i < rates.length; i++) {
3580      if (rates[i] > currentRate) {
3581        newRate = rates[i];
3582        break;
3583      }
3584    }
3585    this.player().playbackRate(newRate);
3586  };
3587
3588  /**
3589   * Get possible playback rates
3590   *
3591   * @return {Array}
3592   *         All possible playback rates
3593   */
3594
3595
3596  PlaybackRateMenuButton.prototype.playbackRates = function playbackRates() {
3597    return this.options_.playbackRates || this.options_.playerOptions && this.options_.playerOptions.playbackRates;
3598  };
3599
3600  /**
3601   * Get whether playback rates is supported by the tech
3602   * and an array of playback rates exists
3603   *
3604   * @return {boolean}
3605   *         Whether changing playback rate is supported
3606   */
3607
3608
3609  PlaybackRateMenuButton.prototype.playbackRateSupported = function playbackRateSupported() {
3610    return this.player().tech_ && this.player().tech_.featuresPlaybackRate && this.playbackRates() && this.playbackRates().length > 0;
3611  };
3612
3613  /**
3614   * Hide playback rate controls when they're no playback rate options to select
3615   *
3616   * @param {EventTarget~Event} [event]
3617   *        The event that caused this function to run.
3618   *
3619   * @listens Player#loadstart
3620   */
3621
3622
3623  PlaybackRateMenuButton.prototype.updateVisibility = function updateVisibility(event) {
3624    if (this.playbackRateSupported()) {
3625      this.removeClass('vjs-hidden');
3626    } else {
3627      this.addClass('vjs-hidden');
3628    }
3629  };
3630
3631  /**
3632   * Update button label when rate changed
3633   *
3634   * @param {EventTarget~Event} [event]
3635   *        The event that caused this function to run.
3636   *
3637   * @listens Player#ratechange
3638   */
3639
3640
3641  PlaybackRateMenuButton.prototype.updateLabel = function updateLabel(event) {
3642    if (this.playbackRateSupported()) {
3643      this.labelEl_.innerHTML = this.player().playbackRate() + 'x';
3644    }
3645  };
3646
3647  return PlaybackRateMenuButton;
3648}(_menuButton2['default']);
3649
3650/**
3651 * The text that should display over the `FullscreenToggle`s controls. Added for localization.
3652 *
3653 * @type {string}
3654 * @private
3655 */
3656
3657
3658PlaybackRateMenuButton.prototype.controlText_ = 'Playback Rate';
3659
3660_component2['default'].registerComponent('PlaybackRateMenuButton', PlaybackRateMenuButton);
3661exports['default'] = PlaybackRateMenuButton;
3662
3663},{"14":14,"47":47,"49":49,"5":5,"81":81}],14:[function(_dereq_,module,exports){
3664'use strict';
3665
3666exports.__esModule = true;
3667
3668var _menuItem = _dereq_(48);
3669
3670var _menuItem2 = _interopRequireDefault(_menuItem);
3671
3672var _component = _dereq_(5);
3673
3674var _component2 = _interopRequireDefault(_component);
3675
3676function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
3677
3678function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
3679
3680function _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; }
3681
3682function _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; } /**
3683                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file playback-rate-menu-item.js
3684                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
3685
3686
3687/**
3688 * The specific menu item type for selecting a playback rate.
3689 *
3690 * @extends MenuItem
3691 */
3692var PlaybackRateMenuItem = function (_MenuItem) {
3693  _inherits(PlaybackRateMenuItem, _MenuItem);
3694
3695  /**
3696   * Creates an instance of this class.
3697   *
3698   * @param {Player} player
3699   *        The `Player` that this class should be attached to.
3700   *
3701   * @param {Object} [options]
3702   *        The key/value store of player options.
3703   */
3704  function PlaybackRateMenuItem(player, options) {
3705    _classCallCheck(this, PlaybackRateMenuItem);
3706
3707    var label = options.rate;
3708    var rate = parseFloat(label, 10);
3709
3710    // Modify options for parent MenuItem class's init.
3711    options.label = label;
3712    options.selected = rate === 1;
3713    options.selectable = true;
3714
3715    var _this = _possibleConstructorReturn(this, _MenuItem.call(this, player, options));
3716
3717    _this.label = label;
3718    _this.rate = rate;
3719
3720    _this.on(player, 'ratechange', _this.update);
3721    return _this;
3722  }
3723
3724  /**
3725   * This gets called when an `PlaybackRateMenuItem` is "clicked". See
3726   * {@link ClickableComponent} for more detailed information on what a click can be.
3727   *
3728   * @param {EventTarget~Event} [event]
3729   *        The `keydown`, `tap`, or `click` event that caused this function to be
3730   *        called.
3731   *
3732   * @listens tap
3733   * @listens click
3734   */
3735
3736
3737  PlaybackRateMenuItem.prototype.handleClick = function handleClick(event) {
3738    _MenuItem.prototype.handleClick.call(this);
3739    this.player().playbackRate(this.rate);
3740  };
3741
3742  /**
3743   * Update the PlaybackRateMenuItem when the playbackrate changes.
3744   *
3745   * @param {EventTarget~Event} [event]
3746   *        The `ratechange` event that caused this function to run.
3747   *
3748   * @listens Player#ratechange
3749   */
3750
3751
3752  PlaybackRateMenuItem.prototype.update = function update(event) {
3753    this.selected(this.player().playbackRate() === this.rate);
3754  };
3755
3756  return PlaybackRateMenuItem;
3757}(_menuItem2['default']);
3758
3759/**
3760 * The text that should display over the `PlaybackRateMenuItem`s controls. Added for localization.
3761 *
3762 * @type {string}
3763 * @private
3764 */
3765
3766
3767PlaybackRateMenuItem.prototype.contentElType = 'button';
3768
3769_component2['default'].registerComponent('PlaybackRateMenuItem', PlaybackRateMenuItem);
3770exports['default'] = PlaybackRateMenuItem;
3771
3772},{"48":48,"5":5}],15:[function(_dereq_,module,exports){
3773'use strict';
3774
3775exports.__esModule = true;
3776
3777var _component = _dereq_(5);
3778
3779var _component2 = _interopRequireDefault(_component);
3780
3781var _dom = _dereq_(81);
3782
3783var Dom = _interopRequireWildcard(_dom);
3784
3785function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
3786
3787function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
3788
3789function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
3790
3791function _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; }
3792
3793function _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; } /**
3794                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file load-progress-bar.js
3795                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
3796
3797
3798/**
3799 * Shows loading progress
3800 *
3801 * @extends Component
3802 */
3803var LoadProgressBar = function (_Component) {
3804  _inherits(LoadProgressBar, _Component);
3805
3806  /**
3807   * Creates an instance of this class.
3808   *
3809   * @param {Player} player
3810   *        The `Player` that this class should be attached to.
3811   *
3812   * @param {Object} [options]
3813   *        The key/value store of player options.
3814   */
3815  function LoadProgressBar(player, options) {
3816    _classCallCheck(this, LoadProgressBar);
3817
3818    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
3819
3820    _this.partEls_ = [];
3821    _this.on(player, 'progress', _this.update);
3822    return _this;
3823  }
3824
3825  /**
3826   * Create the `Component`'s DOM element
3827   *
3828   * @return {Element}
3829   *         The element that was created.
3830   */
3831
3832
3833  LoadProgressBar.prototype.createEl = function createEl() {
3834    return _Component.prototype.createEl.call(this, 'div', {
3835      className: 'vjs-load-progress',
3836      innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Loaded') + '</span>: 0%</span>'
3837    });
3838  };
3839
3840  /**
3841   * Update progress bar
3842   *
3843   * @param {EventTarget~Event} [event]
3844   *        The `progress` event that caused this function to run.
3845   *
3846   * @listens Player#progress
3847   */
3848
3849
3850  LoadProgressBar.prototype.update = function update(event) {
3851    var buffered = this.player_.buffered();
3852    var duration = this.player_.duration();
3853    var bufferedEnd = this.player_.bufferedEnd();
3854    var children = this.partEls_;
3855
3856    // get the percent width of a time compared to the total end
3857    var percentify = function percentify(time, end) {
3858      // no NaN
3859      var percent = time / end || 0;
3860
3861      return (percent >= 1 ? 1 : percent) * 100 + '%';
3862    };
3863
3864    // update the width of the progress bar
3865    this.el_.style.width = percentify(bufferedEnd, duration);
3866
3867    // add child elements to represent the individual buffered time ranges
3868    for (var i = 0; i < buffered.length; i++) {
3869      var start = buffered.start(i);
3870      var end = buffered.end(i);
3871      var part = children[i];
3872
3873      if (!part) {
3874        part = this.el_.appendChild(Dom.createEl());
3875        children[i] = part;
3876      }
3877
3878      // set the percent based on the width of the progress bar (bufferedEnd)
3879      part.style.left = percentify(start, bufferedEnd);
3880      part.style.width = percentify(end - start, bufferedEnd);
3881    }
3882
3883    // remove unused buffered range elements
3884    for (var _i = children.length; _i > buffered.length; _i--) {
3885      this.el_.removeChild(children[_i - 1]);
3886    }
3887    children.length = buffered.length;
3888  };
3889
3890  return LoadProgressBar;
3891}(_component2['default']);
3892
3893_component2['default'].registerComponent('LoadProgressBar', LoadProgressBar);
3894exports['default'] = LoadProgressBar;
3895
3896},{"5":5,"81":81}],16:[function(_dereq_,module,exports){
3897'use strict';
3898
3899exports.__esModule = true;
3900
3901var _component = _dereq_(5);
3902
3903var _component2 = _interopRequireDefault(_component);
3904
3905var _dom = _dereq_(81);
3906
3907var Dom = _interopRequireWildcard(_dom);
3908
3909var _fn = _dereq_(83);
3910
3911var Fn = _interopRequireWildcard(_fn);
3912
3913var _formatTime = _dereq_(84);
3914
3915var _formatTime2 = _interopRequireDefault(_formatTime);
3916
3917var _computedStyle = _dereq_(80);
3918
3919var _computedStyle2 = _interopRequireDefault(_computedStyle);
3920
3921function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
3922
3923function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
3924
3925function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
3926
3927function _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; }
3928
3929function _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; } /**
3930                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file mouse-time-display.js
3931                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
3932
3933
3934/**
3935 * The Mouse Time Display component shows the time you will seek to
3936 * when hovering over the progress bar
3937 *
3938 * @extends Component
3939 */
3940var MouseTimeDisplay = function (_Component) {
3941  _inherits(MouseTimeDisplay, _Component);
3942
3943  /**
3944   * Creates an instance of this class.
3945   *
3946   * @param {Player} player
3947   *        The `Player` that this class should be attached to.
3948   *
3949   * @param {Object} [options]
3950   *        The key/value store of player options.
3951   */
3952  function MouseTimeDisplay(player, options) {
3953    _classCallCheck(this, MouseTimeDisplay);
3954
3955    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
3956
3957    if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) {
3958      _this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside;
3959    }
3960
3961    if (_this.keepTooltipsInside) {
3962      _this.tooltip = Dom.createEl('div', { className: 'vjs-time-tooltip' });
3963      _this.el().appendChild(_this.tooltip);
3964      _this.addClass('vjs-keep-tooltips-inside');
3965    }
3966
3967    _this.update(0, 0);
3968
3969    player.on('ready', function () {
3970      _this.on(player.controlBar.progressControl.el(), 'mousemove', Fn.throttle(Fn.bind(_this, _this.handleMouseMove), 25));
3971    });
3972    return _this;
3973  }
3974
3975  /**
3976   * Create the `Component`'s DOM element
3977   *
3978   * @return {Element}
3979   *         The element that was created.
3980   */
3981
3982
3983  MouseTimeDisplay.prototype.createEl = function createEl() {
3984    return _Component.prototype.createEl.call(this, 'div', {
3985      className: 'vjs-mouse-display'
3986    });
3987  };
3988
3989  /**
3990   * Handle the mouse move event on the `MouseTimeDisplay`.
3991   *
3992   * @param {EventTarget~Event} event
3993   *        The `mousemove` event that caused this to event to run.
3994   *
3995   * @listen mousemove
3996   */
3997
3998
3999  MouseTimeDisplay.prototype.handleMouseMove = function handleMouseMove(event) {
4000    var duration = this.player_.duration();
4001    var newTime = this.calculateDistance(event) * duration;
4002    var position = event.pageX - Dom.findElPosition(this.el().parentNode).left;
4003
4004    this.update(newTime, position);
4005  };
4006
4007  /**
4008   * Update the time and posistion of the `MouseTimeDisplay`.
4009   *
4010   * @param {number} newTime
4011   *        Time to change the `MouseTimeDisplay` to.
4012   *
4013   * @param {nubmer} position
4014   *        Postion from the left of the in pixels.
4015   */
4016
4017
4018  MouseTimeDisplay.prototype.update = function update(newTime, position) {
4019    var time = (0, _formatTime2['default'])(newTime, this.player_.duration());
4020
4021    this.el().style.left = position + 'px';
4022    this.el().setAttribute('data-current-time', time);
4023
4024    if (this.keepTooltipsInside) {
4025      var clampedPosition = this.clampPosition_(position);
4026      var difference = position - clampedPosition + 1;
4027      var tooltipWidth = parseFloat((0, _computedStyle2['default'])(this.tooltip, 'width'));
4028      var tooltipWidthHalf = tooltipWidth / 2;
4029
4030      this.tooltip.innerHTML = time;
4031      this.tooltip.style.right = '-' + (tooltipWidthHalf - difference) + 'px';
4032    }
4033  };
4034
4035  /**
4036   * Get the mouse pointers x coordinate in pixels.
4037   *
4038   * @param {EventTarget~Event} [event]
4039   *        The `mousemove` event that was passed to this function by
4040   *        {@link MouseTimeDisplay#handleMouseMove}
4041   *
4042   * @return {number}
4043   *         THe x position in pixels of the mouse pointer.
4044   */
4045
4046
4047  MouseTimeDisplay.prototype.calculateDistance = function calculateDistance(event) {
4048    return Dom.getPointerPosition(this.el().parentNode, event).x;
4049  };
4050
4051  /**
4052   * This takes in a horizontal position for the bar and returns a clamped position.
4053   * Clamped position means that it will keep the position greater than half the width
4054   * of the tooltip and smaller than the player width minus half the width o the tooltip.
4055   * It will only clamp the position if `keepTooltipsInside` option is set.
4056   *
4057   * @param {number} position
4058   *        The position the bar wants to be
4059   *
4060   * @return {number}
4061   *         The (potentially) new clamped position.
4062   *
4063   * @private
4064   */
4065
4066
4067  MouseTimeDisplay.prototype.clampPosition_ = function clampPosition_(position) {
4068    if (!this.keepTooltipsInside) {
4069      return position;
4070    }
4071
4072    var playerWidth = parseFloat((0, _computedStyle2['default'])(this.player().el(), 'width'));
4073    var tooltipWidth = parseFloat((0, _computedStyle2['default'])(this.tooltip, 'width'));
4074    var tooltipWidthHalf = tooltipWidth / 2;
4075    var actualPosition = position;
4076
4077    if (position < tooltipWidthHalf) {
4078      actualPosition = Math.ceil(tooltipWidthHalf);
4079    } else if (position > playerWidth - tooltipWidthHalf) {
4080      actualPosition = Math.floor(playerWidth - tooltipWidthHalf);
4081    }
4082
4083    return actualPosition;
4084  };
4085
4086  return MouseTimeDisplay;
4087}(_component2['default']);
4088
4089_component2['default'].registerComponent('MouseTimeDisplay', MouseTimeDisplay);
4090exports['default'] = MouseTimeDisplay;
4091
4092},{"5":5,"80":80,"81":81,"83":83,"84":84}],17:[function(_dereq_,module,exports){
4093'use strict';
4094
4095exports.__esModule = true;
4096
4097var _component = _dereq_(5);
4098
4099var _component2 = _interopRequireDefault(_component);
4100
4101var _fn = _dereq_(83);
4102
4103var Fn = _interopRequireWildcard(_fn);
4104
4105var _formatTime = _dereq_(84);
4106
4107var _formatTime2 = _interopRequireDefault(_formatTime);
4108
4109function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
4110
4111function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
4112
4113function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
4114
4115function _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; }
4116
4117function _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, { c
4117onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
4118                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file play-progress-bar.js
4119                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
4120
4121
4122/**
4123 * Shows play progress
4124 *
4125 * @extends Component
4126 */
4127var PlayProgressBar = function (_Component) {
4128  _inherits(PlayProgressBar, _Component);
4129
4130  /**
4131   * Creates an instance of this class.
4132   *
4133   * @param {Player} player
4134   *        The `Player` that this class should be attached to.
4135   *
4136   * @param {Object} [options]
4137   *        The key/value store of player options.
4138   */
4139  function PlayProgressBar(player, options) {
4140    _classCallCheck(this, PlayProgressBar);
4141
4142    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
4143
4144    _this.updateDataAttr();
4145    _this.on(player, 'timeupdate', _this.updateDataAttr);
4146    player.ready(Fn.bind(_this, _this.updateDataAttr));
4147
4148    if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) {
4149      _this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside;
4150    }
4151
4152    if (_this.keepTooltipsInside) {
4153      _this.addClass('vjs-keep-tooltips-inside');
4154    }
4155    return _this;
4156  }
4157
4158  /**
4159   * Create the `Component`'s DOM element
4160   *
4161   * @return {Element}
4162   *         The element that was created.
4163   */
4164
4165
4166  PlayProgressBar.prototype.createEl = function createEl() {
4167    return _Component.prototype.createEl.call(this, 'div', {
4168      className: 'vjs-play-progress vjs-slider-bar',
4169      innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Progress') + '</span>: 0%</span>'
4170    });
4171  };
4172
4173  /**
4174   * Update the data-current-time attribute on the `PlayProgressBar`.
4175   *
4176   * @param {EventTarget~Event} [event]
4177   *        The `timeupdate` event that caused this to run.
4178   *
4179   * @listens Player#timeupdate
4180   */
4181
4182
4183  PlayProgressBar.prototype.updateDataAttr = function updateDataAttr(event) {
4184    var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();
4185
4186    this.el_.setAttribute('data-current-time', (0, _formatTime2['default'])(time, this.player_.duration()));
4187  };
4188
4189  return PlayProgressBar;
4190}(_component2['default']);
4191
4192_component2['default'].registerComponent('PlayProgressBar', PlayProgressBar);
4193exports['default'] = PlayProgressBar;
4194
4195},{"5":5,"83":83,"84":84}],18:[function(_dereq_,module,exports){
4196'use strict';
4197
4198exports.__esModule = true;
4199
4200var _component = _dereq_(5);
4201
4202var _component2 = _interopRequireDefault(_component);
4203
4204_dereq_(19);
4205
4206_dereq_(16);
4207
4208function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
4209
4210function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
4211
4212function _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; }
4213
4214function _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, { c
4214onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
4215                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file progress-control.js
4216                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
4217
4218
4219/**
4220 * The Progress Control component contains the seek bar, load progress,
4221 * and play progress.
4222 *
4223 * @extends Component
4224 */
4225var ProgressControl = function (_Component) {
4226  _inherits(ProgressControl, _Component);
4227
4228  function ProgressControl() {
4229    _classCallCheck(this, ProgressControl);
4230
4231    return _possibleConstructorReturn(this, _Component.apply(this, arguments));
4232  }
4233
4234  /**
4235   * Create the `Component`'s DOM element
4236   *
4237   * @return {Element}
4238   *         The element that was created.
4239   */
4240  ProgressControl.prototype.createEl = function createEl() {
4241    return _Component.prototype.createEl.call(this, 'div', {
4242      className: 'vjs-progress-control vjs-control'
4243    });
4244  };
4245
4246  return ProgressControl;
4247}(_component2['default']);
4248
4249/**
4250 * Default options for `ProgressControl`
4251 *
4252 * @type {Object}
4253 * @private
4254 */
4255
4256
4257ProgressControl.prototype.options_ = {
4258  children: ['seekBar']
4259};
4260
4261_component2['default'].registerComponent('ProgressControl', ProgressControl);
4262exports['default'] = ProgressControl;
4263
4264},{"16":16,"19":19,"5":5}],19:[function(_dereq_,module,exports){
4265'use strict';
4266
4267exports.__esModule = true;
4268
4269var _slider = _dereq_(57);
4270
4271var _slider2 = _interopRequireDefault(_slider);
4272
4273var _component = _dereq_(5);
4274
4275var _component2 = _interopRequireDefault(_component);
4276
4277var _fn = _dereq_(83);
4278
4279var Fn = _interopRequireWildcard(_fn);
4280
4281var _formatTime = _dereq_(84);
4282
4283var _formatTime2 = _interopRequireDefault(_formatTime);
4284
4285var _computedStyle = _dereq_(80);
4286
4287var _computedStyle2 = _interopRequireDefault(_computedStyle);
4288
4289_dereq_(15);
4290
4291_dereq_(17);
4292
4293_dereq_(20);
4294
4295function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
4296
4297function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
4298
4299function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
4300
4301function _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; }
4302
4303function _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; } /**
4304                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file seek-bar.js
4305                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
4306
4307
4308/**
4309 * Seek Bar and holder for the progress bars
4310 *
4311 * @extends Slider
4312 */
4313var SeekBar = function (_Slider) {
4314  _inherits(SeekBar, _Slider);
4315
4316  /**
4317   * Creates an instance of this class.
4318   *
4319   * @param {Player} player
4320   *        The `Player` that this class should be attached to.
4321   *
4322   * @param {Object} [options]
4323   *        The key/value store of player options.
4324   */
4325  function SeekBar(player, options) {
4326    _classCallCheck(this, SeekBar);
4327
4328    var _this = _possibleConstructorReturn(this, _Slider.call(this, player, options));
4329
4330    _this.on(player, 'timeupdate', _this.updateProgress);
4331    _this.on(player, 'ended', _this.updateProgress);
4332    player.ready(Fn.bind(_this, _this.updateProgress));
4333
4334    if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) {
4335      _this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside;
4336    }
4337
4338    if (_this.keepTooltipsInside) {
4339      _this.tooltipProgressBar = _this.addChild('TooltipProgressBar');
4340    }
4341    return _this;
4342  }
4343
4344  /**
4345   * Create the `Component`'s DOM element
4346   *
4347   * @return {Element}
4348   *         The element that was created.
4349   */
4350
4351
4352  SeekBar.prototype.createEl = function createEl() {
4353    return _Slider.prototype.createEl.call(this, 'div', {
4354      className: 'vjs-progress-holder'
4355    }, {
4356      'aria-label': 'progress bar'
4357    });
4358  };
4359
4360  /**
4361   * Update the seek bars tooltip and width.
4362   *
4363   * @param {EventTarget~Event} [event]
4364   *        The `timeupdate` or `ended` event that caused this to run.
4365   *
4366   * @listens Player#timeupdate
4367   * @listens Player#ended
4368   */
4369
4370
4371  SeekBar.prototype.updateProgress = function updateProgress(event) {
4372    this.updateAriaAttributes(this.el_);
4373
4374    if (this.keepTooltipsInside) {
4375      this.updateAriaAttributes(this.tooltipProgressBar.el_);
4376      this.tooltipProgressBar.el_.style.width = this.bar.el_.style.width;
4377
4378      var playerWidth = parseFloat((0, _computedStyle2['default'])(this.player().el(), 'width'));
4379      var tooltipWidth = parseFloat((0, _computedStyle2['default'])(this.tooltipProgressBar.tooltip, 'width'));
4380      var tooltipStyle = this.tooltipProgressBar.el().style;
4381
4382      tooltipStyle.maxWidth = Math.floor(playerWidth - tooltipWidth / 2) + 'px';
4383      tooltipStyle.minWidth = Math.ceil(tooltipWidth / 2) + 'px';
4384      tooltipStyle.right = '-' + tooltipWidth / 2 + 'px';
4385    }
4386  };
4387
4388  /**
4389   * Update ARIA accessibility attributes
4390   *
4391   * @param {Element} el
4392   *        The element to update with aria accessibility attributes.
4393   */
4394
4395
4396  SeekBar.prototype.updateAriaAttributes = function updateAriaAttributes(el) {
4397    // Allows for smooth scrubbing, when player can't keep up.
4398    var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();
4399
4400    // machine readable value of progress bar (percentage complete)
4401    el.setAttribute('aria-valuenow', (this.getPercent() * 100).toFixed(2));
4402    // human readable value of progress bar (time complete)
4403    el.setAttribute('aria-valuetext', (0, _formatTime2['default'])(time, this.player_.duration()));
4404  };
4405
4406  /**
4407   * Get percentage of video played
4408   *
4409   * @return {number}
4410   *         The percentage played
4411   */
4412
4413
4414  SeekBar.prototype.getPercent = function getPercent() {
4415    var percent = this.player_.currentTime() / this.player_.duration();
4416
4417    return percent >= 1 ? 1 : percent;
4418  };
4419
4420  /**
4421   * Handle mouse down on seek bar
4422   *
4423   * @param {EventTarget~Event} event
4424   *        The `mousedown` event that caused this to run.
4425   *
4426   * @listens mousedown
4427   */
4428
4429
4430  SeekBar.prototype.handleMouseDown = function handleMouseDown(event) {
4431    this.player_.scrubbing(true);
4432
4433    this.videoWasPlaying = !this.player_.paused();
4434    this.player_.pause();
4435
4436    _Slider.prototype.handleMouseDown.call(this, event);
4437  };
4438
4439  /**
4440   * Handle mouse move on seek bar
4441   *
4442   * @param {EventTarget~Event} event
4443   *        The `mousemove` event that caused this to run.
4444   *
4445   * @listens mousemove
4446   */
4447
4448
4449  SeekBar.prototype.handleMouseMove = function handleMouseMove(event) {
4450    var newTime = this.calculateDistance(event) * this.player_.duration();
4451
4452    // Don't let video end while scrubbing.
4453    if (newTime === this.player_.duration()) {
4454      newTime = newTime - 0.1;
4455    }
4456
4457    // Set new time (tell player to seek to new time)
4458    this.player_.currentTime(newTime);
4459  };
4460
4461  /**
4462   * Handle mouse up on seek bar
4463   *
4464   * @param {EventTarget~Event} event
4465   *        The `mouseup` event that caused this to run.
4466   *
4467   * @listens mouseup
4468   */
4469
4470
4471  SeekBar.prototype.handleMouseUp = function handleMouseUp(event) {
4472    _Slider.prototype.handleMouseUp.call(this, event);
4473
4474    this.player_.scrubbing(false);
4475    if (this.videoWasPlaying) {
4476      this.player_.play();
4477    }
4478  };
4479
4480  /**
4481   * Move more quickly fast forward for keyboard-only users
4482   */
4483
4484
4485  SeekBar.prototype.stepForward = function stepForward() {
4486    // more quickly fast forward for keyboard-only users
4487    this.player_.currentTime(this.player_.currentTime() + 5);
4488  };
4489
4490  /**
4491   * Move more quickly rewind for keyboard-only users
4492   */
4493
4494
4495  SeekBar.prototype.stepBack = function stepBack() {
4496    // more quickly rewind for keyboard-only users
4497    this.player_.currentTime(this.player_.currentTime() - 5);
4498  };
4499
4500  return SeekBar;
4501}(_slider2['default']);
4502
4503/**
4504 * Default options for the `SeekBar`
4505 *
4506 * @type {Object}
4507 * @private
4508 */
4509
4510
4511SeekBar.prototype.options_ = {
4512  children: ['loadProgressBar', 'mouseTimeDisplay', 'playProgressBar'],
4513  barName: 'playProgressBar'
4514};
4515
4516/**
4517 * Call the update event for this Slider when this event happens on the player.
4518 *
4519 * @type {string}
4520 */
4521SeekBar.prototype.playerEvent = 'timeupdate';
4522
4523_component2['default'].registerComponent('SeekBar', SeekBar);
4524exports['default'] = SeekBar;
4525
4526},{"15":15,"17":17,"20":20,"5":5,"57":57,"80":80,"83":83,"84":84}],20:[function(_dereq_,module,exports){
4527'use strict';
4528
4529exports.__esModule = true;
4530
4531var _component = _dereq_(5);
4532
4533var _component2 = _interopRequireDefault(_component);
4534
4535var _fn = _dereq_(83);
4536
4537var Fn = _interopRequireWildcard(_fn);
4538
4539var _formatTime = _dereq_(84);
4540
4541var _formatTime2 = _interopRequireDefault(_formatTime);
4542
4543function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
4544
4545function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
4546
4547function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
4548
4549function _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; }
4550
4551function _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, { c
4551onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
4552                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file play-progress-bar.js
4553                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
4554
4555
4556/**
4557 * Shows play progress
4558 *
4559 * @extends Component
4560 */
4561var TooltipProgressBar = function (_Component) {
4562  _inherits(TooltipProgressBar, _Component);
4563
4564  /**
4565   * Creates an instance of this class.
4566   *
4567   * @param {Player} player
4568   *        The `Player` that this class should be attached to.
4569   *
4570   * @param {Object} [options]
4571   *        The key/value store of player options.
4572   */
4573  function TooltipProgressBar(player, options) {
4574    _classCallCheck(this, TooltipProgressBar);
4575
4576    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
4577
4578    _this.updateDataAttr();
4579    _this.on(player, 'timeupdate', _this.updateDataAttr);
4580    player.ready(Fn.bind(_this, _this.updateDataAttr));
4581    return _this;
4582  }
4583
4584  /**
4585   * Create the `Component`'s DOM element
4586   *
4587   * @return {Element}
4588   *         The element that was created.
4589   */
4590
4591
4592  TooltipProgressBar.prototype.createEl = function createEl() {
4593    var el = _Component.prototype.createEl.call(this, 'div', {
4594      className: 'vjs-tooltip-progress-bar vjs-slider-bar',
4595      innerHTML: '<div class="vjs-time-tooltip"></div>\n        <span class="vjs-control-text"><span>' + this.localize('Progress') + '</span>: 0%</span>'
4596    });
4597
4598    this.tooltip = el.querySelector('.vjs-time-tooltip');
4599
4600    return el;
4601  };
4602
4603  /**
4604   * Updatet the data-current-time attribute for TooltipProgressBar
4605   *
4606   * @param {EventTarget~Event} [event]
4607   *        The `timeupdate` event that caused this function to run.
4608   *
4609   * @listens Player#timeupdate
4610   */
4611
4612
4613  TooltipProgressBar.prototype.updateDataAttr = function updateDataAttr(event) {
4614    var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();
4615    var formattedTime = (0, _formatTime2['default'])(time, this.player_.duration());
4616
4617    this.el_.setAttribute('data-current-time', formattedTime);
4618    this.tooltip.innerHTML = formattedTime;
4619  };
4620
4621  return TooltipProgressBar;
4622}(_component2['default']);
4623
4624_component2['default'].registerComponent('TooltipProgressBar', TooltipProgressBar);
4625exports['default'] = TooltipProgressBar;
4626
4627},{"5":5,"83":83,"84":84}],21:[function(_dereq_,module,exports){
4628'use strict';
4629
4630exports.__esModule = true;
4631
4632var _spacer = _dereq_(22);
4633
4634var _spacer2 = _interopRequireDefault(_spacer);
4635
4636var _component = _dereq_(5);
4637
4638var _component2 = _interopRequireDefault(_component);
4639
4640function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
4641
4642function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
4643
4644function _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; }
4645
4646function _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, { c
4646onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
4647                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file custom-control-spacer.js
4648                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
4649
4650
4651/**
4652 * Spacer specifically meant to be used as an insertion point for new plugins, etc.
4653 *
4654 * @extends Spacer
4655 */
4656var CustomControlSpacer = function (_Spacer) {
4657  _inherits(CustomControlSpacer, _Spacer);
4658
4659  function CustomControlSpacer() {
4660    _classCallCheck(this, CustomControlSpacer);
4661
4662    return _possibleConstructorReturn(this, _Spacer.apply(this, arguments));
4663  }
4664
4665  /**
4666   * Builds the default DOM `className`.
4667   *
4668   * @return {string}
4669   *         The DOM `className` for this object.
4670   */
4671  CustomControlSpacer.prototype.buildCSSClass = function buildCSSClass() {
4672    return 'vjs-custom-control-spacer ' + _Spacer.prototype.buildCSSClass.call(this);
4673  };
4674
4675  /**
4676   * Create the `Component`'s DOM element
4677   *
4678   * @return {Element}
4679   *         The element that was created.
4680   */
4681
4682
4683  CustomControlSpacer.prototype.createEl = function createEl() {
4684    var el = _Spacer.prototype.createEl.call(this, {
4685      className: this.buildCSSClass()
4686    });
4687
4688    // No-flex/table-cell mode requires there be some content
4689    // in the cell to fill the remaining space of the table.
4690    el.innerHTML = '&nbsp;';
4691    return el;
4692  };
4693
4694  return CustomControlSpacer;
4695}(_spacer2['default']);
4696
4697_component2['default'].registerComponent('CustomControlSpacer', CustomControlSpacer);
4698exports['default'] = CustomControlSpacer;
4699
4700},{"22":22,"5":5}],22:[function(_dereq_,module,exports){
4701'use strict';
4702
4703exports.__esModule = true;
4704
4705var _component = _dereq_(5);
4706
4707var _component2 = _interopRequireDefault(_component);
4708
4709function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
4710
4711function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
4712
4713function _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; }
4714
4715function _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; } /**
4716                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file spacer.js
4717                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
4718
4719
4720/**
4721 * Just an empty spacer element that can be used as an append point for plugins, etc.
4722 * Also can be used to create space between elements when necessary.
4723 *
4724 * @extends Component
4725 */
4726var Spacer = function (_Component) {
4727  _inherits(Spacer, _Component);
4728
4729  function Spacer() {
4730    _classCallCheck(this, Spacer);
4731
4732    return _possibleConstructorReturn(this, _Component.apply(this, arguments));
4733  }
4734
4735  /**
4736   * Builds the default DOM `className`.
4737   *
4738   * @return {string}
4739   *         The DOM `className` for this object.
4740   */
4741  Spacer.prototype.buildCSSClass = function buildCSSClass() {
4742    return 'vjs-spacer ' + _Component.prototype.buildCSSClass.call(this);
4743  };
4744
4745  /**
4746   * Create the `Component`'s DOM element
4747   *
4748   * @return {Element}
4749   *         The element that was created.
4750   */
4751
4752
4753  Spacer.prototype.createEl = function createEl() {
4754    return _Component.prototype.createEl.call(this, 'div', {
4755      className: this.buildCSSClass()
4756    });
4757  };
4758
4759  return Spacer;
4760}(_component2['default']);
4761
4762_component2['default'].registerComponent('Spacer', Spacer);
4763
4764exports['default'] = Spacer;
4765
4766},{"5":5}],23:[function(_dereq_,module,exports){
4767'use strict';
4768
4769exports.__esModule = true;
4770
4771var _textTrackMenuItem = _dereq_(31);
4772
4773var _textTrackMenuItem2 = _interopRequireDefault(_textTrackMenuItem);
4774
4775var _component = _dereq_(5);
4776
4777var _component2 = _interopRequireDefault(_component);
4778
4779function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
4780
4781function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
4782
4783function _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; }
4784
4785function _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, { c
4785onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
4786                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file caption-settings-menu-item.js
4787                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
4788
4789
4790/**
4791 * The menu item for caption track settings menu
4792 *
4793 * @extends TextTrackMenuItem
4794 */
4795var CaptionSettingsMenuItem = function (_TextTrackMenuItem) {
4796  _inherits(CaptionSettingsMenuItem, _TextTrackMenuItem);
4797
4798  /**
4799   * Creates an instance of this class.
4800   *
4801   * @param {Player} player
4802   *        The `Player` that this class should be attached to.
4803   *
4804   * @param {Object} [options]
4805   *        The key/value store of player options.
4806   */
4807  function CaptionSettingsMenuItem(player, options) {
4808    _classCallCheck(this, CaptionSettingsMenuItem);
4809
4810    options.track = {
4811      player: player,
4812      kind: options.kind,
4813      label: options.kind + ' settings',
4814      selectable: false,
4815      'default': false,
4816      mode: 'disabled'
4817    };
4818
4819    // CaptionSettingsMenuItem has no concept of 'selected'
4820    options.selectable = false;
4821
4822    var _this = _possibleConstructorReturn(this, _TextTrackMenuItem.call(this, player, options));
4823
4824    _this.addClass('vjs-texttrack-settings');
4825    _this.controlText(', opens ' + options.kind + ' settings dialog');
4826    return _this;
4827  }
4828
4829  /**
4830   * This gets called when an `CaptionSettingsMenuItem` is "clicked". See
4831   * {@link ClickableComponent} for more detailed information on what a click can be.
4832   *
4833   * @param {EventTarget~Event} [event]
4834   *        The `keydown`, `tap`, or `click` event that caused this function to be
4835   *        called.
4836   *
4837   * @listens tap
4838   * @listens click
4839   */
4840
4841
4842  CaptionSettingsMenuItem.prototype.handleClick = function handleClick(event) {
4843    this.player().getChild('textTrackSettings').show();
4844    this.player().getChild('textTrackSettings').el_.focus();
4845  };
4846
4847  return CaptionSettingsMenuItem;
4848}(_textTrackMenuItem2['default']);
4849
4850_component2['default'].registerComponent('CaptionSettingsMenuItem', CaptionSettingsMenuItem);
4851exports['default'] = CaptionSettingsMenuItem;
4852
4853},{"31":31,"5":5}],24:[function(_dereq_,module,exports){
4854'use strict';
4855
4856exports.__esModule = true;
4857
4858var _textTrackButton = _dereq_(30);
4859
4860var _textTrackButton2 = _interopRequireDefault(_textTrackButton);
4861
4862var _component = _dereq_(5);
4863
4864var _component2 = _interopRequireDefault(_component);
4865
4866var _captionSettingsMenuItem = _dereq_(23);
4867
4868var _captionSettingsMenuItem2 = _interopRequireDefault(_captionSettingsMenuItem);
4869
4870function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
4871
4872function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
4873
4874function _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; }
4875
4876function _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, { c
4876onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
4877                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file captions-button.js
4878                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
4879
4880
4881/**
4882 * The button component for toggling and selecting captions
4883 *
4884 * @extends TextTrackButton
4885 */
4886var CaptionsButton = function (_TextTrackButton) {
4887  _inherits(CaptionsButton, _TextTrackButton);
4888
4889  /**
4890   * Creates an instance of this class.
4891   *
4892   * @param {Player} player
4893   *        The `Player` that this class should be attached to.
4894   *
4895   * @param {Object} [options]
4896   *        The key/value store of player options.
4897   *
4898   * @param {Component~ReadyCallback} [ready]
4899   *        The function to call when this component is ready.
4900   */
4901  function CaptionsButton(player, options, ready) {
4902    _classCallCheck(this, CaptionsButton);
4903
4904    var _this = _possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready));
4905
4906    _this.el_.setAttribute('aria-label', 'Captions Menu');
4907    return _this;
4908  }
4909
4910  /**
4911   * Builds the default DOM `className`.
4912   *
4913   * @return {string}
4914   *         The DOM `className` for this object.
4915   */
4916
4917
4918  CaptionsButton.prototype.buildCSSClass = function buildCSSClass() {
4919    return 'vjs-captions-button ' + _TextTrackButton.prototype.buildCSSClass.call(this);
4920  };
4921
4922  /**
4923   * Create caption menu items
4924   *
4925   * @return {CaptionSettingsMenuItem[]}
4926   *         The array of current menu items.
4927   */
4928
4929
4930  CaptionsButton.prototype.createItems = function createItems() {
4931    var items = [];
4932
4933    if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks)) {
4934      items.push(new _captionSettingsMenuItem2['default'](this.player_, { kind: this.kind_ }));
4935
4936      this.hideThreshold_ += 1;
4937    }
4938
4939    return _TextTrackButton.prototype.createItems.call(this, items);
4940  };
4941
4942  return CaptionsButton;
4943}(_textTrackButton2['default']);
4944
4945/**
4946 * `kind` of TextTrack to look for to associate it with this menu.
4947 *
4948 * @type {string}
4949 * @private
4950 */
4951
4952
4953CaptionsButton.prototype.kind_ = 'captions';
4954
4955/**
4956 * The text that should display over the `CaptionsButton`s controls. Added for localization.
4957 *
4958 * @type {string}
4959 * @private
4960 */
4961CaptionsButton.prototype.controlText_ = 'Captions';
4962
4963_component2['default'].registerComponent('CaptionsButton', CaptionsButton);
4964exports['default'] = CaptionsButton;
4965
4966},{"23":23,"30":30,"5":5}],25:[function(_dereq_,module,exports){
4967'use strict';
4968
4969exports.__esModule = true;
4970
4971var _textTrackButton = _dereq_(30);
4972
4973var _textTrackButton2 = _interopRequireDefault(_textTrackButton);
4974
4975var _component = _dereq_(5);
4976
4977var _component2 = _interopRequireDefault(_component);
4978
4979var _chaptersTrackMenuItem = _dereq_(26);
4980
4981var _chaptersTrackMenuItem2 = _interopRequireDefault(_chaptersTrackMenuItem);
4982
4983var _toTitleCase = _dereq_(91);
4984
4985var _toTitleCase2 = _interopRequireDefault(_toTitleCase);
4986
4987function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
4988
4989function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
4990
4991function _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; }
4992
4993function _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, { c
vendor: 4,377 bytes, lines 4993-5110
4993onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
4994                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file chapters-button.js
4995                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
4996
4997
4998/**
4999 * The button component for toggling and selecting chapters
5000 * Chapters act much differently than other text tracks
5001 * Cues are navigation vs. other tracks of alternative languages
5002 *
5003 * @extends TextTrackButton
5004 */
5005var ChaptersButton = function (_TextTrackButton) {
5006  _inherits(ChaptersButton, _TextTrackButton);
5007
5008  /**
5009   * Creates an instance of this class.
5010   *
5011   * @param {Player} player
5012   *        The `Player` that this class should be attached to.
5013   *
5014   * @param {Object} [options]
5015   *        The key/value store of player options.
5016   *
5017   * @param {Component~ReadyCallback} [ready]
5018   *        The function to call when this function is ready.
5019   */
5020  function ChaptersButton(player, options, ready) {
5021    _classCallCheck(this, ChaptersButton);
5022
5023    var _this = _possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready));
5024
5025    _this.el_.setAttribute('aria-label', 'Chapters Menu');
5026    return _this;
5027  }
5028
5029  /**
5030   * Builds the default DOM `className`.
5031   *
5032   * @return {string}
5033   *         The DOM `className` for this object.
5034   */
5035
5036
5037  ChaptersButton.prototype.buildCSSClass = function buildCSSClass() {
5038    return 'vjs-chapters-button ' + _TextTrackButton.prototype.buildCSSClass.call(this);
5039  };
5040
5041  /**
5042   * Update the menu based on the current state of its items.
5043   *
5044   * @param {EventTarget~Event} [event]
5045   *        An event that triggered this function to run.
5046   *
5047   * @listens TextTrackList#addtrack
5048   * @listens TextTrackList#removetrack
5049   * @listens TextTrackList#change
5050   */
5051
5052
5053  ChaptersButton.prototype.update = function update(event) {
5054    if (!this.track_ || event && (event.type === 'addtrack' || event.type === 'removetrack')) {
5055      this.setTrack(this.findChaptersTrack());
5056    }
5057    _TextTrackButton.prototype.update.call(this);
5058  };
5059
5060  /**
5061   * Set the currently selected track for the chapters button.
5062   *
5063   * @param {TextTrack} track
5064   *        The new track to select. Nothing will change if this is the currently selected
5065   *        track.
5066   */
5067
5068
5069  ChaptersButton.prototype.setTrack = function setTrack(track) {
5070    if (this.track_ === track) {
5071      return;
5072    }
5073
5074    if (!this.updateHandler_) {
5075      this.updateHandler_ = this.update.bind(this);
5076    }
5077
5078    // here this.track_ refers to the old track instance
5079    if (this.track_) {
5080      var remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(this.track_);
5081
5082      if (remoteTextTrackEl) {
5083        remoteTextTrackEl.removeEventListener('load', this.updateHandler_);
5084      }
5085
5086      this.track_ = null;
5087    }
5088
5089    this.track_ = track;
5090
5091    // here this.track_ refers to the new track instance
5092    if (this.track_) {
5093      this.track_.mode = 'hidden';
5094
5095      var _remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(this.track_);
5096
5097      if (_remoteTextTrackEl) {
5098        _remoteTextTrackEl.addEventListener('load', this.updateHandler_);
5099      }
5100    }
5101  };
5102
5103  /**
5104   * Find the track object that is currently in use by this ChaptersButton
5105   *
5106   * @return {TextTrack|undefined}
5107   *         The current track or undefined if none was found.
5108   */
5109
5110
5111  ChaptersButton.prototype.findChaptersTrack = function findChaptersTrack() {
5112    var tracks = this.player_.textTracks() || [];
5113
5114    for (var i = tracks.length - 1; i >= 0; i--) {
5115      // We will always choose the last track as our chaptersTrack
5116      var track = tracks[i];
5117
5118      if (track.kind === this.kind_) {
5119        return track;
5120      }
5121    }
5122  };
5123
5124  /**
5125   * Get the caption for the ChaptersButton based on the track label. This will also
5126   * use the current tracks localized kind as a fallback if a label does not exist.
5127   *
5128   * @return {string}
5129   *         The tracks current label or the localized track kind.
5130   */
5131
5132
5133  ChaptersButton.prototype.getMenuCaption = function getMenuCaption() {
5134    if (this.track_ && this.track_.label) {
5135      return this.track_.label;
5136    }
5137    return this.localize((0, _toTitleCase2['default'])(this.kind_));
5138  };
5139
5140  /**
5141   * Create menu from chapter track
5142   *
5143   * @return {Menu}
5144   *         New menu for the chapter buttons
5145   */
5146
5147
5148  ChaptersButton.prototype.createMenu = function createMenu() {
5149    this.options_.title = this.getMenuCaption();
5150    return _TextTrackButton.prototype.createMenu.call(this);
5151  };
5152
5153  /**
5154   * Create a menu item for each text track
5155   *
5156   * @return {TextTrackMenuItem[]}
5157   *         Array of menu items
5158   */
5159
5160
5161  ChaptersButton.prototype.createItems = function createItems() {
5162    var items = [];
5163
5164    if (!this.track_) {
5165      return items;
5166    }
5167
5168    var cues = this.track_.cues;
5169
5170    if (!cues) {
5171      return items;
5172    }
5173
5174    for (var i = 0, l = cues.length; i < l; i++) {
5175      var cue = cues[i];
5176      var mi = new _chaptersTrackMenuItem2['default'](this.player_, { track: this.track_, cue: cue });
5177
5178      items.push(mi);
5179    }
5180
5181    return items;
5182  };
5183
5184  return ChaptersButton;
5185}(_textTrackButton2['default']);
5186
5187/**
5188 * `kind` of TextTrack to look for to associate it with this menu.
5189 *
5190 * @type {string}
5191 * @private
5192 */
5193
5194
5195ChaptersButton.prototype.kind_ = 'chapters';
5196
5197/**
5198 * The text that should display over the `ChaptersButton`s controls. Added for localization.
5199 *
5200 * @type {string}
5201 * @private
5202 */
5203ChaptersButton.prototype.controlText_ = 'Chapters';
5204
5205_component2['default'].registerComponent('ChaptersButton', ChaptersButton);
5206exports['default'] = ChaptersButton;
5207
5208},{"26":26,"30":30,"5":5,"91":91}],26:[function(_dereq_,module,exports){
5209'use strict';
5210
5211exports.__esModule = true;
5212
5213var _menuItem = _dereq_(48);
5214
5215var _menuItem2 = _interopRequireDefault(_menuItem);
5216
5217var _component = _dereq_(5);
5218
5219var _component2 = _interopRequireDefault(_component);
5220
5221var _fn = _dereq_(83);
5222
5223var Fn = _interopRequireWildcard(_fn);
5224
5225function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
5226
5227function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
5228
5229function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
5230
5231function _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; }
5232
5233function _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; } /**
5234                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file chapters-track-menu-item.js
5235                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
5236
5237
5238/**
5239 * The chapter track menu item
5240 *
5241 * @extends MenuItem
5242 */
5243var ChaptersTrackMenuItem = function (_MenuItem) {
5244  _inherits(ChaptersTrackMenuItem, _MenuItem);
5245
5246  /**
5247   * Creates an instance of this class.
5248   *
5249   * @param {Player} player
5250   *        The `Player` that this class should be attached to.
5251   *
5252   * @param {Object} [options]
5253   *        The key/value store of player options.
5254   */
5255  function ChaptersTrackMenuItem(player, options) {
5256    _classCallCheck(this, ChaptersTrackMenuItem);
5257
5258    var track = options.track;
5259    var cue = options.cue;
5260    var currentTime = player.currentTime();
5261
5262    // Modify options for parent MenuItem class's init.
5263    options.selectable = true;
5264    options.label = cue.text;
5265    options.selected = cue.startTime <= currentTime && currentTime < cue.endTime;
5266
5267    var _this = _possibleConstructorReturn(this, _MenuItem.call(this, player, options));
5268
5269    _this.track = track;
5270    _this.cue = cue;
5271    track.addEventListener('cuechange', Fn.bind(_this, _this.update));
5272    return _this;
5273  }
5274
5275  /**
5276   * This gets called when an `ChaptersTrackMenuItem` is "clicked". See
5277   * {@link ClickableComponent} for more detailed information on what a click can be.
5278   *
5279   * @param {EventTarget~Event} [event]
5280   *        The `keydown`, `tap`, or `click` event that caused this function to be
5281   *        called.
5282   *
5283   * @listens tap
5284   * @listens click
5285   */
5286
5287
5288  ChaptersTrackMenuItem.prototype.handleClick = function handleClick(event) {
5289    _MenuItem.prototype.handleClick.call(this);
5290    this.player_.currentTime(this.cue.startTime);
5291    this.update(this.cue.startTime);
5292  };
5293
5294  /**
5295   * Update chapter menu item
5296   *
5297   * @param {EventTarget~Event} [event]
5298   *        The `cuechange` event that caused this function to run.
5299   *
5300   * @listens TextTrack#cuechange
5301   */
5302
5303
5304  ChaptersTrackMenuItem.prototype.update = function update(event) {
5305    var cue = this.cue;
5306    var currentTime = this.player_.currentTime();
5307
5308    // vjs.log(currentTime, cue.startTime);
5309    this.selected(cue.startTime <= currentTime && currentTime < cue.endTime);
5310  };
5311
5312  return ChaptersTrackMenuItem;
5313}(_menuItem2['default']);
5314
5315_component2['default'].registerComponent('ChaptersTrackMenuItem', ChaptersTrackMenuItem);
5316exports['default'] = ChaptersTrackMenuItem;
5317
5318},{"48":48,"5":5,"83":83}],27:[function(_dereq_,module,exports){
5319'use strict';
5320
5321exports.__esModule = true;
5322
5323var _textTrackButton = _dereq_(30);
5324
5325var _textTrackButton2 = _interopRequireDefault(_textTrackButton);
5326
5327var _component = _dereq_(5);
5328
5329var _component2 = _interopRequireDefault(_component);
5330
5331var _fn = _dereq_(83);
5332
5333var Fn = _interopRequireWildcard(_fn);
5334
5335function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
5336
5337function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
5338
5339function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
5340
5341function _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; }
5342
5343function _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; } /**
5344                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file descriptions-button.js
5345                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
5346
5347
5348/**
5349 * The button component for toggling and selecting descriptions
5350 *
5351 * @extends TextTrackButton
5352 */
5353var DescriptionsButton = function (_TextTrackButton) {
5354  _inherits(DescriptionsButton, _TextTrackButton);
5355
5356  /**
5357   * Creates an instance of this class.
5358   *
5359   * @param {Player} player
5360   *        The `Player` that this class should be attached to.
5361   *
5362   * @param {Object} [options]
5363   *        The key/value store of player options.
5364   *
5365   * @param {Component~ReadyCallback} [ready]
5366   *        The function to call when this component is ready.
5367   */
5368  function DescriptionsButton(player, options, ready) {
5369    _classCallCheck(this, DescriptionsButton);
5370
5371    var _this = _possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready));
5372
5373    _this.el_.setAttribute('aria-label', 'Descriptions Menu');
5374
5375    var tracks = player.textTracks();
5376
5377    if (tracks) {
5378      var changeHandler = Fn.bind(_this, _this.handleTracksChange);
5379
5380      tracks.addEventListener('change', changeHandler);
5381      _this.on('dispose', function () {
5382        tracks.removeEventListener('change', changeHandler);
5383      });
5384    }
5385    return _this;
5386  }
5387
5388  /**
5389   * Handle text track change
5390   *
5391   * @param {EventTarget~Event} event
5392   *        The event that caused this function to run
5393   *
5394   * @listens TextTrackList#change
5395   */
5396
5397
5398  DescriptionsButton.prototype.handleTracksChange = function handleTracksChange(event) {
5399    var tracks = this.player().textTracks();
5400    var disabled = false;
5401
5402    // Check whether a track of a different kind is showing
5403    for (var i = 0, l = tracks.length; i < l; i++) {
5404      var track = tracks[i];
5405
5406      if (track.kind !== this.kind_ && track.mode === 'showing') {
5407        disabled = true;
5408        break;
5409      }
5410    }
5411
5412    // If another track is showing, disable this menu button
5413    if (disabled) {
5414      this.disable();
5415    } else {
5416      this.enable();
5417    }
5418  };
5419
5420  /**
5421   * Builds the default DOM `className`.
5422   *
5423   * @return {string}
5424   *         The DOM `className` for this object.
5425   */
5426
5427
5428  DescriptionsButton.prototype.buildCSSClass = function buildCSSClass() {
5429    return 'vjs-descriptions-button ' + _TextTrackButton.prototype.buildCSSClass.call(this);
5430  };
5431
5432  return DescriptionsButton;
5433}(_textTrackButton2['default']);
5434
5435/**
5436 * `kind` of TextTrack to look for to associate it with this menu.
5437 *
5438 * @type {string}
5439 * @private
5440 */
5441
5442
5443DescriptionsButton.prototype.kind_ = 'descriptions';
5444
5445/**
5446 * The text that should display over the `DescriptionsButton`s controls. Added for localization.
5447 *
5448 * @type {string}
5449 * @private
5450 */
5451DescriptionsButton.prototype.controlText_ = 'Descriptions';
5452
5453_component2['default'].registerComponent('DescriptionsButton', DescriptionsButton);
5454exports['default'] = DescriptionsButton;
5455
5456},{"30":30,"5":5,"83":83}],28:[function(_dereq_,module,exports){
5457'use strict';
5458
5459exports.__esModule = true;
5460
5461var _textTrackMenuItem = _dereq_(31);
5462
5463var _textTrackMenuItem2 = _interopRequireDefault(_textTrackMenuItem);
5464
5465var _component = _dereq_(5);
5466
5467var _component2 = _interopRequireDefault(_component);
5468
5469function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
5470
5471function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
5472
5473function _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; }
5474
5475function _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; } /**
5476                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file off-text-track-menu-item.js
5477                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
5478
5479
5480/**
5481 * A special menu item for turning of a specific type of text track
5482 *
5483 * @extends TextTrackMenuItem
5484 */
5485var OffTextTrackMenuItem = function (_TextTrackMenuItem) {
5486  _inherits(OffTextTrackMenuItem, _TextTrackMenuItem);
5487
5488  /**
5489   * Creates an instance of this class.
5490   *
5491   * @param {Player} player
5492   *        The `Player` that this class should be attached to.
5493   *
5494   * @param {Object} [options]
5495   *        The key/value store of player options.
5496   */
5497  function OffTextTrackMenuItem(player, options) {
5498    _classCallCheck(this, OffTextTrackMenuItem);
5499
5500    // Create pseudo track info
5501    // Requires options['kind']
5502    options.track = {
5503      player: player,
5504      kind: options.kind,
5505      label: options.kind + ' off',
5506      'default': false,
5507      mode: 'disabled'
5508    };
5509
5510    // MenuItem is selectable
5511    options.selectable = true;
5512
5513    var _this = _possibleConstructorReturn(this, _TextTrackMenuItem.call(this, player, options));
5514
5515    _this.selected(true);
5516    return _this;
5517  }
5518
5519  /**
5520   * Handle text track change
5521   *
5522   * @param {EventTarget~Event} event
5523   *        The event that caused this function to run
5524   */
5525
5526
5527  OffTextTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) {
5528    var tracks = this.player().textTracks();
5529    var selected = true;
5530
5531    for (var i = 0, l = tracks.length; i < l; i++) {
5532      var track = tracks[i];
5533
5534      if (track.kind === this.track.kind && track.mode === 'showing') {
5535        selected = false;
5536        break;
5537      }
5538    }
5539
5540    this.selected(selected);
5541  };
5542
5543  return OffTextTrackMenuItem;
5544}(_textTrackMenuItem2['default']);
5545
5546_component2['default'].registerComponent('OffTextTrackMenuItem', OffTextTrackMenuItem);
5547exports['default'] = OffTextTrackMenuItem;
5548
5549},{"31":31,"5":5}],29:[function(_dereq_,module,exports){
5550'use strict';
5551
5552exports.__esModule = true;
5553
5554var _textTrackButton = _dereq_(30);
5555
5556var _textTrackButton2 = _interopRequireDefault(_textTrackButton);
5557
5558var _component = _dereq_(5);
5559
5560var _component2 = _interopRequireDefault(_component);
5561
5562function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
5563
5564function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
5565
5566function _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; }
5567
5568function _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; } /**
5569                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file subtitles-button.js
5570                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
5571
5572
5573/**
5574 * The button component for toggling and selecting subtitles
5575 *
5576 * @extends TextTrackButton
5577 */
5578var SubtitlesButton = function (_TextTrackButton) {
5579  _inherits(SubtitlesButton, _TextTrackButton);
5580
5581  /**
5582   * Creates an instance of this class.
5583   *
5584   * @param {Player} player
5585   *        The `Player` that this class should be attached to.
5586   *
5587   * @param {Object} [options]
5588   *        The key/value store of player options.
5589   *
5590   * @param {Component~ReadyCallback} [ready]
5591   *        The function to call when this component is ready.
5592   */
5593  function SubtitlesButton(player, options, ready) {
5594    _classCallCheck(this, SubtitlesButton);
5595
5596    var _this = _possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready));
5597
5598    _this.el_.setAttribute('aria-label', 'Subtitles Menu');
5599    return _this;
5600  }
5601
5602  /**
5603   * Builds the default DOM `className`.
5604   *
5605   * @return {string}
5606   *         The DOM `className` for this object.
5607   */
5608
5609
5610  SubtitlesButton.prototype.buildCSSClass = function buildCSSClass() {
5611    return 'vjs-subtitles-button ' + _TextTrackButton.prototype.buildCSSClass.call(this);
5612  };
5613
5614  return SubtitlesButton;
5615}(_textTrackButton2['default']);
5616
5617/**
5618 * `kind` of TextTrack to look for to associate it with this menu.
5619 *
5620 * @type {string}
5621 * @private
5622 */
5623
5624
5625SubtitlesButton.prototype.kind_ = 'subtitles';
5626
5627/**
5628 * The text that should display over the `SubtitlesButton`s controls. Added for localization.
5629 *
5630 * @type {string}
5631 * @private
5632 */
5633SubtitlesButton.prototype.controlText_ = 'Subtitles';
5634
5635_component2['default'].registerComponent('SubtitlesButton', SubtitlesButton);
5636exports['default'] = SubtitlesButton;
5637
5638},{"30":30,"5":5}],30:[function(_dereq_,module,exports){
5639'use strict';
5640
5641exports.__esModule = true;
5642
5643var _trackButton = _dereq_(36);
5644
5645var _trackButton2 = _interopRequireDefault(_trackButton);
5646
5647var _component = _dereq_(5);
5648
5649var _component2 = _interopRequireDefault(_component);
5650
5651var _textTrackMenuItem = _dereq_(31);
5652
5653var _textTrackMenuItem2 = _interopRequireDefault(_textTrackMenuItem);
5654
5655var _offTextTrackMenuItem = _dereq_(28);
5656
5657var _offTextTrackMenuItem2 = _interopRequireDefault(_offTextTrackMenuItem);
5658
5659function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
5660
5661function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
5662
5663function _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; }
5664
5665function _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, { c
5665onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
5666                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file text-track-button.js
5667                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
5668
5669
5670/**
5671 * The base class for buttons that toggle specific text track types (e.g. subtitles)
5672 *
5673 * @extends MenuButton
5674 */
5675var TextTrackButton = function (_TrackButton) {
5676  _inherits(TextTrackButton, _TrackButton);
5677
5678  /**
5679   * Creates an instance of this class.
5680   *
5681   * @param {Player} player
5682   *        The `Player` that this class should be attached to.
5683   *
5684   * @param {Object} [options={}]
5685   *        The key/value store of player options.
5686   */
5687  function TextTrackButton(player) {
5688    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
5689
5690    _classCallCheck(this, TextTrackButton);
5691
5692    options.tracks = player.textTracks();
5693
5694    return _possibleConstructorReturn(this, _TrackButton.call(this, player, options));
5695  }
5696
5697  /**
5698   * Create a menu item for each text track
5699   *
5700   * @param {TextTrackMenuItem[]} [items=[]]
5701   *        Existing array of items to use during creation
5702   *
5703   * @return {TextTrackMenuItem[]}
5704   *         Array of menu items that were created
5705   */
5706
5707
5708  TextTrackButton.prototype.createItems = function createItems() {
5709    var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
5710
5711    // Add an OFF menu item to turn all tracks off
5712    items.push(new _offTextTrackMenuItem2['default'](this.player_, { kind: this.kind_ }));
5713    this.hideThreshold_ += 1;
5714
5715    var tracks = this.player_.textTracks();
5716
5717    if (!tracks) {
5718      return items;
5719    }
5720
5721    for (var i = 0; i < tracks.length; i++) {
5722      var track = tracks[i];
5723
5724      // only add tracks that are of the appropriate kind and have a label
5725      if (track.kind === this.kind_) {
5726        items.push(new _textTrackMenuItem2['default'](this.player_, {
5727          track: track,
5728          // MenuItem is selectable
5729          selectable: true
5730        }));
5731      }
5732    }
5733
5734    return items;
5735  };
5736
5737  return TextTrackButton;
5738}(_trackButton2['default']);
5739
5740_component2['default'].registerComponent('TextTrackButton', TextTrackButton);
5741exports['default'] = TextTrackButton;
5742
5743},{"28":28,"31":31,"36":36,"5":5}],31:[function(_dereq_,module,exports){
5744'use strict';
5745
5746exports.__esModule = true;
5747
5748var _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; };
5749
5750var _menuItem = _dereq_(48);
5751
5752var _menuItem2 = _interopRequireDefault(_menuItem);
5753
5754var _component = _dereq_(5);
5755
5756var _component2 = _interopRequireDefault(_component);
5757
5758var _fn = _dereq_(83);
5759
5760var Fn = _interopRequireWildcard(_fn);
5761
5762var _window = _dereq_(95);
5763
5764var _window2 = _interopRequireDefault(_window);
5765
5766var _document = _dereq_(94);
5767
5768var _document2 = _interopRequireDefault(_document);
5769
5770function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
5771
5772function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
5773
5774function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
5775
5776function _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; }
5777
5778function _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, { c
5778onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
5779                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file text-track-menu-item.js
5780                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
5781
5782
5783/**
5784 * The specific menu item type for selecting a language within a text track kind
5785 *
5786 * @extends MenuItem
5787 */
5788var TextTrackMenuItem = function (_MenuItem) {
5789  _inherits(TextTrackMenuItem, _MenuItem);
5790
5791  /**
5792   * Creates an instance of this class.
5793   *
5794   * @param {Player} player
5795   *        The `Player` that this class should be attached to.
5796   *
5797   * @param {Object} [options]
5798   *        The key/value store of player options.
5799   */
5800  function TextTrackMenuItem(player, options) {
5801    _classCallCheck(this, TextTrackMenuItem);
5802
5803    var track = options.track;
5804    var tracks = player.textTracks();
5805
5806    // Modify options for parent MenuItem class's init.
5807    options.label = track.label || track.language || 'Unknown';
5808    options.selected = track['default'] || track.mode === 'showing';
5809
5810    var _this = _possibleConstructorReturn(this, _MenuItem.call(this, player, options));
5811
5812    _this.track = track;
5813
5814    if (tracks) {
5815      var changeHandler = Fn.bind(_this, _this.handleTracksChange);
5816
5817      player.on(['loadstart', 'texttrackchange'], changeHandler);
5818      tracks.addEventListener('change', changeHandler);
5819      _this.on('dispose', function () {
5820        tracks.removeEventListener('change', changeHandler);
5821      });
5822    }
5823
5824    // iOS7 doesn't dispatch change events to TextTrackLists when an
5825    // associated track's mode changes. Without something like
5826    // Object.observe() (also not present on iOS7), it's not
5827    // possible to detect changes to the mode attribute and polyfill
5828    // the change event. As a poor substitute, we manually dispatch
5829    // change events whenever the controls modify the mode.
5830    if (tracks && tracks.onchange === undefined) {
5831      var event = void 0;
5832
5833      _this.on(['tap', 'click'], function () {
5834        if (_typeof(_window2['default'].Event) !== 'object') {
5835          // Android 2.3 throws an Illegal Constructor error for window.Event
5836          try {
5837            event = new _window2['default'].Event('change');
5838          } catch (err) {
5839            // continue regardless of error
5840          }
5841        }
5842
5843        if (!event) {
5844          event = _document2['default'].createEvent('Event');
5845          event.initEvent('change', true, true);
5846        }
5847
5848        tracks.dispatchEvent(event);
5849      });
5850    }
5851    return _this;
5852  }
5853
5854  /**
5855   * This gets called when an `TextTrackMenuItem` is "clicked". See
5856   * {@link ClickableComponent} for more detailed information on what a click can be.
5857   *
5858   * @param {EventTarget~Event} event
5859   *        The `keydown`, `tap`, or `click` event that caused this function to be
5860   *        called.
5861   *
5862   * @listens tap
5863   * @listens click
5864   */
5865
5866
5867  TextTrackMenuItem.prototype.handleClick = function handleClick(event) {
5868    var kind = this.track.kind;
5869    var tracks = this.player_.textTracks();
5870
5871    _MenuItem.prototype.handleClick.call(this, event);
5872
5873    if (!tracks) {
5874      return;
5875    }
5876
5877    for (var i = 0; i < tracks.length; i++) {
5878      var track = tracks[i];
5879
5880      if (track.kind !== kind) {
5881        continue;
5882      }
5883
5884      if (track === this.track) {
5885        if (track.mode !== 'showing') {
5886          track.mode = 'showing';
5887        }
5888      } else if (track.mode !== 'disabled') {
5889        track.mode = 'disabled';
5890      }
5891    }
5892  };
5893
5894  /**
5895   * Handle text track list change
5896   *
5897   * @param {EventTarget~Event} event
5898   *        The `change` event that caused this function to be called.
5899   *
5900   * @listens TextTrackList#change
5901   */
5902
5903
5904  TextTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) {
5905    this.selected(this.track.mode === 'showing');
5906  };
5907
5908  return TextTrackMenuItem;
5909}(_menuItem2['default']);
5910
5911_component2['default'].registerComponent('TextTrackMenuItem', TextTrackMenuItem);
5912exports['default'] = TextTrackMenuItem;
5913
5914},{"48":48,"5":5,"83":83,"94":94,"95":95}],32:[function(_dereq_,module,exports){
5915'use strict';
5916
5917exports.__esModule = true;
5918
5919var _component = _dereq_(5);
5920
5921var _component2 = _interopRequireDefault(_component);
5922
5923var _dom = _dereq_(81);
5924
5925var Dom = _interopRequireWildcard(_dom);
5926
5927var _formatTime = _dereq_(84);
5928
5929var _formatTime2 = _interopRequireDefault(_formatTime);
5930
5931function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
5932
5933function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
5934
5935function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
5936
5937function _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; }
5938
5939function _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, { c
5939onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
5940                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file current-time-display.js
5941                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
5942
5943
5944/**
5945 * Displays the current time
5946 *
5947 * @extends Component
5948 */
5949var CurrentTimeDisplay = function (_Component) {
5950  _inherits(CurrentTimeDisplay, _Component);
5951
5952  /**
5953   * Creates an instance of this class.
5954   *
5955   * @param {Player} player
5956   *        The `Player` that this class should be attached to.
5957   *
5958   * @param {Object} [options]
5959   *        The key/value store of player options.
5960   */
5961  function CurrentTimeDisplay(player, options) {
5962    _classCallCheck(this, CurrentTimeDisplay);
5963
5964    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
5965
5966    _this.on(player, 'timeupdate', _this.updateContent);
5967    return _this;
5968  }
5969
5970  /**
5971   * Create the `Component`'s DOM element
5972   *
5973   * @return {Element}
5974   *         The element that was created.
5975   */
5976
5977
5978  CurrentTimeDisplay.prototype.createEl = function createEl() {
5979    var el = _Component.prototype.createEl.call(this, 'div', {
5980      className: 'vjs-current-time vjs-time-control vjs-control'
5981    });
5982
5983    this.contentEl_ = Dom.createEl('div', {
5984      className: 'vjs-current-time-display',
5985      // label the current time for screen reader users
5986      innerHTML: '<span class="vjs-control-text">Current Time </span>' + '0:00'
5987    }, {
5988      // tell screen readers not to automatically read the time as it changes
5989      'aria-live': 'off'
5990    });
5991
5992    el.appendChild(this.contentEl_);
5993    return el;
5994  };
5995
5996  /**
5997   * Update current time display
5998   *
5999   * @param {EventTarget~Event} [event]
6000   *        The `timeupdate` event that caused this function to run.
6001   *
6002   * @listens Player#timeupdate
6003   */
6004
6005
6006  CurrentTimeDisplay.prototype.updateContent = function updateContent(event) {
6007    // Allows for smooth scrubbing, when player can't keep up.
6008    var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();
6009    var localizedText = this.localize('Current Time');
6010    var formattedTime = (0, _formatTime2['default'])(time, this.player_.duration());
6011
6012    if (formattedTime !== this.formattedTime_) {
6013      this.formattedTime_ = formattedTime;
6014      this.contentEl_.innerHTML = '<span class="vjs-control-text">' + localizedText + '</span> ' + formattedTime;
6015    }
6016  };
6017
6018  return CurrentTimeDisplay;
6019}(_component2['default']);
6020
6021_component2['default'].registerComponent('CurrentTimeDisplay', CurrentTimeDisplay);
6022exports['default'] = CurrentTimeDisplay;
6023
6024},{"5":5,"81":81,"84":84}],33:[function(_dereq_,module,exports){
6025'use strict';
6026
6027exports.__esModule = true;
6028
6029var _component = _dereq_(5);
6030
6031var _component2 = _interopRequireDefault(_component);
6032
6033var _dom = _dereq_(81);
6034
6035var Dom = _interopRequireWildcard(_dom);
6036
6037var _formatTime = _dereq_(84);
6038
6039var _formatTime2 = _interopRequireDefault(_formatTime);
6040
6041function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
6042
6043function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
6044
6045function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6046
6047function _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; }
6048
6049function _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, { c
6049onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
6050                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file duration-display.js
6051                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
6052
6053
6054/**
6055 * Displays the duration
6056 *
6057 * @extends Component
6058 */
6059var DurationDisplay = function (_Component) {
6060  _inherits(DurationDisplay, _Component);
6061
6062  /**
6063   * Creates an instance of this class.
6064   *
6065   * @param {Player} player
6066   *        The `Player` that this class should be attached to.
6067   *
6068   * @param {Object} [options]
6069   *        The key/value store of player options.
6070   */
6071  function DurationDisplay(player, options) {
6072    _classCallCheck(this, DurationDisplay);
6073
6074    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
6075
6076    _this.on(player, 'durationchange', _this.updateContent);
6077
6078    // Also listen for timeupdate and loadedmetadata because removing those
6079    // listeners could have broken dependent applications/libraries. These
6080    // can likely be removed for 6.0.
6081    _this.on(player, 'timeupdate', _this.updateContent);
6082    _this.on(player, 'loadedmetadata', _this.updateContent);
6083    return _this;
6084  }
6085
6086  /**
6087   * Create the `Component`'s DOM element
6088   *
6089   * @return {Element}
6090   *         The element that was created.
6091   */
6092
6093
6094  DurationDisplay.prototype.createEl = function createEl() {
6095    var el = _Component.prototype.createEl.call(this, 'div', {
6096      className: 'vjs-duration vjs-time-control vjs-control'
6097    });
6098
6099    this.contentEl_ = Dom.createEl('div', {
6100      className: 'vjs-duration-display',
6101      // label the duration time for screen reader users
6102      innerHTML: '<span class="vjs-control-text">' + this.localize('Duration Time') + '</span> 0:00'
6103    }, {
6104      // tell screen readers not to automatically read the time as it changes
6105      'aria-live': 'off'
6106    });
6107
6108    el.appendChild(this.contentEl_);
6109    return el;
6110  };
6111
6112  /**
6113   * Update duration time display.
6114   *
6115   * @param {EventTarget~Event} [event]
6116   *        The `durationchange`, `timeupdate`, or `loadedmetadata` event that caused
6117   *        this function to be called.
6118   *
6119   * @listens Player#durationchange
6120   * @listens Player#timeupdate
6121   * @listens Player#loadedmetadata
6122   */
6123
6124
6125  DurationDisplay.prototype.updateContent = function updateContent(event) {
6126    var duration = this.player_.duration();
6127
6128    if (duration && this.duration_ !== duration) {
6129      this.duration_ = duration;
6130      var localizedText = this.localize('Duration Time');
6131      var formattedTime = (0, _formatTime2['default'])(duration);
6132
6133      // label the duration time for screen reader users
6134      this.contentEl_.innerHTML = '<span class="vjs-control-text">' + localizedText + '</span> ' + formattedTime;
6135    }
6136  };
6137
6138  return DurationDisplay;
6139}(_component2['default']);
6140
6141_component2['default'].registerComponent('DurationDisplay', DurationDisplay);
6142exports['default'] = DurationDisplay;
6143
6144},{"5":5,"81":81,"84":84}],34:[function(_dereq_,module,exports){
6145'use strict';
6146
6147exports.__esModule = true;
6148
6149var _component = _dereq_(5);
6150
6151var _component2 = _interopRequireDefault(_component);
6152
6153var _dom = _dereq_(81);
6154
6155var Dom = _interopRequireWildcard(_dom);
6156
6157var _formatTime = _dereq_(84);
6158
6159var _formatTime2 = _interopRequireDefault(_formatTime);
6160
6161function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
6162
6163function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
6164
6165function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6166
6167function _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; }
6168
6169function _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, { c
6169onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
6170                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file remaining-time-display.js
6171                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
6172
6173
6174/**
6175 * Displays the time left in the video
6176 *
6177 * @extends Component
6178 */
6179var RemainingTimeDisplay = function (_Component) {
6180  _inherits(RemainingTimeDisplay, _Component);
6181
6182  /**
6183   * Creates an instance of this class.
6184   *
6185   * @param {Player} player
6186   *        The `Player` that this class should be attached to.
6187   *
6188   * @param {Object} [options]
6189   *        The key/value store of player options.
6190   */
6191  function RemainingTimeDisplay(player, options) {
6192    _classCallCheck(this, RemainingTimeDisplay);
6193
6194    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
6195
6196    _this.on(player, 'timeupdate', _this.updateContent);
6197    _this.on(player, 'durationchange', _this.updateContent);
6198    return _this;
6199  }
6200
6201  /**
6202   * Create the `Component`'s DOM element
6203   *
6204   * @return {Element}
6205   *         The element that was created.
6206   */
6207
6208
6209  RemainingTimeDisplay.prototype.createEl = function createEl() {
6210    var el = _Component.prototype.createEl.call(this, 'div', {
6211      className: 'vjs-remaining-time vjs-time-control vjs-control'
6212    });
6213
6214    this.contentEl_ = Dom.createEl('div', {
6215      className: 'vjs-remaining-time-display',
6216      // label the remaining time for screen reader users
6217      innerHTML: '<span class="vjs-control-text">' + this.localize('Remaining Time') + '</span> -0:00'
6218    }, {
6219      // tell screen readers not to automatically read the time as it changes
6220      'aria-live': 'off'
6221    });
6222
6223    el.appendChild(this.contentEl_);
6224    return el;
6225  };
6226
6227  /**
6228   * Update remaining time display.
6229   *
6230   * @param {EventTarget~Event} [event]
6231   *        The `timeupdate` or `durationchange` event that caused this to run.
6232   *
6233   * @listens Player#timeupdate
6234   * @listens Player#durationchange
6235   */
6236
6237
6238  RemainingTimeDisplay.prototype.updateContent = function updateContent(event) {
6239    if (this.player_.duration()) {
6240      var localizedText = this.localize('Remaining Time');
6241      var formattedTime = (0, _formatTime2['default'])(this.player_.remainingTime());
6242
6243      if (formattedTime !== this.formattedTime_) {
6244        this.formattedTime_ = formattedTime;
6245        this.contentEl_.innerHTML = '<span class="vjs-control-text">' + localizedText + '</span> -' + formattedTime;
6246      }
6247    }
6248
6249    // Allows for smooth scrubbing, when player can't keep up.
6250    // var time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime();
6251    // this.contentEl_.innerHTML = vjs.formatTime(time, this.player_.duration());
6252  };
6253
6254  return RemainingTimeDisplay;
6255}(_component2['default']);
6256
6257_component2['default'].registerComponent('RemainingTimeDisplay', RemainingTimeDisplay);
6258exports['default'] = RemainingTimeDisplay;
6259
6260},{"5":5,"81":81,"84":84}],35:[function(_dereq_,module,exports){
6261'use strict';
6262
6263exports.__esModule = true;
6264
6265var _component = _dereq_(5);
6266
6267var _component2 = _interopRequireDefault(_component);
6268
6269function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
6270
6271function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6272
6273function _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; }
6274
6275function _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, { c
6275onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
6276                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file time-divider.js
6277                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
6278
6279
6280/**
6281 * The separator between the current time and duration.
6282 * Can be hidden if it's not needed in the design.
6283 *
6284 * @extends Component
6285 */
6286var TimeDivider = function (_Component) {
6287  _inherits(TimeDivider, _Component);
6288
6289  function TimeDivider() {
6290    _classCallCheck(this, TimeDivider);
6291
6292    return _possibleConstructorReturn(this, _Component.apply(this, arguments));
6293  }
6294
6295  /**
6296   * Create the component's DOM element
6297   *
6298   * @return {Element}
6299   *         The element that was created.
6300   */
6301  TimeDivider.prototype.createEl = function createEl() {
6302    return _Component.prototype.createEl.call(this, 'div', {
6303      className: 'vjs-time-control vjs-time-divider',
6304      innerHTML: '<div><span>/</span></div>'
6305    });
6306  };
6307
6308  return TimeDivider;
6309}(_component2['default']);
6310
6311_component2['default'].registerComponent('TimeDivider', TimeDivider);
6312exports['default'] = TimeDivider;
6313
6314},{"5":5}],36:[function(_dereq_,module,exports){
6315'use strict';
6316
6317exports.__esModule = true;
6318
6319var _menuButton = _dereq_(47);
6320
6321var _menuButton2 = _interopRequireDefault(_menuButton);
6322
6323var _component = _dereq_(5);
6324
6325var _component2 = _interopRequireDefault(_component);
6326
6327var _fn = _dereq_(83);
6328
6329var Fn = _interopRequireWildcard(_fn);
6330
6331function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
6332
6333function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
6334
6335function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6336
6337function _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; }
6338
6339function _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; } /**
6340                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file track-button.js
6341                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
6342
6343
6344/**
6345 * The base class for buttons that toggle specific  track types (e.g. subtitles).
6346 *
6347 * @extends MenuButton
6348 */
6349var TrackButton = function (_MenuButton) {
6350  _inherits(TrackButton, _MenuButton);
6351
6352  /**
6353   * Creates an instance of this class.
6354   *
6355   * @param {Player} player
6356   *        The `Player` that this class should be attached to.
6357   *
6358   * @param {Object} [options]
6359   *        The key/value store of player options.
6360   */
6361  function TrackButton(player, options) {
6362    _classCallCheck(this, TrackButton);
6363
6364    var tracks = options.tracks;
6365
6366    var _this = _possibleConstructorReturn(this, _MenuButton.call(this, player, options));
6367
6368    if (_this.items.length <= 1) {
6369      _this.hide();
6370    }
6371
6372    if (!tracks) {
6373      return _possibleConstructorReturn(_this);
6374    }
6375
6376    var updateHandler = Fn.bind(_this, _this.update);
6377
6378    tracks.addEventListener('removetrack', updateHandler);
6379    tracks.addEventListener('addtrack', updateHandler);
6380
6381    _this.player_.on('dispose', function () {
6382      tracks.removeEventListener('removetrack', updateHandler);
6383      tracks.removeEventListener('addtrack', updateHandler);
6384    });
6385    return _this;
6386  }
6387
6388  return TrackButton;
6389}(_menuButton2['default']);
6390
6391_component2['default'].registerComponent('TrackButton', TrackButton);
6392exports['default'] = TrackButton;
6393
6394},{"47":47,"5":5,"83":83}],37:[function(_dereq_,module,exports){
6395'use strict';
6396
6397exports.__esModule = true;
6398
6399var _slider = _dereq_(57);
6400
6401var _slider2 = _interopRequireDefault(_slider);
6402
6403var _component = _dereq_(5);
6404
6405var _component2 = _interopRequireDefault(_component);
6406
6407var _fn = _dereq_(83);
6408
6409var Fn = _interopRequireWildcard(_fn);
6410
6411_dereq_(39);
6412
6413function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
6414
6415function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
6416
6417function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6418
6419function _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; }
6420
6421function _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, { c
6421onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
6422                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file volume-bar.js
6423                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
6424
6425
6426// Required children
6427
6428
6429/**
6430 * The bar that contains the volume level and can be clicked on to adjust the level
6431 *
6432 * @extends Slider
6433 */
6434var VolumeBar = function (_Slider) {
6435  _inherits(VolumeBar, _Slider);
6436
6437  /**
6438   * Creates an instance of this class.
6439   *
6440   * @param {Player} player
6441   *        The `Player` that this class should be attached to.
6442   *
6443   * @param {Object} [options]
6444   *        The key/value store of player options.
6445   */
6446  function VolumeBar(player, options) {
6447    _classCallCheck(this, VolumeBar);
6448
6449    var _this = _possibleConstructorReturn(this, _Slider.call(this, player, options));
6450
6451    _this.on(player, 'volumechange', _this.updateARIAAttributes);
6452    player.ready(Fn.bind(_this, _this.updateARIAAttributes));
6453    return _this;
6454  }
6455
6456  /**
6457   * Create the `Component`'s DOM element
6458   *
6459   * @return {Element}
6460   *         The element that was created.
6461   */
6462
6463
6464  VolumeBar.prototype.createEl = function createEl() {
6465    return _Slider.prototype.createEl.call(this, 'div', {
6466      className: 'vjs-volume-bar vjs-slider-bar'
6467    }, {
6468      'aria-label': 'volume level'
6469    });
6470  };
6471
6472  /**
6473   * Handle movement events on the {@link VolumeMenuButton}.
6474   *
6475   * @param {EventTarget~Event} event
6476   *        The event that caused this function to run.
6477   *
6478   * @listens mousemove
6479   */
6480
6481
6482  VolumeBar.prototype.handleMouseMove = function handleMouseMove(event) {
6483    this.checkMuted();
6484    this.player_.volume(this.calculateDistance(event));
6485  };
6486
6487  /**
6488   * If the player is muted unmute it.
6489   */
6490
6491
6492  VolumeBar.prototype.checkMuted = function checkMuted() {
6493    if (this.player_.muted()) {
6494      this.player_.muted(false);
6495    }
6496  };
6497
6498  /**
6499   * Get percent of volume level
6500   *
6501   * @return {number}
6502   *         Volume level percent as a decimal number.
6503   */
6504
6505
6506  VolumeBar.prototype.getPercent = function getPercent() {
6507    if (this.player_.muted()) {
6508      return 0;
6509    }
6510    return this.player_.volume();
6511  };
6512
6513  /**
6514   * Increase volume level for keyboard users
6515   */
6516
6517
6518  VolumeBar.prototype.stepForward = function stepForward() {
6519    this.checkMuted();
6520    this.player_.volume(this.player_.volume() + 0.1);
6521  };
6522
6523  /**
6524   * Decrease volume level for keyboard users
6525   */
6526
6527
6528  VolumeBar.prototype.stepBack = function stepBack() {
6529    this.checkMuted();
6530    this.player_.volume(this.player_.volume() - 0.1);
6531  };
6532
6533  /**
6534   * Update ARIA accessibility attributes
6535   *
6536   * @param {EventTarget~Event} [event]
6537   *        The `volumechange` event that caused this function to run.
6538   *
6539   * @listens Player#volumechange
6540   */
6541
6542
6543  VolumeBar.prototype.updateARIAAttributes = function updateARIAAttributes(event) {
6544    // Current value of volume bar as a percentage
6545    var volume = (this.player_.volume() * 100).toFixed(2);
6546
6547    this.el_.setAttribute('aria-valuenow', volume);
6548    this.el_.setAttribute('aria-valuetext', volume + '%');
6549  };
6550
6551  return VolumeBar;
6552}(_slider2['default']);
6553
6554/**
6555 * Default options for the `VolumeBar`
6556 *
6557 * @type {Object}
6558 * @private
6559 */
6560
6561
6562VolumeBar.prototype.options_ = {
6563  children: ['volumeLevel'],
6564  barName: 'volumeLevel'
6565};
6566
6567/**
6568 * Call the update event for this Slider when this event happens on the player.
6569 *
6570 * @type {string}
6571 */
6572VolumeBar.prototype.playerEvent = 'volumechange';
6573
6574_component2['default'].registerComponent('VolumeBar', VolumeBar);
6575exports['default'] = VolumeBar;
6576
6577},{"39":39,"5":5,"57":57,"83":83}],38:[function(_dereq_,module,exports){
6578'use strict';
6579
6580exports.__esModule = true;
6581
6582var _component = _dereq_(5);
6583
6584var _component2 = _interopRequireDefault(_component);
6585
6586_dereq_(37);
6587
6588function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
6589
6590function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6591
6592function _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; }
6593
6594function _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, { c
6594onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
6595                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file volume-control.js
6596                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
6597
6598
6599// Required children
6600
6601
6602/**
6603 * The component for controlling the volume level
6604 *
6605 * @extends Component
6606 */
6607var VolumeControl = function (_Component) {
6608  _inherits(VolumeControl, _Component);
6609
6610  /**
6611   * Creates an instance of this class.
6612   *
6613   * @param {Player} player
6614   *        The `Player` that this class should be attached to.
6615   *
6616   * @param {Object} [options={}]
6617   *        The key/value store of player options.
6618   */
6619  function VolumeControl(player, options) {
6620    _classCallCheck(this, VolumeControl);
6621
6622    // hide volume controls when they're not supported by the current tech
6623    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
6624
6625    if (player.tech_ && player.tech_.featuresVolumeControl === false) {
6626      _this.addClass('vjs-hidden');
6627    }
6628    _this.on(player, 'loadstart', function () {
6629      if (player.tech_.featuresVolumeControl === false) {
6630        this.addClass('vjs-hidden');
6631      } else {
6632        this.removeClass('vjs-hidden');
6633      }
6634    });
6635    return _this;
6636  }
6637
6638  /**
6639   * Create the `Component`'s DOM element
6640   *
6641   * @return {Element}
6642   *         The element that was created.
6643   */
6644
6645
6646  VolumeControl.prototype.createEl = function createEl() {
6647    return _Component.prototype.createEl.call(this, 'div', {
6648      className: 'vjs-volume-control vjs-control'
6649    });
6650  };
6651
6652  return VolumeControl;
6653}(_component2['default']);
6654
6655/**
6656 * Default options for the `VolumeControl`
6657 *
6658 * @type {Object}
6659 * @private
6660 */
6661
6662
6663VolumeControl.prototype.options_ = {
6664  children: ['volumeBar']
6665};
6666
6667_component2['default'].registerComponent('VolumeControl', VolumeControl);
6668exports['default'] = VolumeControl;
6669
6670},{"37":37,"5":5}],39:[function(_dereq_,module,exports){
6671'use strict';
6672
6673exports.__esModule = true;
6674
6675var _component = _dereq_(5);
6676
6677var _component2 = _interopRequireDefault(_component);
6678
6679function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
6680
6681function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6682
6683function _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; }
6684
6685function _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; } /**
6686                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file volume-level.js
6687                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
6688
6689
6690/**
6691 * Shows volume level
6692 *
6693 * @extends Component
6694 */
6695var VolumeLevel = function (_Component) {
6696  _inherits(VolumeLevel, _Component);
6697
6698  function VolumeLevel() {
6699    _classCallCheck(this, VolumeLevel);
6700
6701    return _possibleConstructorReturn(this, _Component.apply(this, arguments));
6702  }
6703
6704  /**
6705   * Create the `Component`'s DOM element
6706   *
6707   * @return {Element}
6708   *         The element that was created.
6709   */
6710  VolumeLevel.prototype.createEl = function createEl() {
6711    return _Component.prototype.createEl.call(this, 'div', {
6712      className: 'vjs-volume-level',
6713      innerHTML: '<span class="vjs-control-text"></span>'
6714    });
6715  };
6716
6717  return VolumeLevel;
6718}(_component2['default']);
6719
6720_component2['default'].registerComponent('VolumeLevel', VolumeLevel);
6721exports['default'] = VolumeLevel;
6722
6723},{"5":5}],40:[function(_dereq_,module,exports){
6724'use strict';
6725
6726exports.__esModule = true;
6727
6728var _fn = _dereq_(83);
6729
6730var Fn = _interopRequireWildcard(_fn);
6731
6732var _component = _dereq_(5);
6733
6734var _component2 = _interopRequireDefault(_component);
6735
6736var _popup = _dereq_(54);
6737
6738var _popup2 = _interopRequireDefault(_popup);
6739
6740var _popupButton = _dereq_(53);
6741
6742var _popupButton2 = _interopRequireDefault(_popupButton);
6743
6744var _muteToggle = _dereq_(11);
6745
6746var _muteToggle2 = _interopRequireDefault(_muteToggle);
6747
6748var _volumeBar = _dereq_(37);
6749
6750var _volumeBar2 = _interopRequireDefault(_volumeBar);
6751
6752function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
6753
6754function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
6755
6756function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6757
6758function _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; }
6759
6760function _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, { c
6760onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
6761                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file volume-menu-button.js
6762                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
6763
6764
6765/**
6766 * Button for volume popup
6767 *
6768 * @extends PopupButton
6769 */
6770var VolumeMenuButton = function (_PopupButton) {
6771  _inherits(VolumeMenuButton, _PopupButton);
6772
6773  /**
6774   * Creates an instance of this class.
6775   *
6776   * @param {Player} player
6777   *        The `Player` that this class should be attached to.
6778   *
6779   * @param {Object} [options={}]
6780   *        The key/value store of player options.
6781   */
6782  function VolumeMenuButton(player) {
6783    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6784
6785    _classCallCheck(this, VolumeMenuButton);
6786
6787    // Default to inline
6788    if (options.inline === undefined) {
6789      options.inline = true;
6790    }
6791
6792    // If the vertical option isn't passed at all, default to true.
6793    if (options.vertical === undefined) {
6794      // If an inline volumeMenuButton is used, we should default to using
6795      // a horizontal slider for obvious reasons.
6796      if (options.inline) {
6797        options.vertical = false;
6798      } else {
6799        options.vertical = true;
6800      }
6801    }
6802
6803    // The vertical option needs to be set on the volumeBar as well,
6804    // since that will need to be passed along to the VolumeBar constructor
6805    options.volumeBar = options.volumeBar || {};
6806    options.volumeBar.vertical = !!options.vertical;
6807
6808    // Same listeners as MuteToggle
6809    var _this = _possibleConstructorReturn(this, _PopupButton.call(this, player, options));
6810
6811    _this.on(player, 'volumechange', _this.volumeUpdate);
6812    _this.on(player, 'loadstart', _this.volumeUpdate);
6813
6814    // hide mute toggle if the current tech doesn't support volume control
6815    function updateVisibility() {
6816      if (player.tech_ && player.tech_.featuresVolumeControl === false) {
6817        this.addClass('vjs-hidden');
6818      } else {
6819        this.removeClass('vjs-hidden');
6820      }
6821    }
6822
6823    updateVisibility.call(_this);
6824    _this.on(player, 'loadstart', updateVisibility);
6825
6826    _this.on(_this.volumeBar, ['slideractive', 'focus'], function () {
6827      this.addClass('vjs-slider-active');
6828    });
6829
6830    _this.on(_this.volumeBar, ['sliderinactive', 'blur'], function () {
6831      this.removeClass('vjs-slider-active');
6832    });
6833
6834    _this.on(_this.volumeBar, ['focus'], function () {
6835      this.addClass('vjs-lock-showing');
6836    });
6837
6838    _this.on(_this.volumeBar, ['blur'], function () {
6839      this.removeClass('vjs-lock-showing');
6840    });
6841    return _this;
6842  }
6843
6844  /**
6845   * Builds the default DOM `className`.
6846   *
6847   * @return {string}
6848   *         The DOM `className` for this object.
6849   */
6850
6851
6852  VolumeMenuButton.prototype.buildCSSClass = function buildCSSClass() {
6853    var orientationClass = '';
6854
6855    if (this.options_.vertical) {
6856      orientationClass = 'vjs-volume-menu-button-vertical';
6857    } else {
6858      orientationClass = 'vjs-volume-menu-button-horizontal';
6859    }
6860
6861    return 'vjs-volume-menu-button ' + _PopupButton.prototype.buildCSSClass.call(this) + ' ' + orientationClass;
6862  };
6863
6864  /**
6865   * Create the VolumeMenuButton popup
6866   *
6867   * @return {Popup}
6868   *         The popup that was created
6869   */
6870
6871
6872  VolumeMenuButton.prototype.createPopup = function createPopup() {
6873    var popup = new _popup2['default'](this.player_, {
6874      contentElType: 'div'
6875    });
6876
6877    var vb = new _volumeBar2['default'](this.player_, this.options_.volumeBar);
6878
6879    popup.addChild(vb);
6880
6881    this.menuContent = popup;
6882    this.volumeBar = vb;
6883
6884    this.attachVolumeBarEvents();
6885
6886    return popup;
6887  };
6888
6889  /**
6890   * This gets called when an `VolumeMenuButton` is "clicked". See
6891   * {@link ClickableComponent} for more detailed information on what a click can be.
6892   *
6893   * @param {EventTarget~Event} [event]
6894   *        The `keydown`, `tap`, or `click` event that caused this function to be
6895   *        called.
6896   *
6897   * @listens tap
6898   * @listens click
6899   */
6900
6901
6902  VolumeMenuButton.prototype.handleClick = function handleClick(event) {
6903    _muteToggle2['default'].prototype.handleClick.call(this);
6904    _PopupButton.prototype.handleClick.call(this);
6905  };
6906
6907  /**
6908   * Add events listeners to the created `VolumeBar`.
6909   */
6910
6911
6912  VolumeMenuButton.prototype.attachVolumeBarEvents = function attachVolumeBarEvents() {
6913    this.menuContent.on(['mousedown', 'touchdown'], Fn.bind(this, this.handleMouseDown));
6914  };
6915
6916  /**
6917   * Handle the `mousedown` and `touchdown` events on the `VolumeBar`
6918   *
6919   * @param {EventTarget~Event} [event]
6920   *        The `mousedown` or `touchdown` event that caused this to run.
6921   *
6922   * @listens mousedown
6923   * @listens touchdown
6924   */
6925
6926
6927  VolumeMenuButton.prototype.handleMouseDown = function handleMouseDown(event) {
6928    this.on(['mousemove', 'touchmove'], Fn.bind(this.volumeBar, this.volumeBar.handleMouseMove));
6929    this.on(this.el_.ownerDocument, ['mouseup', 'touchend'], this.handleMouseUp);
6930  };
6931
6932  /**
6933   * Handle the `mouseup` and `touchend` events on the `VolumeBar`
6934   *
6935   * @param {EventTarget~Event} [event]
6936   *        The `mouseup` or `touchend` event that caused this to run.
6937   *
6938   * @listens mouseup
6939   * @listens touchend
6940   */
6941
6942
6943  VolumeMenuButton.prototype.handleMouseUp = function handleMouseUp(event) {
6944    this.off(['mousemove', 'touchmove'], Fn.bind(this.volumeBar, this.volumeBar.handleMouseMove));
6945  };
6946
6947  return VolumeMenuButton;
6948}(_popupButton2['default']);
6949
6950/**
6951 * @borrows MuteToggle#update as VolumeMenuButton#volumeUpdate
6952 */
6953
6954
6955VolumeMenuButton.prototype.volumeUpdate = _muteToggle2['default'].prototype.update;
6956
6957/**
6958 * The text that should display over the `VolumeMenuButton`s controls. Added for localization.
6959 *
6960 * @type {string}
6961 * @private
6962 */
6963VolumeMenuButton.prototype.controlText_ = 'Mute';
6964
6965_component2['default'].registerComponent('VolumeMenuButton', VolumeMenuButton);
6966exports['default'] = VolumeMenuButton;
6967
6968},{"11":11,"37":37,"5":5,"53":53,"54":54,"83":83}],41:[function(_dereq_,module,exports){
6969'use strict';
6970
6971exports.__esModule = true;
6972
6973var _component = _dereq_(5);
6974
6975var _component2 = _interopRequireDefault(_component);
6976
6977var _modalDialog = _dereq_(50);
6978
6979var _modalDialog2 = _interopRequireDefault(_modalDialog);
6980
6981var _mergeOptions = _dereq_(87);
6982
6983var _mergeOptions2 = _interopRequireDefault(_mergeOptions);
6984
6985function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
6986
6987function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6988
6989function _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; }
6990
6991function _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, { c
6991onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
6992                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file error-display.js
6993                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
6994
6995
6996/**
6997 * A display that indicates an error has occurred. This means that the video
6998 * is unplayable.
6999 *
7000 * @extends ModalDialog
7001 */
7002var ErrorDisplay = function (_ModalDialog) {
7003  _inherits(ErrorDisplay, _ModalDialog);
7004
7005  /**
7006   * Creates an instance of this class.
7007   *
7008   * @param  {Player} player
7009   *         The `Player` that this class should be attached to.
7010   *
7011   * @param  {Object} [options]
7012   *         The key/value store of player options.
7013   */
7014  function ErrorDisplay(player, options) {
7015    _classCallCheck(this, ErrorDisplay);
7016
7017    var _this = _possibleConstructorReturn(this, _ModalDialog.call(this, player, options));
7018
7019    _this.on(player, 'error', _this.open);
7020    return _this;
7021  }
7022
7023  /**
7024   * Builds the default DOM `className`.
7025   *
7026   * @return {string}
7027   *         The DOM `className` for this object.
7028   *
7029   * @deprecated Since version 5.
7030   */
7031
7032
7033  ErrorDisplay.prototype.buildCSSClass = function buildCSSClass() {
7034    return 'vjs-error-display ' + _ModalDialog.prototype.buildCSSClass.call(this);
7035  };
7036
7037  /**
7038   * Gets the localized error message based on the `Player`s error.
7039   *
7040   * @return {string}
7041   *         The `Player`s error message localized or an empty string.
7042   */
7043
7044
7045  ErrorDisplay.prototype.content = function content() {
7046    var error = this.player().error();
7047
7048    return error ? this.localize(error.message) : '';
7049  };
7050
7051  return ErrorDisplay;
7052}(_modalDialog2['default']);
7053
7054/**
7055 * The default options for an `ErrorDisplay`.
7056 *
7057 * @private
7058 */
7059
7060
7061ErrorDisplay.prototype.options_ = (0, _mergeOptions2['default'])(_modalDialog2['default'].prototype.options_, {
7062  pauseOnOpen: false,
7063  fillAlways: true,
7064  temporary: false,
7065  uncloseable: true
7066});
7067
7068_component2['default'].registerComponent('ErrorDisplay', ErrorDisplay);
7069exports['default'] = ErrorDisplay;
7070
7071},{"5":5,"50":50,"87":87}],42:[function(_dereq_,module,exports){
7072'use strict';
7073
7074exports.__esModule = true;
7075
7076var _events = _dereq_(82);
7077
7078var Events = _interopRequireWildcard(_events);
7079
7080function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
7081
7082/**
7083 * `EventTarget` is a class that can have the same API as the DOM `EventTarget`. It
7084 * adds shorthand functions that wrap around lengthy functions. For example:
7085 * the `on` function is a wrapper around `addEventListener`.
7086 *
7087 * @see [EventTarget Spec]{@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget}
7088 * @class EventTarget
7089 */
7090var EventTarget = function EventTarget() {};
7091
7092/**
7093 * A Custom DOM event.
7094 *
7095 * @typedef {Object} EventTarget~Event
7096 * @see [Properties]{@link https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent}
7097 */
7098
7099/**
7100 * All event listeners should follow the following format.
7101 *
7102 * @callback EventTarget~EventListener
7103 * @this {EventTarget}
7104 *
7105 * @param {EventTarget~Event} event
7106 *        the event that triggered this function
7107 *
7108 * @param {Object} [hash]
7109 *        hash of data sent during the event
7110 */
7111
7112/**
7113 * An object containing event names as keys and booleans as values.
7114 *
7115 * > NOTE: If an event name is set to a true value here {@link EventTarget#trigger}
7116 *         will have extra functionality. See that function for more information.
7117 *
7118 * @property EventTarget.prototype.allowedEvents_
7119 * @private
7120 */
7121/**
7122 * @file src/js/event-target.js
7123 */
7124EventTarget.prototype.allowedEvents_ = {};
7125
7126/**
7127 * Adds an `event listener` to an instance of an `EventTarget`. An `event listener` is a
7128 * function that will get called when an event with a certain name gets triggered.
7129 *
7130 * @param {string|string[]} type
7131 *        An event name or an array of event names.
7132 *
7133 * @param {EventTarget~EventListener} fn
7134 *        The function to call with `EventTarget`s
7135 */
7136EventTarget.prototype.on = function (type, fn) {
7137  // Remove the addEventListener alias before calling Events.on
7138  // so we don't get into an infinite type loop
7139  var ael = this.addEventListener;
7140
7141  this.addEventListener = function () {};
7142  Events.on(this, type, fn);
7143  this.addEventListener = ael;
7144};
7145
7146/**
7147 * An alias of {@link EventTarget#on}. Allows `EventTarget` to mimic
7148 * the standard DOM API.
7149 *
7150 * @function
7151 * @see {@link EventTarget#on}
7152 */
7153EventTarget.prototype.addEventListener = EventTarget.prototype.on;
7154
7155/**
7156 * Removes an `event listener` for a specific event from an instance of `EventTarget`.
7157 * This makes it so that the `event listener` will no longer get called when the
7158 * named event happens.
7159 *
7160 * @param {string|string[]} type
7161 *        An event name or an array of event names.
7162 *
7163 * @param {EventTarget~EventListener} fn
7164 *        The function to remove.
7165 */
7166EventTarget.prototype.off = function (type, fn) {
7167  Events.off(this, type, fn);
7168};
7169
7170/**
7171 * An alias of {@link EventTarget#off}. Allows `EventTarget` to mimic
7172 * the standard DOM API.
7173 *
7174 * @function
7175 * @see {@link EventTarget#off}
7176 */
7177EventTarget.prototype.removeEventListener = EventTarget.prototype.off;
7178
7179/**
7180 * This function will add an `event listener` that gets triggered only once. After the
7181 * first trigger it will get removed. This is like adding an `event listener`
7182 * with {@link EventTarget#on} that calls {@link EventTarget#off} on itself.
7183 *
7184 * @param {string|string[]} type
7185 *        An event name or an array of event names.
7186 *
7187 * @param {EventTarget~EventListener} fn
7188 *        The function to be called once for each event name.
7189 */
7190EventTarget.prototype.one = function (type, fn) {
7191  // Remove the addEventListener alialing Events.on
7192  // so we don't get into an infinite type loop
7193  var ael = this.addEventListener;
7194
7195  this.addEventListener = function () {};
7196  Events.one(this, type, fn);
7197  this.addEventListener = ael;
7198};
7199
7200/**
7201 * This function causes an event to happen. This will then cause any `event listeners`
7202 * that are waiting for that event, to get called. If there are no `event listeners`
7203 * for an event then nothing will happen.
7204 *
7205 * If the name of the `Event` that is being triggered is in `EventTarget.allowedEvents_`.
7206 * Trigger will also call the `on` + `uppercaseEventName` function.
7207 *
7208 * Example:
7209 * 'click' is in `EventTarget.allowedEvents_`, so, trigger will attempt to call
7210 * `onClick` if it exists.
7211 *
7212 * @param {string|EventTarget~Event|Object} event
7213 *        The name of the event, an `Event`, or an object with a key of type set to
7214 *        an event name.
7215 */
7216EventTarget.prototype.trigger = function (event) {
7217  var type = event.type || event;
7218
7219  if (typeof event === 'string') {
7220    event = { type: type };
7221  }
7222  event = Events.fixEvent(event);
7223
7224  if (this.allowedEvents_[type] && this['on' + type]) {
7225    this['on' + type](event);
7226  }
7227
7228  Events.trigger(this, event);
7229};
7230
7231/**
7232 * An alias of {@link EventTarget#trigger}. Allows `EventTarget` to mimic
7233 * the standard DOM API.
7234 *
7235 * @function
7236 * @see {@link EventTarget#trigger}
7237 */
7238EventTarget.prototype.dispatchEvent = EventTarget.prototype.trigger;
7239
7240exports['default'] = EventTarget;
7241
7242},{"82":82}],43:[function(_dereq_,module,exports){
7243'use strict';
7244
7245exports.__esModule = true;
7246
7247var _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; };
7248
7249var _log = _dereq_(86);
7250
7251var _log2 = _interopRequireDefault(_log);
7252
7253var _obj = _dereq_(88);
7254
7255function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
7256
7257/**
7258 * @file extend.js
7259 * @module extend
7260 */
7261
7262/**
7263 * A combination of node inherits and babel's inherits (after transpile).
7264 * Both work the same but node adds `super_` to the subClass
7265 * and Bable adds the superClass as __proto__. Both seem useful.
7266 *
7267 * @param {Object} subClass
7268 *        The class to inherit to
7269 *
7270 * @param {Object} superClass
7271 *        The class to inherit from
7272 *
7273 * @private
7274 */
7275var _inherits = function _inherits(subClass, superClass) {
7276  if (typeof superClass !== 'function' && superClass !== null) {
7277    throw new TypeError('Super expression must either be null or a function, not ' + (typeof superClass === 'undefined' ? 'undefined' : _typeof(superClass)));
7278  }
7279
7280  subClass.prototype = Object.create(superClass && superClass.prototype, {
7281    constructor: {
7282      value: subClass,
7283      enumerable: false,
7284      writable: true,
7285      configurable: true
7286    }
7287  });
7288
7289  if (superClass) {
7290    // node
7291    subClass.super_ = superClass;
7292  }
7293};
7294
7295/**
7296 * Function for subclassing using the same inheritance that
7297 * videojs uses internally
7298 *
7299 * @param {Object} superClass
7300 *        The class to inherit from
7301 *
7302 * @param {Object} [subClassMethods={}]
7303 *        The class to inherit to
7304 *
7305 * @return {Object}
7306 *         The new object with subClassMethods that inherited superClass.
7307 */
7308var extendFn = function extendFn(superClass) {
7309  var subClassMethods = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7310
7311  var subClass = function subClass() {
7312    superClass.apply(this, arguments);
7313  };
7314
7315  var methods = {};
7316
7317  if ((0, _obj.isObject)(subClassMethods)) {
7318    if (typeof subClassMethods.init === 'function') {
7319      _log2['default'].warn('Constructor logic via init() is deprecated; please use constructor() instead.');
7320      subClassMethods.constructor = subClassMethods.init;
7321    }
7322    if (subClassMethods.constructor !== Object.prototype.constructor) {
7323      subClass = subClassMethods.constructor;
7324    }
7325    methods = subClassMethods;
7326  } else if (typeof subClassMethods === 'function') {
7327    subClass = subClassMethods;
7328  }
7329
7330  _inherits(subClass, superClass);
7331
7332  // Extend subObj's prototype with functions and other properties from props
7333  for (var name in methods) {
7334    if (methods.hasOwnProperty(name)) {
7335      subClass.prototype[name] = methods[name];
7336    }
7337  }
7338
7339  return subClass;
7340};
7341
7342exports['default'] = extendFn;
7343
7344},{"86":86,"88":88}],44:[function(_dereq_,module,exports){
7345'use strict';
7346
7347exports.__esModule = true;
7348
7349var _document = _dereq_(94);
7350
7351var _document2 = _interopRequireDefault(_document);
7352
7353function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
7354
7355/**
7356 * Store the browser-specific methods for the fullscreen API.
7357 *
7358 * @type {Object}
7359 * @see [Specification]{@link https://fullscreen.spec.whatwg.org}
7360 * @see [Map Approach From Screenfull.js]{@link https://github.com/sindresorhus/screenfull.js}
7361 */
7362var FullscreenApi = {};
7363
7364// browser API methods
7365/**
7366 * @file fullscreen-api.js
7367 * @module fullscreen-api
7368 * @private
7369 */
7370var apiMap = [['requestFullscreen', 'exitFullscreen', 'fullscreenElement', 'fullscreenEnabled', 'fullscreenchange', 'fullscreenerror'],
7371// WebKit
7372['webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitFullscreenElement', 'webkitFullscreenEnabled', 'webkitfullscreenchange', 'webkitfullscreenerror'],
7373// Old WebKit (Safari 5.1)
7374['webkitRequestFullScreen', 'webkitCancelFullScreen', 'webkitCurrentFullScreenElement', 'webkitCancelFullScreen', 'webkitfullscreenchange', 'webkitfullscreenerror'],
7375// Mozilla
7376['mozRequestFullScreen', 'mozCancelFullScreen', 'mozFullScreenElement', 'mozFullScreenEnabled', 'mozfullscreenchange', 'mozfullscreenerror'],
7377// Microsoft
7378['msRequestFullscreen', 'msExitFullscreen', 'msFullscreenElement', 'msFullscreenEnabled', 'MSFullscreenChange', 'MSFullscreenError']];
7379
7380var specApi = apiMap[0];
7381var browserApi = void 0;
7382
7383// determine the supported set of functions
7384for (var i = 0; i < apiMap.length; i++) {
7385  // check for exitFullscreen function
7386  if (apiMap[i][1] in _document2['default']) {
7387    browserApi = apiMap[i];
7388    break;
7389  }
7390}
7391
7392// map the browser API names to the spec API names
7393if (browserApi) {
7394  for (var _i = 0; _i < browserApi.length; _i++) {
7395    FullscreenApi[specApi[_i]] = browserApi[_i];
7396  }
7397}
7398
7399exports['default'] = FullscreenApi;
7400
7401},{"94":94}],45:[function(_dereq_,module,exports){
7402'use strict';
7403
7404exports.__esModule = true;
7405
7406var _component = _dereq_(5);
7407
7408var _component2 = _interopRequireDefault(_component);
7409
7410function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
7411
7412function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
7413
7414function _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; }
7415
7416function _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, { c
7416onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
7417                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file loading-spinner.js
7418                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
7419
7420
7421/**
7422 * A loading spinner for use during waiting/loading events.
7423 *
7424 * @extends Component
7425 */
7426var LoadingSpinner = function (_Component) {
7427  _inherits(LoadingSpinner, _Component);
7428
7429  function LoadingSpinner() {
7430    _classCallCheck(this, LoadingSpinner);
7431
7432    return _possibleConstructorReturn(this, _Component.apply(this, arguments));
7433  }
7434
7435  /**
7436   * Create the `LoadingSpinner`s DOM element.
7437   *
7438   * @return {Element}
7439   *         The dom element that gets created.
7440   */
7441  LoadingSpinner.prototype.createEl = function createEl() {
7442    return _Component.prototype.createEl.call(this, 'div', {
7443      className: 'vjs-loading-spinner',
7444      dir: 'ltr'
7445    });
7446  };
7447
7448  return LoadingSpinner;
7449}(_component2['default']);
7450
7451_component2['default'].registerComponent('LoadingSpinner', LoadingSpinner);
7452exports['default'] = LoadingSpinner;
7453
7454},{"5":5}],46:[function(_dereq_,module,exports){
7455'use strict';
7456
7457exports.__esModule = true;
7458
7459var _obj = _dereq_(88);
7460
7461/**
7462 * A Custom `MediaError` class which mimics the standard HTML5 `MediaError` class.
7463 *
7464 * @param {number|string|Object|MediaError} value
7465 *        This can be of multiple types:
7466 *        - number: should be a standard error code
7467 *        - string: an error message (the code will be 0)
7468 *        - Object: arbitrary properties
7469 *        - `MediaError` (native): used to populate a video.js `MediaError` object
7470 *        - `MediaError` (video.js): will return itself if it's already a
7471 *          video.js `MediaError` object.
7472 *
7473 * @see [MediaError Spec]{@link https://dev.w3.org/html5/spec-author-view/video.html#mediaerror}
7474 * @see [Encrypted MediaError Spec]{@link https://www.w3.org/TR/2013/WD-encrypted-media-20130510/#error-codes}
7475 *
7476 * @class MediaError
7477 */
7478function MediaError(value) {
7479
7480  // Allow redundant calls to this constructor to avoid having `instanceof`
7481  // checks peppered around the code.
7482  if (value instanceof MediaError) {
7483    return value;
7484  }
7485
7486  if (typeof value === 'number') {
7487    this.code = value;
7488  } else if (typeof value === 'string') {
7489    // default code is zero, so this is a custom error
7490    this.message = value;
7491  } else if ((0, _obj.isObject)(value)) {
7492
7493    // We assign the `code` property manually because native `MediaError` objects
7494    // do not expose it as an own/enumerable property of the object.
7495    if (typeof value.code === 'number') {
7496      this.code = value.code;
7497    }
7498
7499    (0, _obj.assign)(this, value);
7500  }
7501
7502  if (!this.message) {
7503    this.message = MediaError.defaultMessages[this.code] || '';
7504  }
7505}
7506
7507/**
7508 * The error code that refers two one of the defined `MediaError` types
7509 *
7510 * @type {Number}
7511 */
7512/**
7513 * @file media-error.js
7514 */
7515MediaError.prototype.code = 0;
7516
7517/**
7518 * An optional message that to show with the error. Message is not part of the HTML5
7519 * video spec but allows for more informative custom errors.
7520 *
7521 * @type {String}
7522 */
7523MediaError.prototype.message = '';
7524
7525/**
7526 * An optional status code that can be set by plugins to allow even more detail about
7527 * the error. For example a plugin might provide a specific HTTP status code and an
7528 * error message for that code. Then when the plugin gets that error this class will
7529 * know how to display an error message for it. This allows a custom message to show
7530 * up on the `Player` error overlay.
7531 *
7532 * @type {Array}
7533 */
7534MediaError.prototype.status = null;
7535
7536/**
7537 * Errors indexed by the W3C standard. The order **CANNOT CHANGE**! See the
7538 * specification listed under {@link MediaError} for more information.
7539 *
7540 * @enum {array}
7541 * @readonly
7542 * @property {string} 0 - MEDIA_ERR_CUSTOM
7543 * @property {string} 1 - MEDIA_ERR_CUSTOM
7544 * @property {string} 2 - MEDIA_ERR_ABORTED
7545 * @property {string} 3 - MEDIA_ERR_NETWORK
7546 * @property {string} 4 - MEDIA_ERR_SRC_NOT_SUPPORTED
7547 * @property {string} 5 - MEDIA_ERR_ENCRYPTED
7548 */
7549MediaError.errorTypes = ['MEDIA_ERR_CUSTOM', 'MEDIA_ERR_ABORTED', 'MEDIA_ERR_NETWORK', 'MEDIA_ERR_DECODE', 'MEDIA_ERR_SRC_NOT_SUPPORTED', 'MEDIA_ERR_ENCRYPTED'];
7550
7551/**
7552 * The default `MediaError` messages based on the {@link MediaError.errorTypes}.
7553 *
7554 * @type {Array}
7555 * @constant
7556 */
7557MediaError.defaultMessages = {
7558  1: 'You aborted the media playback',
7559  2: 'A network error caused the media download to fail part-way.',
7560  3: 'The media playback was aborted due to a corruption problem or because the media used features your browser did not support.',
7561  4: 'The media could not be loaded, either because the server or network failed or because the format is not supported.',
7562  5: 'The media is encrypted and we do not have the keys to decrypt it.'
7563};
7564
7565// Add types as properties on MediaError
7566// e.g. MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = 4;
7567for (var errNum = 0; errNum < MediaError.errorTypes.length; errNum++) {
7568  MediaError[MediaError.errorTypes[errNum]] = errNum;
7569  // values should be accessible on both the class and instance
7570  MediaError.prototype[MediaError.errorTypes[errNum]] = errNum;
7571}
7572
7573// jsdocs for instance/static members added above
7574// instance methods use `#` and static methods use `.`
7575/**
7576 * W3C error code for any custom error.
7577 *
7578 * @member MediaError#MEDIA_ERR_CUSTOM
7579 * @constant {number}
7580 * @default 0
7581 */
7582/**
7583 * W3C error code for any custom error.
7584 *
7585 * @member MediaError.MEDIA_ERR_CUSTOM
7586 * @constant {number}
7587 * @default 0
7588 */
7589
7590/**
7591 * W3C error code for media error aborted.
7592 *
7593 * @member MediaError#MEDIA_ERR_ABORTED
7594 * @constant {number}
7595 * @default 1
7596 */
7597/**
7598 * W3C error code for media error aborted.
7599 *
7600 * @member MediaError.MEDIA_ERR_ABORTED
7601 * @constant {number}
7602 * @default 1
7603 */
7604
7605/**
7606 * W3C error code for any network error.
7607 *
7608 * @member MediaError#MEDIA_ERR_NETWORK
7609 * @constant {number}
7610 * @default 2
7611 */
7612/**
7613 * W3C error code for any network error.
7614 *
7615 * @member MediaError.MEDIA_ERR_NETWORK
7616 * @constant {number}
7617 * @default 2
7618 */
7619
7620/**
7621 * W3C error code for any decoding error.
7622 *
7623 * @member MediaError#MEDIA_ERR_DECODE
7624 * @constant {number}
7625 * @default 3
7626 */
7627/**
7628 * W3C error code for any decoding error.
7629 *
7630 * @member MediaError.MEDIA_ERR_DECODE
7631 * @constant {number}
7632 * @default 3
7633 */
7634
7635/**
7636 * W3C error code for any time that a source is not supported.
7637 *
7638 * @member MediaError#MEDIA_ERR_SRC_NOT_SUPPORTED
7639 * @constant {number}
7640 * @default 4
7641 */
7642/**
7643 * W3C error code for any time that a source is not supported.
7644 *
7645 * @member MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED
7646 * @constant {number}
7647 * @default 4
7648 */
7649
7650/**
7651 * W3C error code for any time that a source is encrypted.
7652 *
7653 * @member MediaError#MEDIA_ERR_ENCRYPTED
7654 * @constant {number}
7655 * @default 5
7656 */
7657/**
7658 * W3C error code for any time that a source is encrypted.
7659 *
7660 * @member MediaError.MEDIA_ERR_ENCRYPTED
7661 * @constant {number}
7662 * @default 5
7663 */
7664
7665exports['default'] = MediaError;
7666
7667},{"88":88}],47:[function(_dereq_,module,exports){
7668'use strict';
7669
7670exports.__esModule = true;
7671
7672var _clickableComponent = _dereq_(3);
7673
7674var _clickableComponent2 = _interopRequireDefault(_clickableComponent);
7675
7676var _component = _dereq_(5);
7677
7678var _component2 = _interopRequireDefault(_component);
7679
7680var _menu = _dereq_(49);
7681
7682var _menu2 = _interopRequireDefault(_menu);
7683
7684var _dom = _dereq_(81);
7685
7686var Dom = _interopRequireWildcard(_dom);
7687
7688var _fn = _dereq_(83);
7689
7690var Fn = _interopRequireWildcard(_fn);
7691
7692var _toTitleCase = _dereq_(91);
7693
7694var _toTitleCase2 = _interopRequireDefault(_toTitleCase);
7695
7696function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
7697
7698function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
7699
7700function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
7701
7702function _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; }
7703
7704function _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, { c
vendor: 5,173 bytes, lines 7704-7869
7704onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
7705                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file menu-button.js
7706                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
7707
7708
7709/**
7710 * A `MenuButton` class for any popup {@link Menu}.
7711 *
7712 * @extends ClickableComponent
7713 */
7714var MenuButton = function (_ClickableComponent) {
7715  _inherits(MenuButton, _ClickableComponent);
7716
7717  /**
7718   * Creates an instance of this class.
7719   *
7720   * @param {Player} player
7721   *        The `Player` that this class should be attached to.
7722   *
7723   * @param {Object} [options={}]
7724   *        The key/value store of player options.
7725   */
7726  function MenuButton(player) {
7727    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
7728
7729    _classCallCheck(this, MenuButton);
7730
7731    var _this = _possibleConstructorReturn(this, _ClickableComponent.call(this, player, options));
7732
7733    _this.update();
7734
7735    _this.enabled_ = true;
7736
7737    _this.el_.setAttribute('aria-haspopup', 'true');
7738    _this.el_.setAttribute('role', 'menuitem');
7739    _this.on('keydown', _this.handleSubmenuKeyPress);
7740    return _this;
7741  }
7742
7743  /**
7744   * Update the menu based on the current state of its items.
7745   */
7746
7747
7748  MenuButton.prototype.update = function update() {
7749    var menu = this.createMenu();
7750
7751    if (this.menu) {
7752      this.removeChild(this.menu);
7753    }
7754
7755    this.menu = menu;
7756    this.addChild(menu);
7757
7758    /**
7759     * Track the state of the menu button
7760     *
7761     * @type {Boolean}
7762     * @private
7763     */
7764    this.buttonPressed_ = false;
7765    this.el_.setAttribute('aria-expanded', 'false');
7766
7767    if (this.items && this.items.length <= this.hideThreshold_) {
7768      this.hide();
7769    } else {
7770      this.show();
7771    }
7772  };
7773
7774  /**
7775   * Create the menu and add all items to it.
7776   *
7777   * @return {Menu}
7778   *         The constructed menu
7779   */
7780
7781
7782  MenuButton.prototype.createMenu = function createMenu() {
7783    var menu = new _menu2['default'](this.player_);
7784
7785    /**
7786     * Hide the menu if the number of items is less than or equal to this threshold. This defaults
7787     * to 0 and whenever we add items which can be hidden to the menu we'll increment it. We list
7788     * it here because every time we run `createMenu` we need to reset the value.
7789     *
7790     * @protected
7791     * @type {Number}
7792     */
7793    this.hideThreshold_ = 0;
7794
7795    // Add a title list item to the top
7796    if (this.options_.title) {
7797      var title = Dom.createEl('li', {
7798        className: 'vjs-menu-title',
7799        innerHTML: (0, _toTitleCase2['default'])(this.options_.title),
7800        tabIndex: -1
7801      });
7802
7803      this.hideThreshold_ += 1;
7804
7805      menu.children_.unshift(title);
7806      Dom.insertElFirst(title, menu.contentEl());
7807    }
7808
7809    this.items = this.createItems();
7810
7811    if (this.items) {
7812      // Add menu items to the menu
7813      for (var i = 0; i < this.items.length; i++) {
7814        menu.addItem(this.items[i]);
7815      }
7816    }
7817
7818    return menu;
7819  };
7820
7821  /**
7822   * Create the list of menu items. Specific to each subclass.
7823   *
7824   * @abstract
7825   */
7826
7827
7828  MenuButton.prototype.createItems = function createItems() {};
7829
7830  /**
7831   * Create the `MenuButtons`s DOM element.
7832   *
7833   * @return {Element}
7834   *         The element that gets created.
7835   */
7836
7837
7838  MenuButton.prototype.createEl = function createEl() {
7839    return _ClickableComponent.prototype.createEl.call(this, 'div', {
7840      className: this.buildCSSClass()
7841    });
7842  };
7843
7844  /**
7845   * Builds the default DOM `className`.
7846   *
7847   * @return {string}
7848   *         The DOM `className` for this object.
7849   */
7850
7851
7852  MenuButton.prototype.buildCSSClass = function buildCSSClass() {
7853    var menuButtonClass = 'vjs-menu-button';
7854
7855    // If the inline option is passed, we want to use different styles altogether.
7856    if (this.options_.inline === true) {
7857      menuButtonClass += '-inline';
7858    } else {
7859      menuButtonClass += '-popup';
7860    }
7861
7862    return 'vjs-menu-button ' + menuButtonClass + ' ' + _ClickableComponent.prototype.buildCSSClass.call(this);
7863  };
7864
7865  /**
7866   * Handle a click on a `MenuButton`.
7867   * See {@link ClickableComponent#handleClick} for instances where this is called.
7868   *
7869   * @param {EventTarget~Event} event
7870   *        The `keydown`, `tap`, or `click` event that caused this function to be
7871   *        called.
7872   *
7873   * @listens tap
7874   * @listens click
7875   */
7876
7877
7878  MenuButton.prototype.handleClick = function handleClick(event) {
7879    // When you click the button it adds focus, which will show the menu.
7880    // So we'll remove focus when the mouse leaves the button. Focus is needed
7881    // for tab navigation.
7882
7883    this.one(this.menu.contentEl(), 'mouseleave', Fn.bind(this, function (e) {
7884      this.unpressButton();
7885      this.el_.blur();
7886    }));
7887    if (this.buttonPressed_) {
7888      this.unpressButton();
7889    } else {
7890      this.pressButton();
7891    }
7892  };
7893
7894  /**
7895   * Handle tab, escape, down arrow, and up arrow keys for `MenuButton`. See
7896   * {@link ClickableComponent#handleKeyPress} for instances where this is called.
7897   *
7898   * @param {EventTarget~Event} event
7899   *        The `keydown` event that caused this function to be called.
7900   *
7901   * @listens keydown
7902   */
7903
7904
7905  MenuButton.prototype.handleKeyPress = function handleKeyPress(event) {
7906
7907    // Escape (27) key or Tab (9) key unpress the 'button'
7908    if (event.which === 27 || event.which === 9) {
7909      if (this.buttonPressed_) {
7910        this.unpressButton();
7911      }
7912      // Don't preventDefault for Tab key - we still want to lose focus
7913      if (event.which !== 9) {
7914        event.preventDefault();
7915      }
7916      // Up (38) key or Down (40) key press the 'button'
7917    } else if (event.which === 38 || event.which === 40) {
7918      if (!this.buttonPressed_) {
7919        this.pressButton();
7920        event.preventDefault();
7921      }
7922    } else {
7923      _ClickableComponent.prototype.handleKeyPress.call(this, event);
7924    }
7925  };
7926
7927  /**
7928   * Handle a `keydown` event on a sub-menu. The listener for this is added in
7929   * the constructor.
7930   *
7931   * @param {EventTarget~Event} event
7932   *        Key press event
7933   *
7934   * @listens keydown
7935   */
7936
7937
7938  MenuButton.prototype.handleSubmenuKeyPress = function handleSubmenuKeyPress(event) {
7939
7940    // Escape (27) key or Tab (9) key unpress the 'button'
7941    if (event.which === 27 || event.which === 9) {
7942      if (this.buttonPressed_) {
7943        this.unpressButton();
7944      }
7945      // Don't preventDefault for Tab key - we still want to lose focus
7946      if (event.which !== 9) {
7947        event.preventDefault();
7948      }
7949    }
7950  };
7951
7952  /**
7953   * Put the current `MenuButton` into a pressed state.
7954   */
7955
7956
7957  MenuButton.prototype.pressButton = function pressButton() {
7958    if (this.enabled_) {
7959      this.buttonPressed_ = true;
7960      this.menu.lockShowing();
7961      this.el_.setAttribute('aria-expanded', 'true');
7962      // set the focus into the submenu
7963      this.menu.focus();
7964    }
7965  };
7966
7967  /**
7968   * Take the current `MenuButton` out of a pressed state.
7969   */
7970
7971
7972  MenuButton.prototype.unpressButton = function unpressButton() {
7973    if (this.enabled_) {
7974      this.buttonPressed_ = false;
7975      this.menu.unlockShowing();
7976      this.el_.setAttribute('aria-expanded', 'false');
7977      // Set focus back to this menu button
7978      this.el_.focus();
7979    }
7980  };
7981
7982  /**
7983   * Disable the `MenuButton`. Don't allow it to be clicked.
7984   *
7985   * @return {MenuButton}
7986   *         Returns itself; method can be chained.
7987   */
7988
7989
7990  MenuButton.prototype.disable = function disable() {
7991    // Unpress, but don't force focus on this button
7992    this.buttonPressed_ = false;
7993    this.menu.unlockShowing();
7994    this.el_.setAttribute('aria-expanded', 'false');
7995
7996    this.enabled_ = false;
7997
7998    return _ClickableComponent.prototype.disable.call(this);
7999  };
8000
8001  /**
8002   * Enable the `MenuButton`. Allow it to be clicked.
8003   *
8004   * @return {MenuButton}
8005   *         Returns itself; method can be chained.
8006   */
8007
8008
8009  MenuButton.prototype.enable = function enable() {
8010    this.enabled_ = true;
8011
8012    return _ClickableComponent.prototype.enable.call(this);
8013  };
8014
8015  return MenuButton;
8016}(_clickableComponent2['default']);
8017
8018_component2['default'].registerComponent('MenuButton', MenuButton);
8019exports['default'] = MenuButton;
8020
8021},{"3":3,"49":49,"5":5,"81":81,"83":83,"91":91}],48:[function(_dereq_,module,exports){
8022'use strict';
8023
8024exports.__esModule = true;
8025
8026var _clickableComponent = _dereq_(3);
8027
8028var _clickableComponent2 = _interopRequireDefault(_clickableComponent);
8029
8030var _component = _dereq_(5);
8031
8032var _component2 = _interopRequireDefault(_component);
8033
8034var _obj = _dereq_(88);
8035
8036function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
8037
8038function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
8039
8040function _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; }
8041
8042function _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, { c
8042onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
8043                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file menu-item.js
8044                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
8045
8046
8047/**
8048 * The component for a menu item. `<li>`
8049 *
8050 * @extends ClickableComponent
8051 */
8052var MenuItem = function (_ClickableComponent) {
8053  _inherits(MenuItem, _ClickableComponent);
8054
8055  /**
8056   * Creates an instance of the this class.
8057   *
8058   * @param {Player} player
8059   *        The `Player` that this class should be attached to.
8060   *
8061   * @param {Object} [options={}]
8062   *        The key/value store of player options.
8063   *
8064   */
8065  function MenuItem(player, options) {
8066    _classCallCheck(this, MenuItem);
8067
8068    var _this = _possibleConstructorReturn(this, _ClickableComponent.call(this, player, options));
8069
8070    _this.selectable = options.selectable;
8071
8072    _this.selected(options.selected);
8073
8074    if (_this.selectable) {
8075      // TODO: May need to be either menuitemcheckbox or menuitemradio,
8076      //       and may need logical grouping of menu items.
8077      _this.el_.setAttribute('role', 'menuitemcheckbox');
8078    } else {
8079      _this.el_.setAttribute('role', 'menuitem');
8080    }
8081    return _this;
8082  }
8083
8084  /**
8085   * Create the `MenuItem's DOM element
8086   *
8087   * @param {string} [type=li]
8088   *        Element's node type, not actually used, always set to `li`.
8089   *
8090   * @param {Object} [props={}]
8091   *        An object of properties that should be set on the element
8092   *
8093   * @param {Object} [attrs={}]
8094   *        An object of attributes that should be set on the element
8095   *
8096   * @return {Element}
8097   *         The element that gets created.
8098   */
8099
8100
8101  MenuItem.prototype.createEl = function createEl(type, props, attrs) {
8102    // The control is textual, not just an icon
8103    this.nonIconControl = true;
8104
8105    return _ClickableComponent.prototype.createEl.call(this, 'li', (0, _obj.assign)({
8106      className: 'vjs-menu-item',
8107      innerHTML: this.localize(this.options_.label),
8108      tabIndex: -1
8109    }, props), attrs);
8110  };
8111
8112  /**
8113   * Any click on a `MenuItem` puts int into the selected state.
8114   * See {@link ClickableComponent#handleClick} for instances where this is called.
8115   *
8116   * @param {EventTarget~Event} event
8117   *        The `keydown`, `tap`, or `click` event that caused this function to be
8118   *        called.
8119   *
8120   * @listens tap
8121   * @listens click
8122   */
8123
8124
8125  MenuItem.prototype.handleClick = function handleClick(event) {
8126    this.selected(true);
8127  };
8128
8129  /**
8130   * Set the state for this menu item as selected or not.
8131   *
8132   * @param {boolean} selected
8133   *        if the menu item is selected or not
8134   */
8135
8136
8137  MenuItem.prototype.selected = function selected(_selected) {
8138    if (this.selectable) {
8139      if (_selected) {
8140        this.addClass('vjs-selected');
8141        this.el_.setAttribute('aria-checked', 'true');
8142        // aria-checked isn't fully supported by browsers/screen readers,
8143        // so indicate selected state to screen reader in the control text.
8144        this.controlText(', selected');
8145      } else {
8146        this.removeClass('vjs-selected');
8147        this.el_.setAttribute('aria-checked', 'false');
8148        // Indicate un-selected state to screen reader
8149        // Note that a space clears out the selected state text
8150        this.controlText(' ');
8151      }
8152    }
8153  };
8154
8155  return MenuItem;
8156}(_clickableComponent2['default']);
8157
8158_component2['default'].registerComponent('MenuItem', MenuItem);
8159exports['default'] = MenuItem;
8160
8161},{"3":3,"5":5,"88":88}],49:[function(_dereq_,module,exports){
8162'use strict';
8163
8164exports.__esModule = true;
8165
8166var _component = _dereq_(5);
8167
8168var _component2 = _interopRequireDefault(_component);
8169
8170var _dom = _dereq_(81);
8171
8172var Dom = _interopRequireWildcard(_dom);
8173
8174var _fn = _dereq_(83);
8175
8176var Fn = _interopRequireWildcard(_fn);
8177
8178var _events = _dereq_(82);
8179
8180var Events = _interopRequireWildcard(_events);
8181
8182function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
8183
8184function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
8185
8186function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
8187
8188function _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; }
8189
8190function _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; } /**
8191                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file menu.js
8192                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
8193
8194
8195/**
8196 * The Menu component is used to build popup menus, including subtitle and
8197 * captions selection menus.
8198 *
8199 * @extends Component
8200 */
8201var Menu = function (_Component) {
8202  _inherits(Menu, _Component);
8203
8204  /**
8205   * Create an instance of this class.
8206   *
8207   * @param {Player} player
8208   *        the player that this component should attach to
8209   *
8210   * @param {Object} [options]
8211   *        Object of option names and values
8212   *
8213   */
8214  function Menu(player, options) {
8215    _classCallCheck(this, Menu);
8216
8217    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
8218
8219    _this.focusedChild_ = -1;
8220
8221    _this.on('keydown', _this.handleKeyPress);
8222    return _this;
8223  }
8224
8225  /**
8226   * Add a {@link MenuItem} to the menu.
8227   *
8228   * @param {Object|string} component
8229   *        The name or instance of the `MenuItem` to add.
8230   *
8231   */
8232
8233
8234  Menu.prototype.addItem = function addItem(component) {
8235    this.addChild(component);
8236    component.on('click', Fn.bind(this, function (event) {
8237      this.unlockShowing();
8238      // TODO: Need to set keyboard focus back to the menuButton
8239    }));
8240  };
8241
8242  /**
8243   * Create the `Menu`s DOM element.
8244   *
8245   * @return {Element}
8246   *         the element that was created
8247   */
8248
8249
8250  Menu.prototype.createEl = function createEl() {
8251    var contentElType = this.options_.contentElType || 'ul';
8252
8253    this.contentEl_ = Dom.createEl(contentElType, {
8254      className: 'vjs-menu-content'
8255    });
8256
8257    this.contentEl_.setAttribute('role', 'menu');
8258
8259    var el = _Component.prototype.createEl.call(this, 'div', {
8260      append: this.contentEl_,
8261      className: 'vjs-menu'
8262    });
8263
8264    el.setAttribute('role', 'presentation');
8265    el.appendChild(this.contentEl_);
8266
8267    // Prevent clicks from bubbling up. Needed for Menu Buttons,
8268    // where a click on the parent is significant
8269    Events.on(el, 'click', function (event) {
8270      event.preventDefault();
8271      event.stopImmediatePropagation();
8272    });
8273
8274    return el;
8275  };
8276
8277  /**
8278   * Handle a `keydown` event on this menu. This listener is added in the constructor.
8279   *
8280   * @param {EventTarget~Event} event
8281   *        A `keydown` event that happened on the menu.
8282   *
8283   * @listens keydown
8284   */
8285
8286
8287  Menu.prototype.handleKeyPress = function handleKeyPress(event) {
8288    // Left and Down Arrows
8289    if (event.which === 37 || event.which === 40) {
8290      event.preventDefault();
8291      this.stepForward();
8292
8293      // Up and Right Arrows
8294    } else if (event.which === 38 || event.which === 39) {
8295      event.preventDefault();
8296      this.stepBack();
8297    }
8298  };
8299
8300  /**
8301   * Move to next (lower) menu item for keyboard users.
8302   */
8303
8304
8305  Menu.prototype.stepForward = function stepForward() {
8306    var stepChild = 0;
8307
8308    if (this.focusedChild_ !== undefined) {
8309      stepChild = this.focusedChild_ + 1;
8310    }
8311    this.focus(stepChild);
8312  };
8313
8314  /**
8315   * Move to previous (higher) menu item for keyboard users.
8316   */
8317
8318
8319  Menu.prototype.stepBack = function stepBack() {
8320    var stepChild = 0;
8321
8322    if (this.focusedChild_ !== undefined) {
8323      stepChild = this.focusedChild_ - 1;
8324    }
8325    this.focus(stepChild);
8326  };
8327
8328  /**
8329   * Set focus on a {@link MenuItem} in the `Menu`.
8330   *
8331   * @param {Object|string} [item=0]
8332   *        Index of child item set focus on.
8333   */
8334
8335
8336  Menu.prototype.focus = function focus() {
8337    var item = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
8338
8339    var children = this.children().slice();
8340    var haveTitle = children.length && children[0].className && /vjs-menu-title/.test(children[0].className);
8341
8342    if (haveTitle) {
8343      children.shift();
8344    }
8345
8346    if (children.length > 0) {
8347      if (item < 0) {
8348        item = 0;
8349      } else if (item >= children.length) {
8350        item = children.length - 1;
8351      }
8352
8353      this.focusedChild_ = item;
8354
8355      children[item].el_.focus();
8356    }
8357  };
8358
8359  return Menu;
8360}(_component2['default']);
8361
8362_component2['default'].registerComponent('Menu', Menu);
8363exports['default'] = Menu;
8364
8365},{"5":5,"81":81,"82":82,"83":83}],50:[function(_dereq_,module,exports){
8366'use strict';
8367
8368exports.__esModule = true;
8369
8370var _dom = _dereq_(81);
8371
8372var Dom = _interopRequireWildcard(_dom);
8373
8374var _fn = _dereq_(83);
8375
8376var Fn = _interopRequireWildcard(_fn);
8377
8378var _component = _dereq_(5);
8379
8380var _component2 = _interopRequireDefault(_component);
8381
8382function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
8383
8384function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
8385
8386function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
8387
8388function _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; }
8389
8390function _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; } /**
8391                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file modal-dialog.js
8392                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
8393
8394
8395var MODAL_CLASS_NAME = 'vjs-modal-dialog';
8396var ESC = 27;
8397
8398/**
8399 * The `ModalDialog` displays over the video and its controls, which blocks
8400 * interaction with the player until it is closed.
8401 *
8402 * Modal dialogs include a "Close" button and will close when that button
8403 * is activated - or when ESC is pressed anywhere.
8404 *
8405 * @extends Component
8406 */
8407
8408var ModalDialog = function (_Component) {
8409  _inherits(ModalDialog, _Component);
8410
8411  /**
8412   * Create an instance of this class.
8413   *
8414   * @param {Player} player
8415   *        The `Player` that this class should be attached to.
8416   *
8417   * @param {Object} [options]
8418   *        The key/value store of player options.
8419   *
8420   * @param {Mixed} [options.content=undefined]
8421   *        Provide customized content for this modal.
8422   *
8423   * @param {string} [options.description]
8424   *        A text description for the modal, primarily for accessibility.
8425   *
8426   * @param {boolean} [options.fillAlways=false]
8427   *        Normally, modals are automatically filled only the first time
8428   *        they open. This tells the modal to refresh its content
8429   *        every time it opens.
8430   *
8431   * @param {string} [options.label]
8432   *        A text label for the modal, primarily for accessibility.
8433   *
8434   * @param {boolean} [options.temporary=true]
8435   *        If `true`, the modal can only be opened once; it will be
8436   *        disposed as soon as it's closed.
8437   *
8438   * @param {boolean} [options.uncloseable=false]
8439   *        If `true`, the user will not be able to close the modal
8440   *        through the UI in the normal ways. Programmatic closing is
8441   *        still possible.
8442   */
8443  function ModalDialog(player, options) {
8444    _classCallCheck(this, ModalDialog);
8445
8446    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
8447
8448    _this.opened_ = _this.hasBeenOpened_ = _this.hasBeenFilled_ = false;
vendor: 5,078 bytes, lines 8449-8646
8449
8450    _this.closeable(!_this.options_.uncloseable);
8451    _this.content(_this.options_.content);
8452
8453    // Make sure the contentEl is defined AFTER any children are initialized
8454    // because we only want the contents of the modal in the contentEl
8455    // (not the UI elements like the close button).
8456    _this.contentEl_ = Dom.createEl('div', {
8457      className: MODAL_CLASS_NAME + '-content'
8458    }, {
8459      role: 'document'
8460    });
8461
8462    _this.descEl_ = Dom.createEl('p', {
8463      className: MODAL_CLASS_NAME + '-description vjs-offscreen',
8464      id: _this.el().getAttribute('aria-describedby')
8465    });
8466
8467    Dom.textContent(_this.descEl_, _this.description());
8468    _this.el_.appendChild(_this.descEl_);
8469    _this.el_.appendChild(_this.contentEl_);
8470    return _this;
8471  }
8472
8473  /**
8474   * Create the `ModalDialog`'s DOM element
8475   *
8476   * @return {Element}
8477   *         The DOM element that gets created.
8478   */
8479
8480
8481  ModalDialog.prototype.createEl = function createEl() {
8482    return _Component.prototype.createEl.call(this, 'div', {
8483      className: this.buildCSSClass(),
8484      tabIndex: -1
8485    }, {
8486      'aria-describedby': this.id() + '_description',
8487      'aria-hidden': 'true',
8488      'aria-label': this.label(),
8489      'role': 'dialog'
8490    });
8491  };
8492
8493  /**
8494   * Builds the default DOM `className`.
8495   *
8496   * @return {string}
8497   *         The DOM `className` for this object.
8498   */
8499
8500
8501  ModalDialog.prototype.buildCSSClass = function buildCSSClass() {
8502    return MODAL_CLASS_NAME + ' vjs-hidden ' + _Component.prototype.buildCSSClass.call(this);
8503  };
8504
8505  /**
8506   * Handles `keydown` events on the document, looking for ESC, which closes
8507   * the modal.
8508   *
8509   * @param {EventTarget~Event} e
8510   *        The keypress that triggered this event.
8511   *
8512   * @listens keydown
8513   */
8514
8515
8516  ModalDialog.prototype.handleKeyPress = function handleKeyPress(e) {
8517    if (e.which === ESC && this.closeable()) {
8518      this.close();
8519    }
8520  };
8521
8522  /**
8523   * Returns the label string for this modal. Primarily used for accessibility.
8524   *
8525   * @return {string}
8526   *         the localized or raw label of this modal.
8527   */
8528
8529
8530  ModalDialog.prototype.label = function label() {
8531    return this.options_.label || this.localize('Modal Window');
8532  };
8533
8534  /**
8535   * Returns the description string for this modal. Primarily used for
8536   * accessibility.
8537   *
8538   * @return {string}
8539   *         The localized or raw description of this modal.
8540   */
8541
8542
8543  ModalDialog.prototype.description = function description() {
8544    var desc = this.options_.description || this.localize('This is a modal window.');
8545
8546    // Append a universal closeability message if the modal is closeable.
8547    if (this.closeable()) {
8548      desc += ' ' + this.localize('This modal can be closed by pressing the Escape key or activating the close button.');
8549    }
8550
8551    return desc;
8552  };
8553
8554  /**
8555   * Opens the modal.
8556   *
8557   * @fires ModalDialog#beforemodalopen
8558   * @fires ModalDialog#modalopen
8559   *
8560   * @return {ModalDialog}
8561   *         Returns itself; method can be chained.
8562   */
8563
8564
8565  ModalDialog.prototype.open = function open() {
8566    if (!this.opened_) {
8567      var player = this.player();
8568
8569      /**
8570       * Fired just before a `ModalDialog` is opened.
8571       *
8572       * @event ModalDialog#beforemodalopen
8573       * @type {EventTarget~Event}
8574       */
8575      this.trigger('beforemodalopen');
8576      this.opened_ = true;
8577
8578      // Fill content if the modal has never opened before and
8579      // never been filled.
8580      if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) {
8581        this.fill();
8582      }
8583
8584      // If the player was playing, pause it and take note of its previously
8585      // playing state.
8586      this.wasPlaying_ = !player.paused();
8587
8588      if (this.options_.pauseOnOpen && this.wasPlaying_) {
8589        player.pause();
8590      }
8591
8592      if (this.closeable()) {
8593        this.on(this.el_.ownerDocument, 'keydown', Fn.bind(this, this.handleKeyPress));
8594      }
8595
8596      player.controls(false);
8597      this.show();
8598      this.el().setAttribute('aria-hidden', 'false');
8599
8600      /**
8601       * Fired just after a `ModalDialog` is opened.
8602       *
8603       * @event ModalDialog#modalopen
8604       * @type {EventTarget~Event}
8605       */
8606      this.trigger('modalopen');
8607      this.hasBeenOpened_ = true;
8608    }
8609    return this;
8610  };
8611
8612  /**
8613   * If the `ModalDialog` is currently open or closed.
8614   *
8615   * @param  {boolean} [value]
8616   *         If given, it will open (`true`) or close (`false`) the modal.
8617   *
8618   * @return {boolean}
8619   *         the current open state of the modaldialog
8620   */
8621
8622
8623  ModalDialog.prototype.opened = function opened(value) {
8624    if (typeof value === 'boolean') {
8625      this[value ? 'open' : 'close']();
8626    }
8627    return this.opened_;
8628  };
8629
8630  /**
8631   * Closes the modal, does nothing if the `ModalDialog` is
8632   * not open.
8633   *
8634   * @fires ModalDialog#beforemodalclose
8635   * @fires ModalDialog#modalclose
8636   *
8637   * @return {ModalDialog}
8638   *         Returns itself; method can be chained.
8639   */
8640
8641
8642  ModalDialog.prototype.close = function close() {
8643    if (this.opened_) {
8644      var player = this.player();
8645
8646      /**
8647       * Fired just before a `ModalDialog` is closed.
8648       *
8649       * @event ModalDialog#beforemodalclose
8650       * @type {EventTarget~Event}
8651       */
8652      this.trigger('beforemodalclose');
8653      this.opened_ = false;
8654
8655      if (this.wasPlaying_ && this.options_.pauseOnOpen) {
8656        player.play();
8657      }
8658
8659      if (this.closeable()) {
8660        this.off(this.el_.ownerDocument, 'keydown', Fn.bind(this, this.handleKeyPress));
8661      }
8662
8663      player.controls(true);
8664      this.hide();
8665      this.el().setAttribute('aria-hidden', 'true');
8666
8667      /**
8668       * Fired just after a `ModalDialog` is closed.
8669       *
8670       * @event ModalDialog#modalclose
8671       * @type {EventTarget~Event}
8672       */
8673      this.trigger('modalclose');
8674
8675      if (this.options_.temporary) {
8676        this.dispose();
8677      }
8678    }
8679    return this;
8680  };
8681
8682  /**
8683   * Check to see if the `ModalDialog` is closeable via the UI.
8684   *
8685   * @param  {boolean} [value]
8686   *         If given as a boolean, it will set the `closeable` option.
8687   *
8688   * @return {boolean}
8689   *         Returns the final value of the closable option.
8690   */
8691
8692
8693  ModalDialog.prototype.closeable = function closeable(value) {
8694    if (typeof value === 'boolean') {
8695      var closeable = this.closeable_ = !!value;
8696      var close = this.getChild('closeButton');
8697
8698      // If this is being made closeable and has no close button, add one.
8699      if (closeable && !close) {
8700
8701        // The close button should be a child of the modal - not its
8702        // content element, so temporarily change the content element.
8703        var temp = this.contentEl_;
8704
8705        this.contentEl_ = this.el_;
8706        close = this.addChild('closeButton', { controlText: 'Close Modal Dialog' });
8707        this.contentEl_ = temp;
8708        this.on(close, 'close', this.close);
8709      }
8710
8711      // If this is being made uncloseable and has a close button, remove it.
8712      if (!closeable && close) {
8713        this.off(close, 'close', this.close);
8714        this.removeChild(close);
8715        close.dispose();
8716      }
8717    }
8718    return this.closeable_;
8719  };
8720
8721  /**
8722   * Fill the modal's content element with the modal's "content" option.
8723   * The content element will be emptied before this change takes place.
8724   *
8725   * @return {ModalDialog}
8726   *         Returns itself; method can be chained.
8727   */
8728
8729
8730  ModalDialog.prototype.fill = function fill() {
8731    return this.fillWith(this.content());
8732  };
8733
8734  /**
8735   * Fill the modal's content element with arbitrary content.
8736   * The content element will be emptied before this change takes place.
8737   *
8738   * @fires ModalDialog#beforemodalfill
8739   * @fires ModalDialog#modalfill
8740   *
8741   * @param  {Mixed} [content]
8742   *         The same rules apply to this as apply to the `content` option.
8743   *
8744   * @return {ModalDialog}
8745   *         Returns itself; method can be chained.
8746   */
8747
8748
8749  ModalDialog.prototype.fillWith = function fillWith(content) {
8750    var contentEl = this.contentEl();
8751    var parentEl = contentEl.parentNode;
8752    var nextSiblingEl = contentEl.nextSibling;
8753
8754    /**
8755     * Fired just before a `ModalDialog` is filled with content.
8756     *
8757     * @event ModalDialog#beforemodalfill
8758     * @type {EventTarget~Event}
8759     */
8760    this.trigger('beforemodalfill');
8761    this.hasBeenFilled_ = true;
8762
8763    // Detach the content element from the DOM before performing
8764    // manipulation to avoid modifying the live DOM multiple times.
8765    parentEl.removeChild(contentEl);
8766    this.empty();
8767    Dom.insertContent(contentEl, content);
8768    /**
8769     * Fired just after a `ModalDialog` is filled with content.
8770     *
8771     * @event ModalDialog#modalfill
8772     * @type {EventTarget~Event}
8773     */
8774    this.trigger('modalfill');
8775
8776    // Re-inject the re-filled content element.
8777    if (nextSiblingEl) {
8778      parentEl.insertBefore(contentEl, nextSiblingEl);
8779    } else {
8780      parentEl.appendChild(contentEl);
8781    }
8782
8783    return this;
8784  };
8785
8786  /**
8787   * Empties the content element. This happens anytime the modal is filled.
8788   *
8789   * @fires ModalDialog#beforemodalempty
8790   * @fires ModalDialog#modalempty
8791   *
8792   * @return {ModalDialog}
8793   *         Returns itself; method can be chained.
8794   */
8795
8796
8797  ModalDialog.prototype.empty = function empty() {
8798    /**
8799     * Fired just before a `ModalDialog` is emptied.
8800     *
8801     * @event ModalDialog#beforemodalempty
8802     * @type {EventTarget~Event}
8803     */
8804    this.trigger('beforemodalempty');
8805    Dom.emptyEl(this.contentEl());
8806
8807    /**
8808     * Fired just after a `ModalDialog` is emptied.
8809     *
8810     * @event ModalDialog#modalempty
8811     * @type {EventTarget~Event}
8812     */
8813    this.trigger('modalempty');
8814    return this;
8815  };
8816
8817  /**
8818   * Gets or sets the modal content, which gets normalized before being
8819   * rendered into the DOM.
8820   *
8821   * This does not update the DOM or fill the modal, but it is called during
8822   * that process.
8823   *
8824   * @param  {Mixed} [value]
8825   *         If defined, sets the internal content value to be used on the
8826   *         next call(s) to `fill`. This value is normalized before being
8827   *         inserted. To "clear" the internal content value, pass `null`.
8828   *
8829   * @return {Mixed}
8830   *         The current content of the modal dialog
8831   */
8832
8833
8834  ModalDialog.prototype.content = function content(value) {
8835    if (typeof value !== 'undefined') {
8836      this.content_ = value;
8837    }
8838    return this.content_;
8839  };
8840
8841  return ModalDialog;
8842}(_component2['default']);
8843
8844/**
8845 * Default options for `ModalDialog` default options.
8846 *
8847 * @type {Object}
8848 * @private
8849 */
8850
8851
8852ModalDialog.prototype.options_ = {
8853  pauseOnOpen: true,
8854  temporary: true
8855};
8856
8857_component2['default'].registerComponent('ModalDialog', ModalDialog);
8858exports['default'] = ModalDialog;
8859
8860},{"5":5,"81":81,"83":83}],51:[function(_dereq_,module,exports){
8861'use strict';
8862
8863exports.__esModule = true;
8864
8865var _component = _dereq_(5);
8866
8867var _component2 = _interopRequireDefault(_component);
8868
8869var _document = _dereq_(94);
8870
8871var _document2 = _interopRequireDefault(_document);
8872
8873var _window = _dereq_(95);
8874
8875var _window2 = _interopRequireDefault(_window);
8876
8877var _events = _dereq_(82);
8878
8879var Events = _interopRequireWildcard(_events);
8880
8881var _dom = _dereq_(81);
8882
8883var Dom = _interopRequireWildcard(_dom);
8884
8885var _fn = _dereq_(83);
8886
8887var Fn = _interopRequireWildcard(_fn);
8888
8889var _guid = _dereq_(85);
8890
8891var Guid = _interopRequireWildcard(_guid);
8892
8893var _browser = _dereq_(78);
8894
8895var browser = _interopRequireWildcard(_browser);
8896
8897var _log = _dereq_(86);
8898
8899var _log2 = _interopRequireDefault(_log);
8900
8901var _toTitleCase = _dereq_(91);
8902
8903var _toTitleCase2 = _interopRequireDefault(_toTitleCase);
8904
8905var _timeRanges = _dereq_(90);
8906
8907var _buffer = _dereq_(79);
8908
8909var _stylesheet = _dereq_(89);
8910
8911var stylesheet = _interopRequireWildcard(_stylesheet);
8912
8913var _fullscreenApi = _dereq_(44);
8914
8915var _fullscreenApi2 = _interopRequireDefault(_fullscreenApi);
8916
8917var _mediaError = _dereq_(46);
8918
8919var _mediaError2 = _interopRequireDefault(_mediaError);
8920
8921var _tuple = _dereq_(97);
8922
8923var _tuple2 = _interopRequireDefault(_tuple);
8924
8925var _obj = _dereq_(88);
8926
8927var _mergeOptions = _dereq_(87);
8928
8929var _mergeOptions2 = _interopRequireDefault(_mergeOptions);
8930
8931var _textTrackListConverter = _dereq_(69);
8932
8933var _textTrackListConverter2 = _interopRequireDefault(_textTrackListConverter);
8934
8935var _modalDialog = _dereq_(50);
8936
8937var _modalDialog2 = _interopRequireDefault(_modalDialog);
8938
8939var _tech = _dereq_(62);
8940
8941var _tech2 = _interopRequireDefault(_tech);
8942
8943var _audioTrackList = _dereq_(63);
8944
8945var _audioTrackList2 = _interopRequireDefault(_audioTrackList);
8946
8947var _videoTrackList = _dereq_(76);
8948
8949var _videoTrackList2 = _interopRequireDefault(_videoTrackList);
8950
8951_dereq_(61);
8952
8953_dereq_(59);
8954
8955_dereq_(55);
8956
8957_dereq_(68);
8958
8959_dereq_(45);
8960
8961_dereq_(1);
8962
8963_dereq_(4);
8964
8965_dereq_(8);
8966
8967_dereq_(41);
8968
8969_dereq_(71);
8970
8971_dereq_(60);
8972
8973function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
8974
8975function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
8976
8977function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
8978
8979function _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; }
8980
8981function _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, { c
8981onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
8982                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file player.js
8983                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
8984// Subclasses Component
8985
8986
8987// The following imports are used only to ensure that the corresponding modules
8988// are always included in the video.js package. Importing the modules will
8989// execute them and they will register themselves with video.js.
8990
8991
8992// Import Html5 tech, at least for disposing the original video tag.
8993
8994
8995// The following tech events are simply re-triggered
8996// on the player when they happen
8997var TECH_EVENTS_RETRIGGER = [
8998/**
8999 * Fired while the user agent is downloading media data.
9000 *
9001 * @event Player#progress
9002 * @type {EventTarget~Event}
9003 */
9004/**
9005 * Retrigger the `progress` event that was triggered by the {@link Tech}.
9006 *
9007 * @private
9008 * @method Player#handleTechProgress_
9009 * @fires Player#progress
9010 * @listens Tech#progress
9011 */
9012'progress',
9013
9014/**
9015 * Fires when the loading of an audio/video is aborted.
9016 *
9017 * @event Player#abort
9018 * @type {EventTarget~Event}
9019 */
9020/**
9021 * Retrigger the `abort` event that was triggered by the {@link Tech}.
9022 *
9023 * @private
9024 * @method Player#handleTechAbort_
9025 * @fires Player#abort
9026 * @listens Tech#abort
9027 */
9028'abort',
9029
9030/**
9031 * Fires when the browser is intentionally not getting media data.
9032 *
9033 * @event Player#suspend
9034 * @type {EventTarget~Event}
9035 */
9036/**
9037 * Retrigger the `suspend` event that was triggered by the {@link Tech}.
9038 *
9039 * @private
9040 * @method Player#handleTechSuspend_
9041 * @fires Player#suspend
9042 * @listens Tech#suspend
9043 */
9044'suspend',
9045
9046/**
9047 * Fires when the current playlist is empty.
9048 *
9049 * @event Player#emptied
9050 * @type {EventTarget~Event}
9051 */
9052/**
9053 * Retrigger the `emptied` event that was triggered by the {@link Tech}.
9054 *
9055 * @private
9056 * @method Player#handleTechEmptied_
9057 * @fires Player#emptied
9058 * @listens Tech#emptied
9059 */
9060'emptied',
9061/**
9062 * Fires when the browser is trying to get media data, but data is not available.
9063 *
9064 * @event Player#stalled
9065 * @type {EventTarget~Event}
9066 */
9067/**
9068 * Retrigger the `stalled` event that was triggered by the {@link Tech}.
9069 *
9070 * @private
9071 * @method Player#handleTechStalled_
9072 * @fires Player#stalled
9073 * @listens Tech#stalled
9074 */
9075'stalled',
9076
9077/**
9078 * Fires when the browser has loaded meta data for the audio/video.
9079 *
9080 * @event Player#loadedmetadata
9081 * @type {EventTarget~Event}
9082 */
9083/**
9084 * Retrigger the `stalled` event that was triggered by the {@link Tech}.
9085 *
9086 * @private
9087 * @method Player#handleTechLoadedmetadata_
9088 * @fires Player#loadedmetadata
9089 * @listens Tech#loadedmetadata
9090 */
9091'loadedmetadata',
9092
9093/**
9094 * Fires when the browser has loaded the current frame of the audio/video.
9095 *
9096 * @event player#loadeddata
9097 * @type {event}
9098 */
9099/**
9100 * Retrigger the `loadeddata` event that was triggered by the {@link Tech}.
9101 *
9102 * @private
9103 * @method Player#handleTechLoaddeddata_
9104 * @fires Player#loadeddata
9105 * @listens Tech#loadeddata
9106 */
9107'loadeddata',
9108
9109/**
9110 * Fires when the current playback position has changed.
9111 *
9112 * @event player#timeupdate
9113 * @type {event}
9114 */
9115/**
9116 * Retrigger the `timeupdate` event that was triggered by the {@link Tech}.
9117 *
9118 * @private
9119 * @method Player#handleTechTimeUpdate_
9120 * @fires Player#timeupdate
9121 * @listens Tech#timeupdate
9122 */
9123'timeupdate',
9124
9125/**
9126 * Fires when the playing speed of the audio/video is changed
9127 *
9128 * @event player#ratechange
9129 * @type {event}
9130 */
9131/**
9132 * Retrigger the `ratechange` event that was triggered by the {@link Tech}.
9133 *
9134 * @private
9135 * @method Player#handleTechRatechange_
9136 * @fires Player#ratechange
9137 * @listens Tech#ratechange
9138 */
9139'ratechange',
9140
9141/**
9142 * Fires when the volume has been changed
9143 *
9144 * @event player#volumechange
9145 * @type {event}
9146 */
9147/**
9148 * Retrigger the `volumechange` event that was triggered by the {@link Tech}.
9149 *
9150 * @private
9151 * @method Player#handleTechVolumechange_
9152 * @fires Player#volumechange
9153 * @listens Tech#volumechange
9154 */
9155'volumechange',
9156
9157/**
9158 * Fires when the text track has been changed
9159 *
9160 * @event player#texttrackchange
9161 * @type {event}
9162 */
9163/**
9164 * Retrigger the `texttrackchange` event that was triggered by the {@link Tech}.
9165 *
9166 * @private
9167 * @method Player#handleTechTexttrackchange_
9168 * @fires Player#texttrackchange
9169 * @listens Tech#texttrackchange
9170 */
9171'texttrackchange'];
9172
9173/**
9174 * An instance of the `Player` class is created when any of the Video.js setup methods
9175 * are used to initialize a video.
9176 *
9177 * After an instance has been created it can be accessed globally in two ways:
9178 * 1. By calling `videojs('example_video_1');`
9179 * 2. By using it directly via  `videojs.players.example_video_1;`
9180 *
9181 * @extends Component
9182 */
9183
9184var Player = function (_Component) {
9185  _inherits(Player, _Component);
9186
9187  /**
9188   * Create an instance of this class.
9189   *
9190   * @param {Element} tag
9191   *        The original video DOM element used for configuring options.
9192   *
9193   * @param {Object} [options]
9194   *        Object of option names and values.
9195   *
9196   * @param {Component~ReadyCallback} [ready]
9197   *        Ready callback function.
9198   */
9199  function Player(tag, options, ready) {
9200    _classCallCheck(this, Player);
9201
9202    // Make sure tag ID exists
9203    tag.id = tag.id || 'vjs_video_' + Guid.newGUID();
9204
9205    // Set Options
9206    // The options argument overrides options set in the video tag
9207    // which overrides globally set options.
9208    // This latter part coincides with the load order
9209    // (tag must exist before Player)
9210    options = (0, _obj.assign)(Player.getTagSettings(tag), options);
9211
9212    // Delay the initialization of children because we need to set up
9213    // player properties first, and can't use `this` before `super()`
9214    options.initChildren = false;
9215
9216    // Same with creating the element
9217    options.createEl = false;
9218
9219    // we don't want the player to report touch activity on itself
9220    // see enableTouchActivity in Component
9221    options.reportTouchActivity = false;
9222
9223    // If language is not set, get the closest lang attribute
9224    if (!options.language) {
9225      if (typeof tag.closest === 'function') {
9226        var closest = tag.closest('[lang]');
9227
9228        if (closest) {
9229          options.language = closest.getAttribute('lang');
9230        }
9231      } else {
9232        var element = tag;
9233
9234        while (element && element.nodeType === 1) {
9235          if (Dom.getElAttributes(element).hasOwnProperty('lang')) {
9236            options.language = element.getAttribute('lang');
9237            break;
9238          }
9239          element = element.parentNode;
9240        }
9241      }
9242    }
9243
9244    // Run base component initializing with new options
9245
9246    // if the global option object was accidentally blown away by
9247    // someone, bail early with an informative error
9248    var _this = _possibleConstructorReturn(this, _Component.call(this, null, options, ready));
9249
9250    if (!_this.options_ || !_this.options_.techOrder || !_this.options_.techOrder.length) {
9251      throw new Error('No techOrder specified. Did you overwrite ' + 'videojs.options instead of just changing the ' + 'properties you want to override?');
9252    }
9253
9254    // Store the original tag used to set options
9255    _this.tag = tag;
9256
9257    // Store the tag attributes used to restore html5 element
9258    _this.tagAttributes = tag && Dom.getElAttributes(tag);
9259
9260    // Update current language
9261    _this.language(_this.options_.language);
9262
9263    // Update Supported Languages
9264    if (options.languages) {
9265      // Normalise player option languages to lowercase
9266      var languagesToLower = {};
9267
9268      Object.getOwnPropertyNames(options.languages).forEach(function (name) {
9269        languagesToLower[name.toLowerCase()] = options.languages[name];
9270      });
9271      _this.languages_ = languagesToLower;
9272    } else {
9273      _this.languages_ = Player.prototype.options_.languages;
9274    }
9275
9276    // Cache for video property values.
9277    _this.cache_ = {};
9278
9279    // Set poster
9280    _this.poster_ = options.poster || '';
9281
9282    // Set controls
9283    _this.controls_ = !!options.controls;
9284
9285    // Original tag settings stored in options
9286    // now remove immediately so native controls don't flash.
9287    // May be turned back on by HTML5 tech if nativeControlsForTouch is true
9288    tag.controls = false;
9289
9290    /*
9291     * Store the internal state of scrubbing
9292     *
9293     * @private
9294     * @return {Boolean} True if the user is scrubbing
9295     */
9296    _this.scrubbing_ = false;
9297
9298    _this.el_ = _this.createEl();
9299
9300    // We also want to pass the original player options to each component and plugin
9301    // as well so they don't need to reach back into the player for options later.
9302    // We also need to do another copy of this.options_ so we don't end up with
9303    // an infinite loop.
9304    var playerOptionsCopy = (0, _mergeOptions2['default'])(_this.options_);
9305
9306    // Load plugins
9307    if (options.plugins) {
9308      var plugins = options.plugins;
9309
9310      Object.getOwnPropertyNames(plugins).forEach(function (name) {
9311        if (typeof this[name] === 'function') {
9312          this[name](plugins[name]);
9313        } else {
9314          _log2['default'].error('Unable to find plugin:', name);
9315        }
9316      }, _this);
9317    }
9318
9319    _this.options_.playerOptions = playerOptionsCopy;
9320
9321    _this.initChildren();
9322
9323    // Set isAudio based on whether or not an audio tag was used
9324    _this.isAudio(tag.nodeName.toLowerCase() === 'audio');
9325
9326    // Update controls className. Can't do this when the controls are initially
9327    // set because the element doesn't exist yet.
9328    if (_this.controls()) {
9329      _this.addClass('vjs-controls-enabled');
9330    } else {
9331      _this.addClass('vjs-controls-disabled');
9332    }
9333
9334    // Set ARIA label and region role depending on player type
9335    _this.el_.setAttribute('role', 'region');
9336    if (_this.isAudio()) {
9337      _this.el_.setAttribute('aria-label', 'audio player');
9338    } else {
9339      _this.el_.setAttribute('aria-label', 'video player');
9340    }
9341
9342    if (_this.isAudio()) {
9343      _this.addClass('vjs-audio');
9344    }
9345
9346    if (_this.flexNotSupported_()) {
9347      _this.addClass('vjs-no-flex');
9348    }
9349
9350    // TODO: Make this smarter. Toggle user state between touching/mousing
9351    // using events, since devices can have both touch and mouse events.
9352    // if (browser.TOUCH_ENABLED) {
9353    //   this.addClass('vjs-touch-enabled');
9354    // }
9355
9356    // iOS Safari has broken hover handling
9357    if (!browser.IS_IOS) {
9358      _this.addClass('vjs-workinghover');
9359    }
9360
9361    // Make player easily findable by ID
9362    Player.players[_this.id_] = _this;
9363
9364    // Add a major version class to aid css in plugins
9365    var majorVersion = '5.20.2'.split('.')[0];
9366
9367    _this.addClass('vjs-v' + majorVersion);
9368
9369    // When the player is first initialized, trigger activity so components
9370    // like the control bar show themselves if needed
9371    _this.userActive(true);
9372    _this.reportUserActivity();
9373    _this.listenForUserActivity_();
9374
9375    _this.on('fullscreenchange', _this.handleFullscreenChange_);
9376    _this.on('stageclick', _this.handleStageClick_);
9377    return _this;
9378  }
9379
9380  /**
9381   * Destroys the video player and does any necessary cleanup.
9382   *
9383   * This is especially helpful if you are dynamically adding and removing videos
9384   * to/from the DOM.
9385   *
9386   * @fires Player#dispose
9387   */
9388
9389
9390  Player.prototype.dispose = function dispose() {
9391    /**
9392     * Called when the player is being disposed of.
9393     *
9394     * @event Player#dispose
9395     * @type {EventTarget~Event}
9396     */
9397    this.trigger('dispose');
9398    // prevent dispose from being called twice
9399    this.off('dispose');
9400
9401    if (this.styleEl_ && this.styleEl_.parentNode) {
9402      this.styleEl_.parentNode.removeChild(this.styleEl_);
9403    }
9404
9405    // Kill reference to this player
9406    Player.players[this.id_] = null;
9407
9408    if (this.tag && this.tag.player) {
9409      this.tag.player = null;
9410    }
9411
9412    if (this.el_ && this.el_.player) {
9413      this.el_.player = null;
9414    }
9415
9416    if (this.tech_) {
9417      this.tech_.dispose();
9418    }
9419
9420    _Component.prototype.dispose.call(this);
9421  };
9422
9423  /**
9424   * Create the `Player`'s DOM element.
9425   *
9426   * @return {Element}
9427   *         The DOM element that gets created.
9428   */
9429
9430
9431  Player.prototype.createEl = function createEl() {
9432    var tag = this.tag;
9433    var el = void 0;
9434    var playerElIngest = this.playerElIngest_ = tag.parentNode && tag.parentNode.hasAttribute && tag.parentNode.hasAttribute('data-vjs-player');
9435
9436    if (playerElIngest) {
9437      el = this.el_ = tag.parentNode;
9438    } else {
9439      el = this.el_ = _Component.prototype.createEl.call(this, 'div');
9440    }
9441
9442    // set tabindex to -1 so we could focus on the player element
9443    tag.setAttribute('tabindex', '-1');
9444
9445    // Remove width/height attrs from tag so CSS can make it 100% width/height
9446    tag.removeAttribute('width');
9447    tag.removeAttribute('height');
9448
9449    // Copy over all the attributes from the tag, including ID and class
9450    // ID will now reference player box, not the video tag
9451    var attrs = Dom.getElAttributes(tag);
9452
9453    Object.getOwnPropertyNames(attrs).forEach(function (attr) {
9454      // workaround so we don't totally break IE7
9455      // http://stackoverflow.com/questions/3653444/css-styles-not-applied-on-dynamic-elements-in-internet-explorer-7
9456      if (attr === 'class') {
9457        el.className += ' ' + attrs[attr];
9458      } else {
9459        el.setAttribute(attr, attrs[attr]);
9460      }
9461    });
9462
9463    // Update tag id/class for use as HTML5 playback tech
9464    // Might think we should do this after embedding in container so .vjs-tech class
9465    // doesn't flash 100% width/height, but class only applies with .video-js parent
9466    tag.playerId = tag.id;
9467    tag.id += '_html5_api';
9468    tag.className = 'vjs-tech';
9469
9470    // Make player findable on elements
9471    tag.player = el.player = this;
9472    // Default state of video is paused
9473    this.addClass('vjs-paused');
9474
9475    // Add a style element in the player that we'll use to set the width/height
9476    // of the player in a way that's still overrideable by CSS, just like the
9477    // video element
9478    if (_window2['default'].VIDEOJS_NO_DYNAMIC_STYLE !== true) {
9479      this.styleEl_ = stylesheet.createStyleElement('vjs-styles-dimensions');
9480      var defaultsStyleEl = Dom.$('.vjs-styles-defaults');
9481      var head = Dom.$('head');
9482
9483      head.insertBefore(this.styleEl_, defaultsStyleEl ? defaultsStyleEl.nextSibling : head.firstChild);
9484    }
9485
9486    // Pass in the width/height/aspectRatio options which will update the style el
9487    this.width(this.options_.width);
9488    this.height(this.options_.height);
9489    this.fluid(this.options_.fluid);
9490    this.aspectRatio(this.options_.aspectRatio);
9491
9492    // Hide any links within the video/audio tag, because IE doesn't hide them completely.
9493    var links = tag.getElementsByTagName('a');
9494
9495    for (var i = 0; i < links.length; i++) {
9496      var linkEl = links.item(i);
9497
9498      Dom.addElClass(linkEl, 'vjs-hidden');
9499      linkEl.setAttribute('hidden', 'hidden');
9500    }
9501
9502    // insertElFirst seems to cause the networkState to flicker from 3 to 2, so
9503    // keep track of the original for later so we can know if the source originally failed
9504    tag.initNetworkState_ = tag.networkState;
9505
9506    // Wrap video tag in div (el/box) container
9507    if (tag.parentNode && !playerElIngest) {
9508      tag.parentNode.insertBefore(el, tag);
9509    }
9510
9511    // insert the tag as the first child of the player element
9512    // then manually add it to the children array so that this.addChild
9513    // will work properly for other components
9514    //
9515    // Breaks iPhone, fixed in HTML5 setup.
9516    Dom.insertElFirst(tag, el);
9517    this.children_.unshift(tag);
9518
9519    this.el_ = el;
9520
9521    return el;
9522  };
9523
9524  /**
9525   * A getter/setter for the `Player`'s width.
9526   *
9527   * @param {number} [value]
9528   *        The value to set the `Player's width to.
9529   *
9530   * @return {number}
9531   *         The current width of the `Player`.
9532   */
9533
9534
9535  Player.prototype.width = function width(value) {
9536    return this.dimension('width', value);
9537  };
9538
9539  /**
9540   * A getter/setter for the `Player`'s height.
9541   *
9542   * @param {number} [value]
9543   *        The value to set the `Player's heigth to.
9544   *
9545   * @return {number}
9546   *         The current heigth of the `Player`.
9547   */
9548
9549
9550  Player.prototype.height = function height(value) {
9551    return this.dimension('height', value);
9552  };
9553
9554  /**
9555   * A getter/setter for the `Player`'s width & height.
9556   *
9557   * @param {string} dimension
9558   *        This string can be:
9559   *        - 'width'
9560   *        - 'height'
9561   *
9562   * @param {number} [value]
9563   *        Value for dimension specified in the first argument.
9564   *
9565   * @return {Player|number}
9566   *         - Returns itself when setting; method can be chained.
9567   *         - The dimension arguments value when getting (width/height).
9568   */
9569
9570
9571  Player.prototype.dimension = function dimension(_dimension, value) {
9572    var privDimension = _dimension + '_';
9573
9574    if (value === undefined) {
9575      return this[privDimension] || 0;
9576    }
9577
9578    if (value === '') {
9579      // If an empty string is given, reset the dimension to be automatic
9580      this[privDimension] = undefined;
9581    } else {
9582      var parsedVal = parseFloat(value);
9583
9584      if (isNaN(parsedVal)) {
9585        _log2['default'].error('Improper value "' + value + '" supplied for for ' + _dimension);
9586        return this;
9587      }
9588
9589      this[privDimension] = parsedVal;
9590    }
9591
9592    this.updateStyleEl_();
9593    return this;
9594  };
9595
9596  /**
9597   * A getter/setter/toggler for the vjs-fluid `className` on the `Player`.
9598   *
9599   * @param {boolean} [bool]
9600   *        - A value of true adds the class.
9601   *        - A value of false removes the class.
9602   *        - No value will toggle the fluid class.
9603   *
9604   * @return {boolean|undefined}
9605   *         - The value of fluid when getting.
9606   *         - `undefined` when setting.
9607   */
9608
9609
9610  Player.prototype.fluid = function fluid(bool) {
9611    if (bool === undefined) {
9612      return !!this.fluid_;
9613    }
9614
9615    this.fluid_ = !!bool;
9616
9617    if (bool) {
9618      this.addClass('vjs-fluid');
9619    } else {
9620      this.removeClass('vjs-fluid');
9621    }
9622
9623    this.updateStyleEl_();
9624  };
9625
9626  /**
9627   * Get/Set the aspect ratio
9628   *
9629   * @param {string} [ratio]
9630   *        Aspect ratio for player
9631   *
9632   * @return {string|undefined}
9633   *         returns the current aspect ratio when getting
9634   */
9635
9636  /**
9637   * A getter/setter for the `Player`'s aspect ratio.
9638   *
9639   * @param {string} [ratio]
9640   *        The value to set the `Player's aspect ratio to.
9641   *
9642   * @return {string|undefined}
9643   *         - The current aspect ratio of the `Player` when getting.
9644   *         - undefined when setting
9645   */
9646
9647
9648  Player.prototype.aspectRatio = function aspectRatio(ratio) {
9649    if (ratio === undefined) {
9650      return this.aspectRatio_;
9651    }
9652
9653    // Check for width:height format
9654    if (!/^\d+\:\d+$/.test(ratio)) {
9655      throw new Error('Improper value supplied for aspect ratio. The format should be width:height, for example 16:9.');
9656    }
9657    this.aspectRatio_ = ratio;
9658
9659    // We're assuming if you set an aspect ratio you want fluid mode,
9660    // because in fixed mode you could calculate width and height yourself.
9661    this.fluid(true);
9662
9663    this.updateStyleEl_();
9664  };
9665
9666  /**
9667   * Update styles of the `Player` element (height, width and aspect ratio).
9668   *
9669   * @private
9670   * @listens Tech#loadedmetadata
9671   */
9672
9673
9674  Player.prototype.updateStyleEl_ = function updateStyleEl_() {
9675    if (_window2['default'].VIDEOJS_NO_DYNAMIC_STYLE === true) {
9676      var _width = typeof this.width_ === 'number' ? this.width_ : this.options_.width;
9677      var _height = typeof this.height_ === 'number' ? this.height_ : this.options_.height;
9678      var techEl = this.tech_ && this.tech_.el();
9679
9680      if (techEl) {
9681        if (_width >= 0) {
9682          techEl.width = _width;
9683        }
9684        if (_height >= 0) {
9685          techEl.height = _height;
9686        }
9687      }
9688
9689      return;
9690    }
9691
9692    var width = void 0;
9693    var height = void 0;
9694    var aspectRatio = void 0;
9695    var idClass = void 0;
9696
9697    // The aspect ratio is either used directly or to calculate width and height.
9698    if (this.aspectRatio_ !== undefined && this.aspectRatio_ !== 'auto') {
9699      // Use any aspectRatio that's been specifically set
9700      aspectRatio = this.aspectRatio_;
9701    } else if (this.videoWidth() > 0) {
9702      // Otherwise try to get the aspect ratio from the video metadata
9703      aspectRatio = this.videoWidth() + ':' + this.videoHeight();
9704    } else {
9705      // Or use a default. The video element's is 2:1, but 16:9 is more common.
9706      aspectRatio = '16:9';
9707    }
9708
9709    // Get the ratio as a decimal we can use to calculate dimensions
9710    var ratioParts = aspectRatio.split(':');
9711    var ratioMultiplier = ratioParts[1] / ratioParts[0];
9712
9713    if (this.width_ !== undefined) {
9714      // Use any width that's been specifically set
9715      width = this.width_;
9716    } else if (this.height_ !== undefined) {
9717      // Or calulate the width from the aspect ratio if a height has been set
9718      width = this.height_ / ratioMultiplier;
9719    } else {
9720      // Or use the video's metadata, or use the video el's default of 300
9721      width = this.videoWidth() || 300;
9722    }
9723
9724    if (this.height_ !== undefined) {
9725      // Use any height that's been specifically set
9726      height = this.height_;
9727    } else {
9728      // Otherwise calculate the height from the ratio and the width
9729      height = width * ratioMultiplier;
9730    }
9731
9732    // Ensure the CSS class is valid by starting with an alpha character
9733    if (/^[^a-zA-Z]/.test(this.id())) {
9734      idClass = 'dimensions-' + this.id();
9735    } else {
9736      idClass = this.id() + '-dimensions';
9737    }
9738
9739    // Ensure the right class is still on the player for the style element
9740    this.addClass(idClass);
9741
9742    stylesheet.setTextContent(this.styleEl_, '\n      .' + idClass + ' {\n        width: ' + width + 'px;\n        height: ' + height + 'px;\n      }\n\n      .' + idClass + '.vjs-fluid {\n        padding-top: ' + ratioMultiplier * 100 + '%;\n      }\n    ');
9743  };
9744
9745  /**
9746   * Load/Create an instance of playback {@link Tech} including element
9747   * and API methods. Then append the `Tech` element in `Player` as a child.
9748   *
9749   * @param {string} techName
9750   *        name of the playback technology
9751   *
9752   * @param {string} source
9753   *        video source
9754   *
9755   * @private
9756   */
9757
9758
9759  Player.prototype.loadTech_ = function loadTech_(techName, source) {
9760    var _this2 = this;
9761
9762    // Pause and remove current playback technology
9763    if (this.tech_) {
9764      this.unloadTech_();
9765    }
9766
9767    // get rid of the HTML5 video tag as soon as we are using another tech
9768    if (techName !== 'Html5' && this.tag) {
9769      _tech2['default'].getTech('Html5').disposeMediaElement(this.tag);
9770      this.tag.player = null;
9771      this.tag = null;
9772    }
9773
9774    this.techName_ = techName;
9775
9776    // Turn off API access because we're loading a new tech that might load asynchronously
9777    this.isReady_ = false;
9778
9779    // Grab tech-specific options from player options and add source and parent element to use.
9780    var techOptions = (0, _obj.assign)({
9781      source: source,
9782      'nativeControlsForTouch': this.options_.nativeControlsForTouch,
9783      'playerId': this.id(),
9784      'techId': this.id() + '_' + techName + '_api',
9785      'videoTracks': this.videoTracks_,
9786      'textTracks': this.textTracks_,
9787      'audioTracks': this.audioTracks_,
9788      'autoplay': this.options_.autoplay,
9789      'playsinline': this.options_.playsinline,
9790      'preload': this.options_.preload,
9791      'loop': this.options_.loop,
9792      'muted': this.options_.muted,
9793      'poster': this.poster(),
9794      'language': this.language(),
9795      'playerElIngest': this.playerElIngest_ || false,
9796      'vtt.js': this.options_['vtt.js']
9797    }, this.options_[techName.toLowerCase()]);
9798
9799    if (this.tag) {
9800      techOptions.tag = this.tag;
9801    }
9802
9803    if (source) {
9804      this.currentType_ = source.type;
9805
9806      if (source.src === this.cache_.src && this.cache_.currentTime > 0) {
9807        techOptions.startTime = this.cache_.currentTime;
9808      }
9809
9810      this.cache_.sources = null;
9811      this.cache_.source = source;
9812      this.cache_.src = source.src;
9813    }
9814
9815    // Initialize tech instance
9816    var TechComponent = _tech2['default'].getTech(techName);
9817
9818    // Support old behavior of techs being registered as components.
9819    // Remove once that deprecated behavior is removed.
9820    if (!TechComponent) {
9821      TechComponent = _component2['default'].getComponent(techName);
9822    }
9823    this.tech_ = new TechComponent(techOptions);
9824
9825    // player.triggerReady is always async, so don't need this to be async
9826    this.tech_.ready(Fn.bind(this, this.handleTechReady_), true);
9827
9828    _textTrackListConverter2['default'].jsonToTextTracks(this.textTracksJson_ || [], this.tech_);
9829
9830    // Listen to all HTML5-defined events and trigger them on the player
9831    TECH_EVENTS_RETRIGGER.forEach(function (event) {
9832      _this2.on(_this2.tech_, event, _this2['handleTech' + (0, _toTitleCase2['default'])(event) + '_']);
9833    });
9834    this.on(this.tech_, 'loadstart', this.handleTechLoadStart_);
9835    this.on(this.tech_, 'waiting', this.handleTechWaiting_);
9836    this.on(this.tech_, 'canplay', this.handleTechCanPlay_);
9837    this.on(this.tech_, 'canplaythrough', this.handleTechCanPlayThrough_);
9838    this.on(this.tech_, 'playing', this.handleTechPlaying_);
9839    this.on(this.tech_, 'ended', this.handleTechEnded_);
9840    this.on(this.tech_, 'seeking', this.handleTechSeeking_);
9841    this.on(this.tech_, 'seeked', this.handleTechSeeked_);
9842    this.on(this.tech_, 'play', this.handleTechPlay_);
9843    this.on(this.tech_, 'firstplay', this.handleTechFirstPlay_);
9844    this.on(this.tech_, 'pause', this.handleTechPause_);
9845    this.on(this.tech_, 'durationchange', this.handleTechDurationChange_);
9846    this.on(this.tech_, 'fullscreenchange', this.handleTechFullscreenChange_);
9847    this.on(this.tech_, 'error', this.handleTechError_);
9848    this.on(this.tech_, 'loadedmetadata', this.updateStyleEl_);
9849    this.on(this.tech_, 'posterchange', this.handleTechPosterChange_);
9850    this.on(this.tech_, 'textdata', this.handleTechTextData_);
9851
9852    this.usingNativeControls(this.techGet_('controls'));
9853
9854    if (this.controls() && !this.usingNativeControls()) {
9855      this.addTechControlsListeners_();
9856    }
9857
9858    // Add the tech element in the DOM if it was not already there
9859    // Make sure to not insert the original video element if using Html5
9860    if (this.tech_.el().parentNode !== this.el() && (techName !== 'Html5' || !this.tag)) {
9861      Dom.insertElFirst(this.tech_.el(), this.el());
9862    }
9863
9864    // Get rid of the original video tag reference after the first tech is loaded
9865    if (this.tag) {
9866      this.tag.player = null;
9867      this.tag = null;
9868    }
9869  };
9870
9871  /**
9872   * Unload and dispose of the current playback {@link Tech}.
9873   *
9874   * @private
9875   */
9876
9877
9878  Player.prototype.unloadTech_ = function unloadTech_() {
9879    // Save the current text tracks so that we can reuse the same text tracks with the next tech
9880    this.videoTracks_ = this.videoTracks();
9881    this.textTracks_ = this.textTracks();
9882    this.audioTracks_ = this.audioTracks();
9883    this.textTracksJson_ = _textTrackListConverter2['default'].textTracksToJson(this.tech_);
9884
9885    this.isReady_ = false;
9886
9887    this.tech_.dispose();
9888
9889    this.tech_ = false;
9890  };
9891
9892  /**
9893   * Return a reference to the current {@link Tech}, but only if given an object with the
9894   * `IWillNotUseThisInPlugins` property having a true value. This is try and prevent misuse
9895   * of techs by plugins.
9896   *
9897   * @param {Object} safety
9898   *        An object that must contain `{IWillNotUseThisInPlugins: true}`
9899   *
9900   * @param {boolean} safety.IWillNotUseThisInPlugins
9901   *        Must be set to true or else this function will throw an error.
9902   *
9903   * @return {Tech}
9904   *         The Tech
9905   */
9906
9907
9908  Player.prototype.tech = function tech(safety) {
9909    if (safety && safety.IWillNotUseThisInPlugins) {
9910      return this.tech_;
9911    }
9912    var errorText = '\n      Please make sure that you are not using this inside of a plugin.\n      To disable this alert and error, please pass in an object with\n      `IWillNotUseThisInPlugins` to the `tech` method. See\n      https://github.com/videojs/video.js/issues/2617 for more info.\n    ';
9913
9914    _window2['default'].alert(errorText);
9915    throw new Error(errorText);
9916  };
9917
9918  /**
9919   * Set up click and touch listeners for the playback element
9920   *
9921   * - On desktops: a click on the video itself will toggle playback
9922   * - On mobile devices: a click on the video toggles controls
9923   *   which is done by toggling the user state between active and
9924   *   inactive
9925   * - A tap can signal that a user has become active or has become inactive
9926   *   e.g. a quick tap on an iPhone movie should reveal the controls. Another
9927   *   quick tap should hide them again (signaling the user is in an inactive
9928   *   viewing state)
9929   * - In addition to this, we still want the user to be considered inactive after
9930   *   a few seconds of inactivity.
9931   *
9932   * > Note: the only part of iOS interaction we can't mimic with this setup
9933   * is a touch and hold on the video element counting as activity in order to
9934   * keep the controls showing, but that shouldn't be an issue. A touch and hold
9935   * on any controls will still keep the user active
9936   *
9937   * @private
9938   */
9939
9940
9941  Player.prototype.addTechControlsListeners_ = function addTechControlsListeners_() {
9942    // Make sure to remove all the previous listeners in case we are called multiple times.
9943    this.removeTechControlsListeners_();
9944
9945    // Some browsers (Chrome & IE) don't trigger a click on a flash swf, but do
9946    // trigger mousedown/up.
9947    // http://stackoverflow.com/questions/1444562/javascript-onclick-event-over-flash-object
9948    // Any touch events are set to block the mousedown event from happening
9949    this.on(this.tech_, 'mousedown', this.handleTechClick_);
9950
9951    // If the controls were hidden we don't want that to change without a tap event
9952    // so we'll check if the controls were already showing before reporting user
9953    // activity
9954    this.on(this.tech_, 'touchstart', this.handleTechTouchStart_);
9955    this.on(this.tech_, 'touchmove', this.handleTechTouchMove_);
9956    this.on(this.tech_, 'touchend', this.handleTechTouchEnd_);
9957
9958    // The tap listener needs to come after the touchend listener because the tap
9959    // listener cancels out any reportedUserActivity when setting userActive(false)
9960    this.on(this.tech_, 'tap', this.handleTechTap_);
9961  };
9962
9963  /**
9964   * Remove the listeners used for click and tap controls. This is needed for
9965   * toggling to controls disabled, where a tap/touch should do nothing.
9966   *
9967   * @private
9968   */
9969
9970
9971  Player.prototype.removeTechControlsListeners_ = function removeTechControlsListeners_() {
9972    // We don't want to just use `this.off()` because there might be other needed
9973    // listeners added by techs that extend this.
9974    this.off(this.tech_, 'tap', this.handleTechTap_);
9975    this.off(this.tech_, 'touchstart', this.handleTechTouchStart_);
9976    this.off(this.tech_, 'touchmove', this.handleTechTouchMove_);
9977    this.off(this.tech_, 'touchend', this.handleTechTouchEnd_);
9978    this.off(this.tech_, 'mousedown', this.handleTechClick_);
9979  };
9980
9981  /**
9982   * Player waits for the tech to be ready
9983   *
9984   * @private
9985   */
9986
9987
9988  Player.prototype.handleTechReady_ = function handleTechReady_() {
9989    this.triggerReady();
9990
9991    // Keep the same volume as before
9992    if (this.cache_.volume) {
9993      this.techCall_('setVolume', this.cache_.volume);
9994    }
9995
9996    // Look if the tech found a higher resolution poster while loading
9997    this.handleTechPosterChange_();
9998
9999    // Update the duration if available
10000    this.handleTechDurationChange_();
10001
10002    // Chrome and Safari both have issues with autoplay.
10003    // In Safari (5.1.1), when we move the video element into the container div, autoplay doesn't work.
10004    // In Chrome (15), if you have autoplay + a poster + no controls, the video gets hidden (but audio plays)
10005    // This fixes both issues. Need to wait for API, so it updates displays correctly
10006    if ((this.src() || this.currentSrc()) && this.tag && this.options_.autoplay && this.paused()) {
10007      try {
10008        // Chrome Fix. Fixed in Chrome v16.
10009        delete this.tag.poster;
10010      } catch (e) {
10011        (0, _log2['default'])('deleting tag.poster throws in some browsers', e);
10012      }
10013      this.play();
10014    }
10015  };
10016
10017  /**
10018   * Retrigger the `loadstart` event that was triggered by the {@link Tech}. This
10019   * function will also trigger {@link Player#firstplay} if it is the first loadstart
10020   * for a video.
10021   *
10022   * @fires Player#loadstart
10023   * @fires Player#firstplay
10024   * @listens Tech#loadstart
10025   * @private
10026   */
10027
10028
10029  Player.prototype.handleTechLoadStart_ = function handleTechLoadStart_() {
10030    // TODO: Update to use `emptied` event instead. See #1277.
10031
10032    this.removeClass('vjs-ended');
10033    this.removeClass('vjs-seeking');
10034
10035    // reset the error state
10036    this.error(null);
10037
10038    // If it's already playing we want to trigger a firstplay event now.
10039    // The firstplay event relies on both the play and loadstart events
10040    // which can happen in any order for a new source
10041    if (!this.paused()) {
10042      /**
10043       * Fired when the user agent begins looking for media data
10044       *
10045       * @event Player#loadstart
10046       * @type {EventTarget~Event}
10047       */
10048      this.trigger('loadstart');
10049      this.trigger('firstplay');
10050    } else {
10051      // reset the hasStarted state
10052      this.hasStarted(false);
10053      this.trigger('loadstart');
10054    }
10055  };
10056
10057  /**
10058   * Add/remove the vjs-has-started class
10059   *
10060   * @fires Player#firstplay
10061   *
10062   * @param {boolean} hasStarted
10063   *        - true: adds the class
10064   *        - false: remove the class
10065   *
10066   * @return {boolean}
10067   *         the boolean value of hasStarted
10068   */
10069
10070
10071  Player.prototype.hasStarted = function hasStarted(_hasStarted) {
10072    if (_hasStarted !== undefined) {
10073      // only update if this is a new value
10074      if (this.hasStarted_ !== _hasStarted) {
10075        this.hasStarted_ = _hasStarted;
10076        if (_hasStarted) {
10077          this.addClass('vjs-has-started');
10078          // trigger the firstplay event if this newly has played
10079          this.trigger('firstplay');
10080        } else {
10081          this.removeClass('vjs-has-started');
10082        }
10083      }
10084      return this;
10085    }
10086    return !!this.hasStarted_;
10087  };
10088
10089  /**
10090   * Fired whenever the media begins or resumes playback
10091   *
10092   * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-play}
10093   * @fires Player#play
10094   * @listens Tech#play
10095   * @private
10096   */
10097
10098
10099  Player.prototype.handleTechPlay_ = function handleTechPlay_() {
10100    this.removeClass('vjs-ended');
10101    this.removeClass('vjs-paused');
10102    this.addClass('vjs-playing');
10103
10104    // hide the poster when the user hits play
10105    this.hasStarted(true);
10106    /**
10107     * Triggered whenever an {@link Tech#play} event happens. Indicates that
10108     * playback has started or resumed.
10109     *
10110     * @event Player#play
10111     * @type {EventTarget~Event}
10112     */
10113    this.trigger('play');
10114  };
10115
10116  /**
10117   * Retrigger the `waiting` event that was triggered by the {@link Tech}.
10118   *
10119   * @fires Player#waiting
10120   * @listens Tech#waiting
10121   * @private
10122   */
10123
10124
10125  Player.prototype.handleTechWaiting_ = function handleTechWaiting_() {
10126    var _this3 = this;
10127
10128    this.addClass('vjs-waiting');
10129    /**
10130     * A readyState change on the DOM element has caused playback to stop.
10131     *
10132     * @event Player#waiting
10133     * @type {EventTarget~Event}
10134     */
10135    this.trigger('waiting');
10136    this.one('timeupdate', function () {
10137      return _this3.removeClass('vjs-waiting');
10138    });
10139  };
10140
10141  /**
10142   * Retrigger the `canplay` event that was triggered by the {@link Tech}.
10143   * > Note: This is not consistent between browsers. See #1351
10144   *
10145   * @fires Player#canplay
10146   * @listens Tech#canplay
10147   * @private
10148   */
10149
10150
10151  Player.prototype.handleTechCanPlay_ = function handleTechCanPlay_() {
10152    this.removeClass('vjs-waiting');
10153    /**
10154     * The media has a readyState of HAVE_FUTURE_DATA or greater.
10155     *
10156     * @event Player#canplay
10157     * @type {EventTarget~Event}
10158     */
10159    this.trigger('canplay');
10160  };
10161
10162  /**
10163   * Retrigger the `canplaythrough` event that was triggered by the {@link Tech}.
10164   *
10165   * @fires Player#canplaythrough
10166   * @listens Tech#canplaythrough
10167   * @private
10168   */
10169
10170
10171  Player.prototype.handleTechCanPlayThrough_ = function handleTechCanPlayThrough_() {
10172    this.removeClass('vjs-waiting');
10173    /**
10174     * The media has a readyState of HAVE_ENOUGH_DATA or greater. This means that the
10175     * entire media file can be played without buffering.
10176     *
10177     * @event Player#canplaythrough
10178     * @type {EventTarget~Event}
10179     */
10180    this.trigger('canplaythrough');
10181  };
10182
10183  /**
10184   * Retrigger the `playing` event that was triggered by the {@link Tech}.
10185   *
10186   * @fires Player#playing
10187   * @listens Tech#playing
10188   * @private
10189   */
10190
10191
10192  Player.prototype.handleTechPlaying_ = function handleTechPlaying_() {
10193    this.removeClass('vjs-waiting');
10194    /**
10195     * The media is no longer blocked from playback, and has started playing.
10196     *
10197     * @event Player#playing
10198     * @type {EventTarget~Event}
10199     */
10200    this.trigger('playing');
10201  };
10202
10203  /**
10204   * Retrigger the `seeking` event that was triggered by the {@link Tech}.
10205   *
10206   * @fires Player#seeking
10207   * @listens Tech#seeking
10208   * @private
10209   */
10210
10211
10212  Player.prototype.handleTechSeeking_ = function handleTechSeeking_() {
10213    this.addClass('vjs-seeking');
10214    /**
10215     * Fired whenever the player is jumping to a new time
10216     *
10217     * @event Player#seeking
10218     * @type {EventTarget~Event}
10219     */
10220    this.trigger('seeking');
10221  };
10222
10223  /**
10224   * Retrigger the `seeked` event that was triggered by the {@link Tech}.
10225   *
10226   * @fires Player#seeked
10227   * @listens Tech#seeked
10228   * @private
10229   */
10230
10231
10232  Player.prototype.handleTechSeeked_ = function handleTechSeeked_() {
10233    this.removeClass('vjs-seeking');
10234    /**
10235     * Fired when the player has finished jumping to a new time
10236     *
10237     * @event Player#seeked
10238     * @type {EventTarget~Event}
10239     */
10240    this.trigger('seeked');
10241  };
10242
10243  /**
10244   * Retrigger the `firstplay` event that was triggered by the {@link Tech}.
10245   *
10246   * @fires Player#firstplay
10247   * @listens Tech#firstplay
10248   * @deprecated As of 6.0 passing the `starttime` option to the player will be deprecated
10249   * @private
10250   */
10251
10252
10253  Player.prototype.handleTechFirstPlay_ = function handleTechFirstPlay_() {
10254    // If the first starttime attribute is specified
10255    // then we will start at the given offset in seconds
10256    if (this.options_.starttime) {
10257      _log2['default'].warn('Passing the `starttime` option to the player will be deprecated 
vendor: 6,466 bytes, lines 10257-10547
10257in 6.0');
10258      this.currentTime(this.options_.starttime);
10259    }
10260
10261    this.addClass('vjs-has-started');
10262    /**
10263     * Fired the first time a video is played. Not part of the HLS spec, and this is
10264     * probably not the best implementation yet, so use sparingly. If you don't have a
10265     * reason to prevent playback, use `myPlayer.one('play');` instead.
10266     *
10267     * @event Player#firstplay
10268     * @type {EventTarget~Event}
10269     */
10270    this.trigger('firstplay');
10271  };
10272
10273  /**
10274   * Retrigger the `pause` event that was triggered by the {@link Tech}.
10275   *
10276   * @fires Player#pause
10277   * @listens Tech#pause
10278   * @private
10279   */
10280
10281
10282  Player.prototype.handleTechPause_ = function handleTechPause_() {
10283    this.removeClass('vjs-playing');
10284    this.addClass('vjs-paused');
10285    /**
10286     * Fired whenever the media has been paused
10287     *
10288     * @event Player#pause
10289     * @type {EventTarget~Event}
10290     */
10291    this.trigger('pause');
10292  };
10293
10294  /**
10295   * Retrigger the `ended` event that was triggered by the {@link Tech}.
10296   *
10297   * @fires Player#ended
10298   * @listens Tech#ended
10299   * @private
10300   */
10301
10302
10303  Player.prototype.handleTechEnded_ = function handleTechEnded_() {
10304    this.addClass('vjs-ended');
10305    if (this.options_.loop) {
10306      this.currentTime(0);
10307      this.play();
10308    } else if (!this.paused()) {
10309      this.pause();
10310    }
10311
10312    /**
10313     * Fired when the end of the media resource is reached (currentTime == duration)
10314     *
10315     * @event Player#ended
10316     * @type {EventTarget~Event}
10317     */
10318    this.trigger('ended');
10319  };
10320
10321  /**
10322   * Fired when the duration of the media resource is first known or changed
10323   *
10324   * @listens Tech#durationchange
10325   * @private
10326   */
10327
10328
10329  Player.prototype.handleTechDurationChange_ = function handleTechDurationChange_() {
10330    this.duration(this.techGet_('duration'));
10331  };
10332
10333  /**
10334   * Handle a click on the media element to play/pause
10335   *
10336   * @param {EventTarget~Event} event
10337   *        the event that caused this function to trigger
10338   *
10339   * @listens Tech#mousedown
10340   * @private
10341   */
10342
10343
10344  Player.prototype.handleTechClick_ = function handleTechClick_(event) {
10345    // We're using mousedown to detect clicks thanks to Flash, but mousedown
10346    // will also be triggered with right-clicks, so we need to prevent that
10347    if (event.button !== 0) {
10348      return;
10349    }
10350
10351    // When controls are disabled a click should not toggle playback because
10352    // the click is considered a control
10353    if (this.controls()) {
10354      if (this.paused()) {
10355        this.play();
10356      } else {
10357        this.pause();
10358      }
10359    }
10360  };
10361
10362  /**
10363   * Handle a tap on the media element. It will toggle the user
10364   * activity state, which hides and shows the controls.
10365   *
10366   * @listens Tech#tap
10367   * @private
10368   */
10369
10370
10371  Player.prototype.handleTechTap_ = function handleTechTap_() {
10372    this.userActive(!this.userActive());
10373  };
10374
10375  /**
10376   * Handle touch to start
10377   *
10378   * @listens Tech#touchstart
10379   * @private
10380   */
10381
10382
10383  Player.prototype.handleTechTouchStart_ = function handleTechTouchStart_() {
10384    this.userWasActive = this.userActive();
10385  };
10386
10387  /**
10388   * Handle touch to move
10389   *
10390   * @listens Tech#touchmove
10391   * @private
10392   */
10393
10394
10395  Player.prototype.handleTechTouchMove_ = function handleTechTouchMove_() {
10396    if (this.userWasActive) {
10397      this.reportUserActivity();
10398    }
10399  };
10400
10401  /**
10402   * Handle touch to end
10403   *
10404   * @param {EventTarget~Event} event
10405   *        the touchend event that triggered
10406   *        this function
10407   *
10408   * @listens Tech#touchend
10409   * @private
10410   */
10411
10412
10413  Player.prototype.handleTechTouchEnd_ = function handleTechTouchEnd_(event) {
10414    // Stop the mouse events from also happening
10415    event.preventDefault();
10416  };
10417
10418  /**
10419   * Fired when the player switches in or out of fullscreen mode
10420   *
10421   * @private
10422   * @listens Player#fullscreenchange
10423   */
10424
10425
10426  Player.prototype.handleFullscreenChange_ = function handleFullscreenChange_() {
10427    if (this.isFullscreen()) {
10428      this.addClass('vjs-fullscreen');
10429    } else {
10430      this.removeClass('vjs-fullscreen');
10431    }
10432  };
10433
10434  /**
10435   * native click events on the SWF aren't triggered on IE11, Win8.1RT
10436   * use stageclick events triggered from inside the SWF instead
10437   *
10438   * @private
10439   * @listens stageclick
10440   */
10441
10442
10443  Player.prototype.handleStageClick_ = function handleStageClick_() {
10444    this.reportUserActivity();
10445  };
10446
10447  /**
10448   * Handle Tech Fullscreen Change
10449   *
10450   * @param {EventTarget~Event} event
10451   *        the fullscreenchange event that triggered this function
10452   *
10453   * @param {Object} data
10454   *        the data that was sent with the event
10455   *
10456   * @private
10457   * @listens Tech#fullscreenchange
10458   * @fires Player#fullscreenchange
10459   */
10460
10461
10462  Player.prototype.handleTechFullscreenChange_ = function handleTechFullscreenChange_(event, data) {
10463    if (data) {
10464      this.isFullscreen(data.isFullscreen);
10465    }
10466    /**
10467     * Fired when going in and out of fullscreen.
10468     *
10469     * @event Player#fullscreenchange
10470     * @type {EventTarget~Event}
10471     */
10472    this.trigger('fullscreenchange');
10473  };
10474
10475  /**
10476   * Fires when an error occurred during the loading of an audio/video.
10477   *
10478   * @private
10479   * @listens Tech#error
10480   */
10481
10482
10483  Player.prototype.handleTechError_ = function handleTechError_() {
10484    var error = this.tech_.error();
10485
10486    this.error(error);
10487  };
10488
10489  /**
10490   * Retrigger the `textdata` event that was triggered by the {@link Tech}.
10491   *
10492   * @fires Player#textdata
10493   * @listens Tech#textdata
10494   * @private
10495   */
10496
10497
10498  Player.prototype.handleTechTextData_ = function handleTechTextData_() {
10499    var data = null;
10500
10501    if (arguments.length > 1) {
10502      data = arguments[1];
10503    }
10504
10505    /**
10506     * Fires when we get a textdata event from tech
10507     *
10508     * @event Player#textdata
10509     * @type {EventTarget~Event}
10510     */
10511    this.trigger('textdata', data);
10512  };
10513
10514  /**
10515   * Get object for cached values.
10516   *
10517   * @return {Object}
10518   *         get the current object cache
10519   */
10520
10521
10522  Player.prototype.getCache = function getCache() {
10523    return this.cache_;
10524  };
10525
10526  /**
10527   * Pass values to the playback tech
10528   *
10529   * @param {string} [method]
10530   *        the method to call
10531   *
10532   * @param {Object} arg
10533   *        the argument to pass
10534   *
10535   * @private
10536   */
10537
10538
10539  Player.prototype.techCall_ = function techCall_(method, arg) {
10540    // If it's not ready yet, call method when it is
10541    if (this.tech_ && !this.tech_.isReady_) {
10542      this.tech_.ready(function () {
10543        this[method](arg);
10544      }, true);
10545
10546      // Otherwise call method now
10547    } else {
10548      try {
10549        if (this.tech_) {
10550          this.tech_[method](arg);
10551        }
10552      } catch (e) {
10553        (0, _log2['default'])(e);
10554        throw e;
10555      }
10556    }
10557  };
10558
10559  /**
10560   * Get calls can't wait for the tech, and sometimes don't need to.
10561   *
10562   * @param {string} method
10563   *        Tech method
10564   *
10565   * @return {Function|undefined}
10566   *         the method or undefined
10567   *
10568   * @private
10569   */
10570
10571
10572  Player.prototype.techGet_ = function techGet_(method) {
10573    if (this.tech_ && this.tech_.isReady_) {
10574
10575      // Flash likes to die and reload when you hide or reposition it.
10576      // In these cases the object methods go away and we get errors.
10577      // When that happens we'll catch the errors and inform tech that it's not ready any more.
10578      try {
10579        return this.tech_[method]();
10580      } catch (e) {
10581        // When building additional tech libs, an expected method may not be defined yet
10582        if (this.tech_[method] === undefined) {
10583          (0, _log2['default'])('Video.js: ' + method + ' method not defined for ' + this.techName_ + ' playback technology.', e);
10584
10585          // When a method isn't available on the object it throws a TypeError
10586        } else if (e.name === 'TypeError') {
10587          (0, _log2['default'])('Video.js: ' + method + ' unavailable on ' + this.techName_ + ' playback technology element.', e);
10588          this.tech_.isReady_ = false;
10589        } else {
10590          (0, _log2['default'])(e);
10591        }
10592        throw e;
10593      }
10594    }
10595
10596    return;
10597  };
10598
10599  /**
10600   * start media playback
10601   *
10602   * @return {Player}
10603   *         A reference to the player object this function was called on
10604   */
10605
10606
10607  Player.prototype.play = function play() {
10608    // Only calls the tech's play if we already have a src loaded
10609    if (this.src() || this.currentSrc()) {
10610      this.techCall_('play');
10611    } else {
10612      this.tech_.one('loadstart', function () {
10613        this.play();
10614      });
10615    }
10616
10617    return this;
10618  };
10619
10620  /**
10621   * Pause the video playback
10622   *
10623   * @return {Player}
10624   *         A reference to the player object this function was called on
10625   */
10626
10627
10628  Player.prototype.pause = function pause() {
10629    this.techCall_('pause');
10630    return this;
10631  };
10632
10633  /**
10634   * Check if the player is paused or has yet to play
10635   *
10636   * @return {boolean}
10637   *         - false: if the media is currently playing
10638   *         - true: if media is not currently playing
10639   */
10640
10641
10642  Player.prototype.paused = function paused() {
10643    // The initial state of paused should be true (in Safari it's actually false)
10644    return this.techGet_('paused') === false ? false : true;
10645  };
10646
10647  /**
10648   * Returns whether or not the user is "scrubbing". Scrubbing is
10649   * when the user has clicked the progress bar handle and is
10650   * dragging it along the progress bar.
10651   *
10652   * @param {boolean} [isScrubbing]
10653   *        wether the user is or is not scrubbing
10654   *
10655   * @return {boolean|Player}
10656   *         A instance of the player that called this function when setting,
10657   *         and the value of scrubbing when getting
10658   */
10659
10660
10661  Player.prototype.scrubbing = function scrubbing(isScrubbing) {
10662    if (isScrubbing !== undefined) {
10663      this.scrubbing_ = !!isScrubbing;
10664
10665      if (isScrubbing) {
10666        this.addClass('vjs-scrubbing');
10667      } else {
10668        this.removeClass('vjs-scrubbing');
10669      }
10670
10671      return this;
10672    }
10673
10674    return this.scrubbing_;
10675  };
10676
10677  /**
10678   * Get or set the current time (in seconds)
10679   *
10680   * @param {number|string} [seconds]
10681   *        The time to seek to in seconds
10682   *
10683   * @return {Player|number}
10684   *         - the current time in seconds when getting
10685   *         - a reference to the current player object when setting
10686   */
10687
10688
10689  Player.prototype.currentTime = function currentTime(seconds) {
10690    if (seconds !== undefined) {
10691
10692      this.techCall_('setCurrentTime', seconds);
10693
10694      return this;
10695    }
10696
10697    // cache last currentTime and return. default to 0 seconds
10698    //
10699    // Caching the currentTime is meant to prevent a massive amount of reads on the tech's
10700    // currentTime when scrubbing, but may not provide much performance benefit afterall.
10701    // Should be tested. Also something has to read the actual current time or the cache will
10702    // never get updated.
10703    this.cache_.currentTime = this.techGet_('currentTime') || 0;
10704    return this.cache_.currentTime;
10705  };
10706
10707  /**
10708   * Normally gets the length in time of the video in seconds;
10709   * in all but the rarest use cases an argument will NOT be passed to the method
10710   *
10711   * > **NOTE**: The video must have started loading before the duration can be
10712   * known, and in the case of Flash, may not be known until the video starts
10713   * playing.
10714   *
10715   * @fires Player#durationchange
10716   *
10717   * @param {number} [seconds]
10718   *        The duration of the video to set in seconds
10719   *
10720   * @return {number|Player}
10721   *         - The duration of the video in seconds when getting
10722   *         - A reference to the player that called this function
10723   *           when setting
10724   */
10725
10726
10727  Player.prototype.duration = function duration(seconds) {
10728    if (seconds === undefined) {
10729      // return NaN if the duration is not known
10730      return this.cache_.duration !== undefined ? this.cache_.duration : NaN;
10731    }
10732
10733    seconds = parseFloat(seconds);
10734
10735    // Standardize on Inifity for signaling video is live
10736    if (seconds < 0) {
10737      seconds = Infinity;
10738    }
10739
10740    if (seconds !== this.cache_.duration) {
10741      // Cache the last set value for optimized scrubbing (esp. Flash)
10742      this.cache_.duration = seconds;
10743
10744      if (seconds === Infinity) {
10745        this.addClass('vjs-live');
10746      } else {
10747        this.removeClass('vjs-live');
10748      }
10749      /**
10750       * @event Player#durationchange
10751       * @type {EventTarget~Event}
10752       */
10753      this.trigger('durationchange');
10754    }
10755
10756    return this;
10757  };
10758
10759  /**
10760   * Calculates how much time is left in the video. Not part
10761   * of the native video API.
10762   *
10763   * @return {number}
10764   *         The time remaining in seconds
10765   */
10766
10767
10768  Player.prototype.remainingTime = function remainingTime() {
10769    return this.duration() - this.currentTime();
10770  };
10771
10772  //
10773  // Kind of like an array of portions of the video that have been downloaded.
10774
10775  /**
10776   * Get a TimeRange object with an array of the times of the video
10777   * that have been downloaded. If you just want the percent of the
10778   * video that's been downloaded, use bufferedPercent.
10779   *
10780   * @see [Buffered Spec]{@link http://dev.w3.org/html5/spec/video.html#dom-media-buffered}
10781   *
10782   * @return {TimeRange}
10783   *         A mock TimeRange object (following HTML spec)
10784   */
10785
10786
10787  Player.prototype.buffered = function buffered() {
10788    var buffered = this.techGet_('buffered');
10789
10790    if (!buffered || !buffered.length) {
10791      buffered = (0, _timeRanges.createTimeRange)(0, 0);
10792    }
10793
10794    return buffered;
10795  };
10796
10797  /**
10798   * Get the percent (as a decimal) of the video that's been downloaded.
10799   * This method is not a part of the native HTML video API.
10800   *
10801   * @return {number}
10802   *         A decimal between 0 and 1 representing the percent
10803   *         that is bufferred 0 being 0% and 1 being 100%
10804   */
10805
10806
10807  Player.prototype.bufferedPercent = function bufferedPercent() {
10808    return (0, _buffer.bufferedPercent)(this.buffered(), this.duration());
10809  };
10810
10811  /**
10812   * Get the ending time of the last buffered time range
10813   * This is used in the progress bar to encapsulate all time ranges.
10814   *
10815   * @return {number}
10816   *         The end of the last buffered time range
10817   */
10818
10819
10820  Player.prototype.bufferedEnd = function bufferedEnd() {
10821    var buffered = this.buffered();
10822    var duration = this.duration();
10823    var end = buffered.end(buffered.length - 1);
10824
10825    if (end > duration) {
10826      end = duration;
10827    }
10828
10829    return end;
10830  };
10831
10832  /**
10833   * Get or set the current volume of the media
10834   *
10835   * @param  {number} [percentAsDecimal]
10836   *         The new volume as a decimal percent:
10837   *         - 0 is muted/0%/off
10838   *         - 1.0 is 100%/full
10839   *         - 0.5 is half volume or 50%
10840   *
10841   * @return {Player|number}
10842   *         a reference to the calling player when setting and the
10843   *         current volume as a percent when getting
10844   */
10845
10846
10847  Player.prototype.volume = function volume(percentAsDecimal) {
10848    var vol = void 0;
10849
10850    if (percentAsDecimal !== undefined) {
10851      // Force value to between 0 and 1
10852      vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal)));
10853      this.cache_.volume = vol;
10854      this.techCall_('setVolume', vol);
10855
10856      return this;
10857    }
10858
10859    // Default to 1 when returning current volume.
10860    vol = parseFloat(this.techGet_('volume'));
10861    return isNaN(vol) ? 1 : vol;
10862  };
10863
10864  /**
10865   * Get the current muted state, or turn mute on or off
10866   *
10867   * @param {boolean} [muted]
10868   *        - true to mute
10869   *        - false to unmute
10870   *
10871   * @return {boolean|Player}
10872   *         - true if mute is on and getting
10873   *         - false if mute is off and getting
10874   *         - A reference to the current player when setting
10875   */
10876
10877
10878  Player.prototype.muted = function muted(_muted) {
10879    if (_muted !== undefined) {
10880      this.techCall_('setMuted', _muted);
10881      return this;
10882    }
10883    return this.techGet_('muted') || false;
10884  };
10885
10886  /**
10887   * Check if current tech can support native fullscreen
10888   * (e.g. with built in controls like iOS, so not our flash swf)
10889   *
10890   * @return {boolean}
10891   *         if native fullscreen is supported
10892   */
10893
10894
10895  Player.prototype.supportsFullScreen = function supportsFullScreen() {
10896    return this.techGet_('supportsFullScreen') || false;
10897  };
10898
10899  /**
10900   * Check if the player is in fullscreen mode or tell the player that it
10901   * is or is not in fullscreen mode.
10902   *
10903   * > NOTE: As of the latest HTML5 spec, isFullscreen is no longer an official
10904   * property and instead document.fullscreenElement is used. But isFullscreen is
10905   * still a valuable property for internal player workings.
10906   *
10907   * @param  {boolean} [isFS]
10908   *         Set the players current fullscreen state
10909   *
10910   * @return {boolean|Player}
10911   *         - true if fullscreen is on and getting
10912   *         - false if fullscreen is off and getting
10913   *         - A reference to the current player when setting
10914   */
10915
10916
10917  Player.prototype.isFullscreen = function isFullscreen(isFS) {
10918    if (isFS !== undefined) {
10919      this.isFullscreen_ = !!isFS;
10920      return this;
10921    }
10922    return !!this.isFullscreen_;
10923  };
10924
10925  /**
10926   * Increase the size of the video to full screen
10927   * In some browsers, full screen is not supported natively, so it enters
10928   * "full window mode", where the video fills the browser window.
10929   * In browsers and devices that support native full screen, sometimes the
10930   * browser's default controls will be shown, and not the Video.js custom skin.
10931   * This includes most mobile devices (iOS, Android) and older versions of
10932   * Safari.
10933   *
10934   * @fires Player#fullscreenchange
10935   * @return {Player}
10936   *         A reference to the current player
10937   */
10938
10939
10940  Player.prototype.requestFullscreen = function requestFullscreen() {
10941    var fsApi = _fullscreenApi2['default'];
10942
10943    this.isFullscreen(true);
10944
10945    if (fsApi.requestFullscreen) {
10946      // the browser supports going fullscreen at the element level so we can
10947      // take the controls fullscreen as well as the video
10948
10949      // Trigger fullscreenchange event after change
10950      // We have to specifically add this each time, and remove
10951      // when canceling fullscreen. Otherwise if there's multiple
10952      // players on a page, they would all be reacting to the same fullscreen
10953      // events
10954      Events.on(_document2['default'], fsApi.fullscreenchange, Fn.bind(this, function documentFullscreenChange(e) {
10955        this.isFullscreen(_document2['default'][fsApi.fullscreenElement]);
10956
10957        // If cancelling fullscreen, remove event listener.
10958        if (this.isFullscreen() === false) {
10959          Events.off(_document2['default'], fsApi.fullscreenchange, documentFullscreenChange);
10960        }
10961        /**
10962         * @event Player#fullscreenchange
10963         * @type {EventTarget~Event}
10964         */
10965        this.trigger('fullscreenchange');
10966      }));
10967
10968      this.el_[fsApi.requestFullscreen]();
10969    } else if (this.tech_.supportsFullScreen()) {
10970      // we can't take the video.js controls fullscreen but we can go fullscreen
10971      // with native controls
10972      this.techCall_('enterFullScreen');
10973    } else {
10974      // fullscreen isn't supported so we'll just stretch the video element to
10975      // fill the viewport
10976      this.enterFullWindow();
10977      /**
10978       * @event Player#fullscreenchange
10979       * @type {EventTarget~Event}
10980       */
10981      this.trigger('fullscreenchange');
10982    }
10983
10984    return this;
10985  };
10986
10987  /**
10988   * Return the video to its normal size after having been in full screen mode
10989   *
10990   * @fires Player#fullscreenchange
10991   *
10992   * @return {Player}
10993   *         A reference to the current player
10994   */
10995
10996
10997  Player.prototype.exitFullscreen = function exitFullscreen() {
10998    var fsApi = _fullscreenApi2['default'];
10999
11000    this.isFullscreen(false);
11001
11002    // Check for browser element fullscreen support
11003    if (fsApi.requestFullscreen) {
11004      _document2['default'][fsApi.exitFullscreen]();
11005    } else if (this.tech_.supportsFullScreen()) {
11006      this.techCall_('exitFullScreen');
11007    } else {
11008      this.exitFullWindow();
11009      /**
11010       * @event Player#fullscreenchange
11011       * @type {EventTarget~Event}
11012       */
11013      this.trigger('fullscreenchange');
11014    }
11015
11016    return this;
11017  };
11018
11019  /**
11020   * When fullscreen isn't supported we can stretch the
11021   * video container to as wide as the browser will let us.
11022   *
11023   * @fires Player#enterFullWindow
11024   */
11025
11026
11027  Player.prototype.enterFullWindow = function enterFullWindow() {
11028    this.isFullWindow = true;
11029
11030    // Storing original doc overflow value to return to when fullscreen is off
11031    this.docOrigOverflow = _document2['default'].documentElement.style.overflow;
11032
11033    // Add listener for esc key to exit fullscreen
11034    Events.on(_document2['default'], 'keydown', Fn.bind(this, this.fullWindowOnEscKey));
11035
11036    // Hide any scroll bars
11037    _document2['default'].documentElement.style.overflow = 'hidden';
11038
11039    // Apply fullscreen styles
11040    Dom.addElClass(_document2['default'].body, 'vjs-full-window');
11041
11042    /**
11043     * @event Player#enterFullWindow
11044     * @type {EventTarget~Event}
11045     */
11046    this.trigger('enterFullWindow');
11047  };
11048
11049  /**
11050   * Check for call to either exit full window or
11051   * full screen on ESC key
11052   *
11053   * @param {string} event
11054   *        Event to check for key press
11055   */
11056
11057
11058  Player.prototype.fullWindowOnEscKey = function fullWindowOnEscKey(event) {
11059    if (event.keyCode === 27) {
11060      if (this.isFullscreen() === true) {
11061        this.exitFullscreen();
11062      } else {
11063        this.exitFullWindow();
11064      }
11065    }
11066  };
11067
11068  /**
11069   * Exit full window
11070   *
11071   * @fires Player#exitFullWindow
11072   */
11073
11074
11075  Player.prototype.exitFullWindow = function exitFullWindow() {
11076    this.isFullWindow = false;
11077    Events.off(_document2['default'], 'keydown', this.fullWindowOnEscKey);
11078
11079    // Unhide scroll bars.
11080    _document2['default'].documentElement.style.overflow = this.docOrigOverflow;
11081
11082    // Remove fullscreen styles
11083    Dom.removeElClass(_document2['default'].body, 'vjs-full-window');
11084
11085    // Resize the box, controller, and poster to original sizes
11086    // this.positionAll();
11087    /**
11088     * @event Player#exitFullWindow
11089     * @type {EventTarget~Event}
11090     */
11091    this.trigger('exitFullWindow');
11092  };
11093
11094  /**
11095   * Check whether the player can play a given mimetype
11096   *
11097   * @see https://www.w3.org/TR/2011/WD-html5-20110113/video.html#dom-navigator-canplaytype
11098   *
11099   * @param {string} type
11100   *        The mimetype to check
11101   *
11102   * @return {string}
11103   *         'probably', 'maybe', or '' (empty string)
11104   */
11105
11106
11107  Player.prototype.canPlayType = function canPlayType(type) {
11108    var can = void 0;
11109
11110    // Loop through each playback technology in the options order
11111    for (var i = 0, j = this.options_.techOrder; i < j.length; i++) {
11112      var techName = (0, _toTitleCase2['default'])(j[i]);
11113      var tech = _tech2['default'].getTech(techName);
11114
11115      // Support old behavior of techs being registered as components.
11116      // Remove once that deprecated behavior is removed.
11117      if (!tech) {
11118        tech = _component2['default'].getComponent(techName);
11119      }
11120
11121      // Check if the current tech is defined before continuing
11122      if (!tech) {
11123        _log2['default'].error('The "' + techName + '" tech is undefined. Skipped browser support check for that tech.');
11124        continue;
11125      }
11126
11127      // Check if the browser supports this technology
11128      if (tech.isSupported()) {
11129        can = tech.canPlayType(type);
11130
11131        if (can) {
11132          return can;
11133        }
11134      }
11135    }
11136
11137    return '';
11138  };
11139
11140  /**
11141   * Select source based on tech-order or source-order
11142   * Uses source-order selection if `options.sourceOrder` is truthy. Otherwise,
11143   * defaults to tech-order selection
11144   *
11145   * @param {Array} sources
11146   *        The sources for a media asset
11147   *
11148   * @return {Object|boolean}
11149   *         Object of source and tech order or false
11150   */
11151
11152
11153  Player.prototype.selectSource = function selectSource(sources) {
11154    var _this4 = this;
11155
11156    // Get only the techs specified in `techOrder` that exist and are supported by the
11157    // current platform
11158    var techs = this.options_.techOrder.map(_toTitleCase2['default']).map(function (techName) {
11159      // `Component.getComponent(...)` is for support of old behavior of techs
11160      // being registered as components.
11161      // Remove once that deprecated behavior is removed.
11162      return [techName, _tech2['default'].getTech(techName) || _component2['default'].getComponent(techName)];
11163    }).filter(function (_ref) {
11164      var techName = _ref[0],
11165          tech = _ref[1];
11166
11167      // Check if the current tech is defined before continuing
11168      if (tech) {
11169        // Check if the browser supports this technology
11170        return tech.isSupported();
11171      }
11172
11173      _log2['default'].error('The "' + techName + '" tech is undefined. Skipped browser support check for that tech.');
11174      return false;
11175    });
11176
11177    // Iterate over each `innerArray` element once per `outerArray` element and execute
11178    // `tester` with both. If `tester` returns a non-falsy value, exit early and return
11179    // that value.
11180    var findFirstPassingTechSourcePair = function findFirstPassingTechSourcePair(outerArray, innerArray, tester) {
11181      var found = void 0;
11182
11183      outerArray.some(function (outerChoice) {
11184        return innerArray.some(function (innerChoice) {
11185          found = tester(outerChoice, innerChoice);
11186
11187          if (found) {
11188            return true;
11189          }
11190        });
11191      });
11192
11193      return found;
11194    };
11195
11196    var foundSourceAndTech = void 0;
11197    var flip = function flip(fn) {
11198      return function (a, b) {
11199        return fn(b, a);
11200      };
11201    };
11202    var finder = function finder(_ref2, source) {
11203      var techName = _ref2[0],
11204          tech = _ref2[1];
11205
11206      if (tech.canPlaySource(source, _this4.options_[techName.toLowerCase()])) {
11207        return { source: source, tech: techName };
11208      }
11209    };
11210
11211    // Depending on the truthiness of `options.sourceOrder`, we swap the order of techs and sources
11212    // to select from them based on their priority.
11213    if (this.options_.sourceOrder) {
11214      // Source-first ordering
11215      foundSourceAndTech = findFirstPassingTechSourcePair(sources, techs, flip(finder));
11216    } else {
11217      // Tech-first ordering
11218      foundSourceAndTech = findFirstPassingTechSourcePair(techs, sources, finder);
11219    }
11220
11221    return foundSourceAndTech || false;
11222  };
11223
11224  /**
11225   * The source function updates the video source
11226   * There are three types of variables you can pass as the argument.
11227   * **URL string**: A URL to the the video file. Use this method if you are sure
11228   * the current playback technology (HTML5/Flash) can support the source you
11229   * provide. Currently only MP4 files can be used in both HTML5 and Flash.
11230   *
11231   * @param {Tech~SourceObject|Tech~SourceObject[]} [source]
11232   *        One SourceObject or an array of SourceObjects
11233   *
11234   * @return {string|Player}
11235   *         - The current video source when getting
11236   *         - The player when setting
11237   */
11238
11239
11240  Player.prototype.src = function src(source) {
11241    if (source === undefined) {
11242      return this.techGet_('src');
11243    }
11244
11245    var currentTech = _tech2['default'].getTech(this.techName_);
11246
11247    // Support old behavior of techs being registered as components.
11248    // Remove once that deprecated behavior is removed.
11249    if (!currentTech) {
11250      currentTech = _component2['default'].getComponent(this.techName_);
11251    }
11252
11253    // case: Array of source objects to choose from and pick the best to play
11254    if (Array.isArray(source)) {
11255      this.sourceList_(source);
11256
11257      // case: URL String (http://myvideo...)
11258    } else if (typeof source === 'string') {
11259      // create a source object from the string
11260      this.src({ src: source });
11261
11262      // case: Source object { src: '', type: '' ... }
11263    } else if (source instanceof Object) {
11264      // check if the source has a type and the loaded tech cannot play the source
11265      // if there's no type we'll just try the current tech
11266      if (source.type && !currentTech.canPlaySource(source, this.options_[this.techName_.toLowerCase()])) {
11267        // create a source list with the current source and send through
11268        // the tech loop to check for a compatible technology
11269        this.sourceList_([source]);
11270      } else {
11271        this.cache_.sources = null;
11272        this.cache_.source = source;
11273        this.cache_.src = source.src;
11274
11275        this.currentType_ = source.type || '';
11276
11277        // wait until the tech is ready to set the source
11278        this.ready(function () {
11279
11280          // The setSource tech method was added with source handlers
11281          // so older techs won't support it
11282          // We need to check the direct prototype for the case where subclasses
11283          // of the tech do not support source handlers
11284          if (currentTech.prototype.hasOwnProperty('setSource')) {
11285            this.techCall_('setSource', source);
11286          } else {
11287            this.techCall_('src', source.src);
11288          }
11289
11290          if (this.options_.preload === 'auto') {
11291            this.load();
11292          }
11293
11294          if (this.options_.autoplay) {
11295            this.play();
11296          }
11297
11298          // Set the source synchronously if possible (#2326)
11299        }, true);
11300      }
11301    }
11302
11303    return this;
11304  };
11305
11306  /**
11307   * Handle an array of source objects
11308   *
11309   * @param  {Tech~SourceObject[]} sources
11310   *         Array of source objects
11311   *
11312   * @private
11313   */
11314
11315
11316  Player.prototype.sourceList_ = function sourceList_(sources) {
11317    var sourceTech = this.selectSource(sources);
11318
11319    if (sourceTech) {
11320      if (sourceTech.tech === this.techName_) {
11321        // if this technology is already loaded, set the source
11322        this.src(sourceTech.source);
11323      } else {
11324        // load this technology with the chosen source
11325        this.loadTech_(sourceTech.tech, sourceTech.source);
11326      }
11327
11328      this.cache_.sources = sources;
11329    } else {
11330      // We need to wrap this in a timeout to give folks a chance to add error event handlers
11331      this.setTimeout(function () {
11332        this.error({ code: 4, message: this.localize(this.options_.notSupportedMessage) });
11333      }, 0);
11334
11335      // we could not find an appropriate tech, but let's still notify the delegate that this is it
11336      // this needs a better comment about why this is needed
11337      this.triggerReady();
11338    }
11339  };
11340
11341  /**
11342   * Begin loading the src data.
11343   *
11344   * @return {Player}
11345   *         A reference to the player
11346   */
11347
11348
11349  Player.prototype.load = function load() {
11350    this.techCall_('load');
11351    return this;
11352  };
11353
11354  /**
11355   * Reset the player. Loads the first tech in the techOrder,
11356   * and calls `reset` on the tech`.
11357   *
11358   * @return {Player}
11359   *         A reference to the player
11360   */
11361
11362
11363  Player.prototype.reset = function reset() {
11364    this.loadTech_((0, _toTitleCase2['default'])(this.options_.techOrder[0]), null);
11365    this.techCall_('reset');
11366    return this;
11367  };
11368
11369  /**
11370   * Returns all of the current source objects.
11371   *
11372   * @return {Tech~SourceObject[]}
11373   *         The current source objects
11374   */
11375
11376
11377  Player.prototype.currentSources = function currentSources() {
11378    var source = this.currentSource();
11379    var sources = [];
11380
11381    // assume `{}` or `{ src }`
11382    if (Object.keys(source).length !== 0) {
11383      sources.push(source);
11384    }
11385
11386    return this.cache_.sources || sources;
11387  };
11388
11389  /**
11390   * Returns the current source object.
11391   *
11392   * @return {Tech~SourceObject}
11393   *         The current source object
11394   */
11395
11396
11397  Player.prototype.currentSource = function currentSource() {
11398    var source = {};
11399    var src = this.currentSrc();
11400
11401    if (src) {
11402      source.src = src;
11403    }
11404
11405    return this.cache_.source || source;
11406  };
11407
11408  /**
11409   * Returns the fully qualified URL of the current source value e.g. http://mysite.com/video.mp4
11410   * Can be used in conjuction with `currentType` to assist in rebuilding the current source object.
11411   *
11412   * @return {string}
11413   *         The current source
11414   */
11415
11416
11417  Player.prototype.currentSrc = function currentSrc() {
11418    return this.techGet_('currentSrc') || this.cache_.src || '';
11419  };
11420
11421  /**
11422   * Get the current source type e.g. video/mp4
11423   * This can allow you rebuild the current source object so that you could load the same
11424   * source and tech later
11425   *
11426   * @return {string}
11427   *         The source MIME type
11428   */
11429
11430
11431  Player.prototype.currentType = function currentType() {
11432    return this.currentType_ || '';
11433  };
11434
11435  /**
11436   * Get or set the preload attribute
11437   *
11438   * @param {boolean} [value]
11439   *        - true means that we should preload
11440   *        - false maens that we should not preload
11441   *
11442   * @return {string|Player}
11443   *         - the preload attribute value when getting
11444   *         - the player when setting
11445   */
11446
11447
11448  Player.prototype.preload = function preload(value) {
11449    if (value !== undefined) {
11450      this.techCall_('setPreload', value);
11451      this.options_.preload = value;
11452      return this;
11453    }
11454    return this.techGet_('preload');
11455  };
11456
11457  /**
11458   * Get or set the autoplay attribute.
11459   *
11460   * @param {boolean} [value]
11461   *        - true means that we should autoplay
11462   *        - false maens that we should not autoplay
11463   *
11464   * @return {string|Player}
11465   *         - the current value of autoplay
11466   *         - the player when setting
11467   */
11468
11469
11470  Player.prototype.autoplay = function autoplay(value) {
11471    if (value !== undefined) {
11472      this.techCall_('setAutoplay', value);
11473      this.options_.autoplay = value;
11474      return this;
11475    }
11476    return this.techGet_('autoplay', value);
11477  };
11478
11479  /**
11480   * Set or unset the playsinline attribute.
11481   * Playsinline tells the browser that non-fullscreen playback is preferred.
11482   *
11483   * @param {boolean} [value]
11484   *        - true means that we should try to play inline by default
11485   *        - false means that we should use the browser's default playback mode,
11486   *          which in most cases is inline. iOS Safari is a notable exception
11487   *          and plays fullscreen by default.
11488   *
11489   * @return {string|Player}
11490   *         - the current value of playsinline
11491   *         - the player when setting
11492   *
11493   * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}
11494   */
11495
11496
11497  Player.prototype.playsinline = function playsinline(value) {
11498    if (value !== undefined) {
11499      this.techCall_('setPlaysinline', value);
11500      this.options_.playsinline = value;
11501      return this;
11502    }
11503    return this.techGet_('playsinline');
11504  };
11505
11506  /**
11507   * Get or set the loop attribute on the video element.
11508   *
11509   * @param {boolean} [value]
11510   *        - true means that we should loop the video
11511   *        - false means that we should not loop the video
11512   *
11513   * @return {string|Player}
11514   *         - the current value of loop when getting
11515   *         - the player when setting
11516   */
11517
11518
11519  Player.prototype.loop = function loop(value) {
11520    if (value !== undefined) {
11521      this.techCall_('setLoop', value);
11522      this.options_.loop = value;
11523      return this;
11524    }
11525    return this.techGet_('loop');
11526  };
11527
11528  /**
11529   * Get or set the poster image source url
11530   *
11531   * @fires Player#posterchange
11532   *
11533   * @param {string} [src]
11534   *        Poster image source URL
11535   *
11536   * @return {string|Player}
11537   *         - the current value of poster when getting
11538   *         - the player when setting
11539   */
11540
11541
11542  Player.prototype.poster = function poster(src) {
11543    if (src === undefined) {
11544      return this.poster_;
11545    }
11546
11547    // The correct way to remove a poster is to set as an empty string
11548    // other falsey values will throw errors
11549    if (!src) {
11550      src = '';
11551    }
11552
11553    // update the internal poster variable
11554    this.poster_ = src;
11555
11556    // update the tech's poster
11557    this.techCall_('setPoster', src);
11558
11559    // alert components that the poster has been set
11560    /**
11561     * This event fires when the poster image is changed on the player.
11562     *
11563     * @event Player#posterchange
11564     * @type {EventTarget~Event}
11565     */
11566    this.trigger('posterchange');
11567
11568    return this;
11569  };
11570
11571  /**
11572   * Some techs (e.g. YouTube) can provide a poster source in an
11573   * asynchronous way. We want the poster component to use this
11574   * poster source so that it covers up the tech's controls.
11575   * (YouTube's play button). However we only want to use this
11576   * soruce if the player user hasn't set a poster through
11577   * the normal APIs.
11578   *
11579   * @fires Player#posterchange
11580   * @listens Tech#posterchange
11581   * @private
11582   */
11583
11584
11585  Player.prototype.handleTechPosterChange_ = function handleTechPosterChange_() {
11586    if (!this.poster_ && this.tech_ && this.tech_.poster) {
11587      this.poster_ = this.tech_.poster() || '';
11588
11589      // Let components know the poster has changed
11590      this.trigger('posterchange');
11591    }
11592  };
11593
11594  /**
11595   * Get or set whether or not the controls are showing.
11596   *
11597   * @fires Player#controlsenabled
11598   *
11599   * @param {boolean} [bool]
11600   *        - true to turn controls on
11601   *        - false to turn controls off
11602   *
11603   * @return {boolean|Player}
11604   *         - the current value of controls when getting
11605   *         - the player when setting
11606   */
11607
11608
11609  Player.prototype.controls = function controls(bool) {
11610    if (bool !== undefined) {
11611      bool = !!bool;
11612
11613      // Don't trigger a change event unless it actually changed
11614      if (this.controls_ !== bool) {
11615        this.controls_ = bool;
11616
11617        if (this.usingNativeControls()) {
11618          this.techCall_('setControls', bool);
11619        }
11620
11621        if (bool) {
11622          this.removeClass('vjs-controls-disabled');
11623          this.addClass('vjs-controls-enabled');
11624          /**
11625           * @event Player#controlsenabled
11626           * @type {EventTarget~Event}
11627           */
11628          this.trigger('controlsenabled');
11629
11630          if (!this.usingNativeControls()) {
11631            this.addTechControlsListeners_();
11632          }
11633        } else {
11634          this.removeClass('vjs-controls-enabled');
11635          this.addClass('vjs-controls-disabled');
11636          /**
11637           * @event Player#controlsdisabled
11638           * @type {EventTarget~Event}
11639           */
11640          this.trigger('controlsdisabled');
11641
11642          if (!this.usingNativeControls()) {
11643            this.removeTechControlsListeners_();
11644          }
11645        }
11646      }
11647      return this;
11648    }
11649    return !!this.controls_;
11650  };
11651
11652  /**
11653   * Toggle native controls on/off. Native controls are the controls built into
11654   * devices (e.g. default iPhone controls), Flash, or other techs
11655   * (e.g. Vimeo Controls)
11656   * **This should only be set by the current tech, because only the tech knows
11657   * if it can support native controls**
11658   *
11659   * @fires Player#usingnativecontrols
11660   * @fires Player#usingcustomcontrols
11661   *
11662   * @param {boolean} [bool]
11663   *        - true to turn native controls on
11664   *        - false to turn native controls off
11665   *
11666   * @return {boolean|Player}
11667   *         - the current value of native controls when getting
11668   *         - the player when setting
11669   */
11670
11671
11672  Player.prototype.usingNativeControls = function usingNativeControls(bool) {
11673    if (bool !== undefined) {
11674      bool = !!bool;
11675
11676      // Don't trigger a change event unless it actually changed
11677      if (this.usingNativeControls_ !== bool) {
11678        this.usingNativeControls_ = bool;
11679        if (bool) {
11680          this.addClass('vjs-using-native-controls');
11681
11682          /**
11683           * player is using the native device controls
11684           *
11685           * @event Player#usingnativecontrols
11686           * @type {EventTarget~Event}
11687           */
11688          this.trigger('usingnativecontrols');
11689        } else {
11690          this.removeClass('vjs-using-native-controls');
11691
11692          /**
11693           * player is using the custom HTML controls
11694           *
11695           * @event Player#usingcustomcontrols
11696           * @type {EventTarget~Event}
11697           */
11698          this.trigger('usingcustomcontrols');
11699        }
11700      }
11701      return this;
11702    }
11703    return !!this.usingNativeControls_;
11704  };
11705
11706  /**
11707   * Set or get the current MediaError
11708   *
11709   * @fires Player#error
11710   *
11711   * @param  {MediaError|string|number} [err]
11712   *         A MediaError or a string/number to be turned
11713   *         into a MediaError
11714   *
11715   * @return {MediaError|null|Player}
11716   *         - The current MediaError when getting (or null)
11717   *         - The player when setting
11718   */
11719
11720
11721  Player.prototype.error = function error(err) {
11722    if (err === undefined) {
11723      return this.error_ || null;
11724    }
11725
11726    // restoring to default
11727    if (err === null) {
11728      this.error_ = err;
11729      this.removeClass('vjs-error');
11730      if (this.errorDisplay) {
11731        this.errorDisplay.close();
11732      }
11733      return this;
11734    }
11735
11736    this.error_ = new _mediaError2['default'](err);
11737
11738    // add the vjs-error classname to the player
11739    this.addClass('vjs-error');
11740
11741    // log the name of the error type and any message
11742    // ie8 just logs "[object object]" if you just log the error object
11743    _log2['default'].error('(CODE:' + this.error_.code + ' ' + _mediaError2['default'].errorTypes[this.error_.code] + ')', this.error_.message, this.error_);
11744
11745    /**
11746     * @event Player#error
11747     * @type {EventTarget~Event}
11748     */
11749    this.trigger('error');
11750
11751    return this;
11752  };
11753
11754  /**
11755   * Report user activity
11756   *
11757   * @param {Object} event
11758   *        Event object
11759   */
11760
11761
11762  Player.prototype.reportUserActivity = function reportUserActivity(event) {
11763    this.userActivity_ = true;
11764  };
11765
11766  /**
11767   * Get/set if user is active
11768   *
11769   * @fires Player#useractive
11770   * @fires Player#userinactive
11771   *
11772   * @param {boolean} [bool]
11773   *        - true if the user is active
11774   *        - false if the user is inactive
11775   * @return {boolean|Player}
11776   *         - the current value of userActive when getting
11777   *         - the player when setting
11778   */
11779
11780
11781  Player.prototype.userActive = function userActive(bool) {
11782    if (bool !== undefined) {
11783      bool = !!bool;
11784      if (bool !== this.userActive_) {
11785        this.userActive_ = bool;
11786        if (bool) {
11787          // If the user was inactive and is now active we want to reset the
11788          // inactivity timer
11789          this.userActivity_ = true;
11790          this.removeClass('vjs-user-inactive');
11791          this.addClass('vjs-user-active');
11792          /**
11793           * @event Player#useractive
11794           * @type {EventTarget~Event}
11795           */
11796          this.trigger('useractive');
11797        } else {
11798          // We're switching the state to inactive manually, so erase any other
11799          // activity
11800          this.userActivity_ = false;
vendor: 3,493 bytes, lines 11801-11893
11801
11802          // Chrome/Safari/IE have bugs where when you change the cursor it can
11803          // trigger a mousemove event. This causes an issue when you're hiding
11804          // the cursor when the user is inactive, and a mousemove signals user
11805          // activity. Making it impossible to go into inactive mode. Specifically
11806          // this happens in fullscreen when we really need to hide the cursor.
11807          //
11808          // When this gets resolved in ALL browsers it can be removed
11809          // https://code.google.com/p/chromium/issues/detail?id=103041
11810          if (this.tech_) {
11811            this.tech_.one('mousemove', function (e) {
11812              e.stopPropagation();
11813              e.preventDefault();
11814            });
11815          }
11816
11817          this.removeClass('vjs-user-active');
11818          this.addClass('vjs-user-inactive');
11819          /**
11820           * @event Player#userinactive
11821           * @type {EventTarget~Event}
11822           */
11823          this.trigger('userinactive');
11824        }
11825      }
11826      return this;
11827    }
11828    return this.userActive_;
11829  };
11830
11831  /**
11832   * Listen for user activity based on timeout value
11833   *
11834   * @private
11835   */
11836
11837
11838  Player.prototype.listenForUserActivity_ = function listenForUserActivity_() {
11839    var mouseInProgress = void 0;
11840    var lastMoveX = void 0;
11841    var lastMoveY = void 0;
11842    var handleActivity = Fn.bind(this, this.reportUserActivity);
11843
11844    var handleMouseMove = function handleMouseMove(e) {
11845      // #1068 - Prevent mousemove spamming
11846      // Chrome Bug: https://code.google.com/p/chromium/issues/detail?id=366970
11847      if (e.screenX !== lastMoveX || e.screenY !== lastMoveY) {
11848        lastMoveX = e.screenX;
11849        lastMoveY = e.screenY;
11850        handleActivity();
11851      }
11852    };
11853
11854    var handleMouseDown = function handleMouseDown() {
11855      handleActivity();
11856      // For as long as the they are touching the device or have their mouse down,
11857      // we consider them active even if they're not moving their finger or mouse.
11858      // So we want to continue to update that they are active
11859      this.clearInterval(mouseInProgress);
11860      // Setting userActivity=true now and setting the interval to the same time
11861      // as the activityCheck interval (250) should ensure we never miss the
11862      // next activityCheck
11863      mouseInProgress = this.setInterval(handleActivity, 250);
11864    };
11865
11866    var handleMouseUp = function handleMouseUp(event) {
11867      handleActivity();
11868      // Stop the interval that maintains activity if the mouse/touch is down
11869      this.clearInterval(mouseInProgress);
11870    };
11871
11872    // Any mouse movement will be considered user activity
11873    this.on('mousedown', handleMouseDown);
11874    this.on('mousemove', handleMouseMove);
11875    this.on('mouseup', handleMouseUp);
11876
11877    // Listen for keyboard navigation
11878    // Shouldn't need to use inProgress interval because of key repeat
11879    this.on('keydown', handleActivity);
11880    this.on('keyup', handleActivity);
11881
11882    // Run an interval every 250 milliseconds instead of stuffing everything into
11883    // the mousemove/touchmove function itself, to prevent performance degradation.
11884    // `this.reportUserActivity` simply sets this.userActivity_ to true, which
11885    // then gets picked up by this loop
11886    // http://ejohn.org/blog/learning-from-twitter/
11887    var inactivityTimeout = void 0;
11888
11889    this.setInterval(function () {
11890      // Check to see if mouse/touch activity has happened
11891      if (this.userActivity_) {
11892        // Reset the activity tracker
11893        this.userActivity_ = false;
11894
11895        // If the user state was inactive, set the state to active
11896        this.userActive(true);
11897
11898        // Clear any existing inactivity timeout to start the timer over
11899        this.clearTimeout(inactivityTimeout);
11900
11901        var timeout = this.options_.inactivityTimeout;
11902
11903        if (timeout > 0) {
11904          // In <timeout> milliseconds, if no more activity has occurred the
11905          // user will be considered inactive
11906          inactivityTimeout = this.setTimeout(function () {
11907            // Protect against the case where the inactivityTimeout can trigger just
11908            // before the next user activity is picked up by the activity check loop
11909            // causing a flicker
11910            if (!this.userActivity_) {
11911              this.userActive(false);
11912            }
11913          }, timeout);
11914        }
11915      }
11916    }, 250);
11917  };
11918
11919  /**
11920   * Gets or sets the current playback rate. A playback rate of
11921   * 1.0 represents normal speed and 0.5 would indicate half-speed
11922   * playback, for instance.
11923   *
11924   * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-playbackrate
11925   *
11926   * @param {number} [rate]
11927   *       New playback rate to set.
11928   *
11929   * @return {number|Player}
11930   *         - The current playback rate when getting or 1.0
11931   *         - the player when setting
11932   */
11933
11934
11935  Player.prototype.playbackRate = function playbackRate(rate) {
11936    if (rate !== undefined) {
11937      this.techCall_('setPlaybackRate', rate);
11938      return this;
11939    }
11940
11941    if (this.tech_ && this.tech_.featuresPlaybackRate) {
11942      return this.techGet_('playbackRate');
11943    }
11944    return 1.0;
11945  };
11946
11947  /**
11948   * Gets or sets the audio flag
11949   *
11950   * @param {boolean} bool
11951   *        - true signals that this is an audio player
11952   *        - false signals that this is not an audio player
11953   *
11954   * @return {Player|boolean}
11955   *         - the current value of isAudio when getting
11956   *         - the player if setting
11957   */
11958
11959
11960  Player.prototype.isAudio = function isAudio(bool) {
11961    if (bool !== undefined) {
11962      this.isAudio_ = !!bool;
11963      return this;
11964    }
11965
11966    return !!this.isAudio_;
11967  };
11968
11969  /**
11970   * Get the {@link VideoTrackList}
11971   *
11972   * @see https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist
11973   *
11974   * @return {VideoTrackList}
11975   *         the current video track list
11976   */
11977
11978
11979  Player.prototype.videoTracks = function videoTracks() {
11980    // if we have not yet loadTech_, we create videoTracks_
11981    // these will be passed to the tech during loading
11982    if (!this.tech_) {
11983      this.videoTracks_ = this.videoTracks_ || new _videoTrackList2['default']();
11984      return this.videoTracks_;
11985    }
11986
11987    return this.tech_.videoTracks();
11988  };
11989
11990  /**
11991   * Get the {@link AudioTrackList}
11992   *
11993   * @see https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist
11994   *
11995   * @return {AudioTrackList}
11996   *         the current audio track list
11997   */
11998
11999
12000  Player.prototype.audioTracks = function audioTracks() {
12001    // if we have not yet loadTech_, we create videoTracks_
12002    // these will be passed to the tech during loading
12003    if (!this.tech_) {
12004      this.audioTracks_ = this.audioTracks_ || new _audioTrackList2['default']();
12005      return this.audioTracks_;
12006    }
12007
12008    return this.tech_.audioTracks();
12009  };
12010
12011  /**
12012   * Get the {@link TextTrackList}
12013   *
12014   * Text tracks are tracks of timed text events.
12015   * - Captions: text displayed over the video
12016   *             for the hearing impaired
12017   * - Subtitles: text displayed over the video for
12018   *              those who don't understand language in the video
12019   * - Chapters: text displayed in a menu allowing the user to jump
12020   *             to particular points (chapters) in the video
12021   * - Descriptions: (not yet implemented) audio descriptions that are read back to
12022   *                 the user by a screen reading device
12023   *
12024   * @see http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-texttracks
12025   *
12026   * @return {TextTrackList|undefined}
12027   *         The current TextTrackList or undefined if
12028   *         or undefined if we don't have a tech
12029   */
12030
12031
12032  Player.prototype.textTracks = function textTracks() {
12033    // cannot use techGet_ directly because it checks to see whether the tech is ready.
12034    // Flash is unlikely to be ready in time but textTracks should still work.
12035    if (this.tech_) {
12036      return this.tech_.textTracks();
12037    }
12038  };
12039
12040  /**
12041   * Get the "remote" {@link TextTrackList}. Remote Text Tracks
12042   * are tracks that were added to the HTML video element and can
12043   * be removed, whereas normal texttracks cannot be removed.
12044   *
12045   *
12046   * @return {TextTrackList|undefined}
12047   *         The current remote text track list or undefined
12048   *         if we don't have a tech
12049   */
12050
12051
12052  Player.prototype.remoteTextTracks = function remoteTextTracks() {
12053    if (this.tech_) {
12054      return this.tech_.remoteTextTracks();
12055    }
12056  };
12057
12058  /**
12059   * Get the "remote" {@link HTMLTrackElementList}.
12060   * This gives the user all of the DOM elements that match up
12061   * with the remote {@link TextTrackList}.
12062   *
12063   * @return {HTMLTrackElementList}
12064   *         The current remote text track list elements
12065   *         or undefined if we don't have a tech
12066   */
12067
12068
12069  Player.prototype.remoteTextTrackEls = function remoteTextTrackEls() {
12070    if (this.tech_) {
12071      return this.tech_.remoteTextTrackEls();
12072    }
12073  };
12074
12075  /**
12076   * A helper method for adding a {@link TextTrack} to our
12077   * {@link TextTrackList}.
12078   *
12079   * In addition to the W3C settings we allow adding additional info through options.
12080   *
12081   * @see http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-addtexttrack
12082   *
12083   * @param {string} [kind]
12084   *        the kind of TextTrack you are adding
12085   *
12086   * @param {string} [label]
12087   *        the label to give the TextTrack label
12088   *
12089   * @param {string} [language]
12090   *        the language to set on the TextTrack
12091   *
12092   * @return {TextTrack|undefined}
12093   *         the TextTrack that was added or undefined
12094   *         if there is no tech
12095   */
12096
12097
12098  Player.prototype.addTextTrack = function addTextTrack(kind, label, language) {
12099    if (this.tech_) {
12100      return this.tech_.addTextTrack(kind, label, language);
12101    }
12102  };
12103
12104  /**
12105   * Create a remote {@link TextTrack} and an {@link HTMLTrackElement}. It will
12106   * automatically removed from the video element whenever the source changes, unless
12107   * manualCleanup is set to false.
12108   *
12109   * @param {Object} options
12110   *        Options to pass to {@link HTMLTrackElement} during creation. See
12111   *        {@link HTMLTrackElement} for object properties that you should use.
12112   *
12113   * @param {boolean} [manualCleanup=true] if set to false, the TextTrack will be
12114   *
12115   * @return {HTMLTrackElement}
12116   *         the HTMLTrackElement that was created and added
12117   *         to the HTMLTrackElementList and the remote
12118   *         TextTrackList
12119   *
12120   * @deprecated The default value of the "manualCleanup" parameter will default
12121   *             to "false" in upcoming versions of Video.js
12122   */
12123
12124
12125  Player.prototype.addRemoteTextTrack = function addRemoteTextTrack(options, manualCleanup) {
12126    if (this.tech_) {
12127      return this.tech_.addRemoteTextTrack(options, manualCleanup);
12128    }
12129  };
12130
12131  /**
12132   * Remove a remote {@link TextTrack} from the respective
12133   * {@link TextTrackList} and {@link HTMLTrackElementList}.
12134   *
12135   * @param {Object} track
12136   *        Remote {@link TextTrack} to remove
12137   *
12138   * @return {undefined}
12139   *         does not return anything
12140   */
12141
12142
12143  Player.prototype.removeRemoteTextTrack = function removeRemoteTextTrack() {
12144    var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
12145        _ref3$track = _ref3.track,
12146        track = _ref3$track === undefined ? arguments[0] : _ref3$track;
12147
12148    // destructure the input into an object with a track argument, defaulting to arguments[0]
12149    // default the whole argument to an empty object if nothing was passed in
12150
12151    if (this.tech_) {
12152      return this.tech_.removeRemoteTextTrack(track);
12153    }
12154  };
12155
12156  /**
12157   * Gets available media playback quality metrics as specified by the W3C's Media
12158   * Playback Quality API.
12159   *
12160   * @see [Spec]{@link https://wicg.github.io/media-playback-quality}
12161   *
12162   * @return {Object|undefined}
12163   *         An object with supported media playback quality metrics or undefined if there
12164   *         is no tech or the tech does not support it.
12165   */
12166
12167
12168  Player.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() {
12169    return this.techGet_('getVideoPlaybackQuality');
12170  };
12171
12172  /**
12173   * Get video width
12174   *
12175   * @return {number}
12176   *         current video width
12177   */
12178
12179
12180  Player.prototype.videoWidth = function videoWidth() {
12181    return this.tech_ && this.tech_.videoWidth && this.tech_.videoWidth() || 0;
12182  };
12183
12184  /**
12185   * Get video height
12186   *
12187   * @return {number}
12188   *         current video height
12189   */
12190
12191
12192  Player.prototype.videoHeight = function videoHeight() {
12193    return this.tech_ && this.tech_.videoHeight && this.tech_.videoHeight() || 0;
12194  };
12195
12196  // Methods to add support for
12197  // initialTime: function() { return this.techCall_('initialTime'); },
12198  // startOffsetTime: function() { return this.techCall_('startOffsetTime'); },
12199  // played: function() { return this.techCall_('played'); },
12200  // defaultPlaybackRate: function() { return this.techCall_('defaultPlaybackRate'); },
12201  // defaultMuted: function() { return this.techCall_('defaultMuted'); }
12202
12203  /**
12204   * The player's language code
12205   * NOTE: The language should be set in the player options if you want the
12206   * the controls to be built with a specific language. Changing the lanugage
12207   * later will not update controls text.
12208   *
12209   * @param {string} [code]
12210   *        the language code to set the player to
12211   *
12212   * @return {string|Player}
12213   *         - The current language code when getting
12214   *         - A reference to the player when setting
12215   */
12216
12217
12218  Player.prototype.language = function language(code) {
12219    if (code === undefined) {
12220      return this.language_;
12221    }
12222
12223    this.language_ = String(code).toLowerCase();
12224    return this;
12225  };
12226
12227  /**
12228   * Get the player's language dictionary
12229   * Merge every time, because a newly added plugin might call videojs.addLanguage() at any time
12230   * Languages specified directly in the player options have precedence
12231   *
12232   * @return {Array}
12233   *         An array of of supported languages
12234   */
12235
12236
12237  Player.prototype.languages = function languages() {
12238    return (0, _mergeOptions2['default'])(Player.prototype.options_.languages, this.languages_);
12239  };
12240
12241  /**
12242   * returns a JavaScript object reperesenting the current track
12243   * information. **DOES not return it as JSON**
12244   *
12245   * @return {Object}
12246   *         Object representing the current of track info
12247   */
12248
12249
12250  Player.prototype.toJSON = function toJSON() {
12251    var options = (0, _mergeOptions2['default'])(this.options_);
12252    var tracks = options.tracks;
12253
12254    options.tracks = [];
12255
12256    for (var i = 0; i < tracks.length; i++) {
12257      var track = tracks[i];
12258
12259      // deep merge tracks and null out player so no circular references
12260      track = (0, _mergeOptions2['default'])(track);
12261      track.player = undefined;
12262      options.tracks[i] = track;
12263    }
12264
12265    return options;
12266  };
12267
12268  /**
12269   * Creates a simple modal dialog (an instance of the {@link ModalDialog}
12270   * component) that immediately overlays the player with arbitrary
12271   * content and removes itself when closed.
12272   *
12273   * @param {string|Function|Element|Array|null} content
12274   *        Same as {@link ModalDialog#content}'s param of the same name.
12275   *        The most straight-forward usage is to provide a string or DOM
12276   *        element.
12277   *
12278   * @param {Object} [options]
12279   *        Extra options which will be passed on to the {@link ModalDialog}.
12280   *
12281   * @return {ModalDialog}
12282   *         the {@link ModalDialog} that was created
12283   */
12284
12285
12286  Player.prototype.createModal = function createModal(content, options) {
12287    var _this5 = this;
12288
12289    options = options || {};
12290    options.content = content || '';
12291
12292    var modal = new _modalDialog2['default'](this, options);
12293
12294    this.addChild(modal);
12295    modal.on('dispose', function () {
12296      _this5.removeChild(modal);
12297    });
12298
12299    return modal.open();
12300  };
12301
12302  /**
12303   * Gets tag settings
12304   *
12305   * @param {Element} tag
12306   *        The player tag
12307   *
12308   * @return {Object}
12309   *         An object containing all of the settings
12310   *         for a player tag
12311   */
12312
12313
12314  Player.getTagSettings = function getTagSettings(tag) {
12315    var baseOptions = {
12316      sources: [],
12317      tracks: []
12318    };
12319
12320    var tagOptions = Dom.getElAttributes(tag);
12321    var dataSetup = tagOptions['data-setup'];
12322
12323    if (Dom.hasElClass(tag, 'vjs-fluid')) {
12324      tagOptions.fluid = true;
12325    }
12326
12327    // Check if data-setup attr exists.
12328    if (dataSetup !== null) {
12329      // Parse options JSON
12330      // If empty string, make it a parsable json object.
12331      var _safeParseTuple = (0, _tuple2['default'])(dataSetup || '{}'),
12332          err = _safeParseTuple[0],
12333          data = _safeParseTuple[1];
12334
12335      if (err) {
12336        _log2['default'].error(err);
12337      }
12338      (0, _obj.assign)(tagOptions, data);
12339    }
12340
12341    (0, _obj.assign)(baseOptions, tagOptions);
12342
12343    // Get tag children settings
12344    if (tag.hasChildNodes()) {
12345      var children = tag.childNodes;
12346
12347      for (var i = 0, j = children.length; i < j; i++) {
12348        var child = children[i];
12349        // Change case needed: http://ejohn.org/blog/nodename-case-sensitivity/
12350        var childName = child.nodeName.toLowerCase();
12351
12352        if (childName === 'source') {
12353          baseOptions.sources.push(Dom.getElAttributes(child));
12354        } else if (childName === 'track') {
12355          baseOptions.tracks.push(Dom.getElAttributes(child));
12356        }
12357      }
12358    }
12359
12360    return baseOptions;
12361  };
12362
12363  /**
12364   * Determine wether or not flexbox is supported
12365   *
12366   * @return {boolean}
12367   *         - true if flexbox is supported
12368   *         - false if flexbox is not supported
12369   */
12370
12371
12372  Player.prototype.flexNotSupported_ = function flexNotSupported_() {
12373    var elem = _document2['default'].createElement('i');
12374
12375    // Note: We don't actually use flexBasis (or flexOrder), but it's one of the more
12376    // common flex features that we can rely on when checking for flex support.
12377    return !('flexBasis' in elem.style || 'webkitFlexBasis' in elem.style || 'mozFlexBasis' in elem.style || 'msFlexBasis' in elem.style ||
12378    // IE10-specific (2012 flex spec)
12379    'msFlexOrder' in elem.style);
12380  };
12381
12382  return Player;
12383}(_component2['default']);
12384
12385/**
12386 * Global player list
12387 *
12388 * @type {Object}
12389 */
12390
12391
12392Player.players = {};
12393
12394var navigator = _window2['default'].navigator;
12395
12396/*
12397 * Player instance options, surfaced using options
12398 * options = Player.prototype.options_
12399 * Make changes in options, not here.
12400 *
12401 * @type {Object}
12402 * @private
12403 */
12404Player.prototype.options_ = {
12405  // Default order of fallback technology
12406  techOrder: ['html5', 'flash'],
12407  // techOrder: ['flash','html5'],
12408
12409  html5: {},
12410  flash: {},
12411
12412  // defaultVolume: 0.85,
12413  defaultVolume: 0.00,
12414
12415  // default inactivity timeout
12416  inactivityTimeout: 2000,
12417
12418  // default playback rates
12419  playbackRates: [],
12420  // Add playback rate selection by adding rates
12421  // 'playbackRates': [0.5, 1, 1.5, 2],
12422
12423  // Included control sets
12424  children: ['mediaLoader', 'posterImage', 'textTrackDisplay', 'loadingSpinner', 'bigPlayButton', 'controlBar', 'errorDisplay', 'textTrackSettings'],
12425
12426  language: navigator && (navigator.languages && navigator.languages[0] || navigator.userLanguage || navigator.language) || 'en',
12427
12428  // locales and their language translations
12429  languages: {},
12430
12431  // Default message to show when a video cannot be played.
12432  notSupportedMessage: 'No compatible source was found for this media.'
12433};
12434
12435[
12436/**
12437 * Returns whether or not the player is in the "ended" state.
12438 *
12439 * @return {Boolean} True if the player is in the ended state, false if not.
12440 * @method Player#ended
12441 */
12442'ended',
12443/**
12444 * Returns whether or not the player is in the "seeking" state.
12445 *
12446 * @return {Boolean} True if the player is in the seeking state, false if not.
12447 * @method Player#seeking
12448 */
12449'seeking',
12450/**
12451 * Returns the TimeRanges of the media that are currently available
12452 * for seeking to.
12453 *
12454 * @return {TimeRanges} the seekable intervals of the media timeline
12455 * @method Player#seekable
12456 */
12457'seekable',
12458/**
12459 * Returns the current state of network activity for the element, from
12460 * the codes in the list below.
12461 * - NETWORK_EMPTY (numeric value 0)
12462 *   The element has not yet been initialised. All attributes are in
12463 *   their initial states.
12464 * - NETWORK_IDLE (numeric value 1)
12465 *   The element's resource selection algorithm is active and has
12466 *   selected a resource, but it is not actually using the network at
12467 *   this time.
12468 * - NETWORK_LOADING (numeric value 2)
12469 *   The user agent is actively trying to download data.
12470 * - NETWORK_NO_SOURCE (numeric value 3)
12471 *   The element's resource selection algorithm is active, but it has
12472 *   not yet found a resource to use.
12473 *
12474 * @see https://html.spec.whatwg.org/multipage/embedded-content.html#network-states
12475 * @return {number} the current network activity state
12476 * @method Player#networkState
12477 */
12478'networkState',
12479/**
12480 * Returns a value that expresses the current state of the element
12481 * with respect to rendering the current playback position, from the
12482 * codes in the list below.
12483 * - HAVE_NOTHING (numeric value 0)
12484 *   No information regarding the media resource is available.
12485 * - HAVE_METADATA (numeric value 1)
12486 *   Enough of the resource has been obtained that the duration of the
12487 *   resource is available.
12488 * - HAVE_CURRENT_DATA (numeric value 2)
12489 *   Data for the immediate current playback position is available.
12490 * - HAVE_FUTURE_DATA (numeric value 3)
12491 *   Data for the immediate current playback position is available, as
12492 *   well as enough data for the user agent to advance the current
12493 *   playback position in the direction of playback.
12494 * - HAVE_ENOUGH_DATA (numeric value 4)
12495 *   The user agent estimates that enough data is available for
12496 *   playback to proceed uninterrupted.
12497 *
12498 * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-readystate
12499 * @return {number} the current playback rendering state
12500 * @method Player#readyState
12501 */
12502'readyState'].forEach(function (fn) {
12503  Player.prototype[fn] = function () {
12504    return this.techGet_(fn);
12505  };
12506});
12507
12508TECH_EVENTS_RETRIGGER.forEach(function (event) {
12509  Player.prototype['handleTech' + (0, _toTitleCase2['default'])(event) + '_'] = function () {
12510    return this.trigger(event);
12511  };
12512});
12513
12514/**
12515 * Fired when the player has initial duration and dimension information
12516 *
12517 * @event Player#loadedmetadata
12518 * @type {EventTarget~Event}
12519 */
12520
12521/**
12522 * Fired when the player has downloaded data at the current playback position
12523 *
12524 * @event Player#loadeddata
12525 * @type {EventTarget~Event}
12526 */
12527
12528/**
12529 * Fired when the current playback position has changed *
12530 * During playback this is fired every 15-250 milliseconds, depending on the
12531 * playback technology in use.
12532 *
12533 * @event Player#timeupdate
12534 * @type {EventTarget~Event}
12535 */
12536
12537/**
12538 * Fired when the volume changes
12539 *
12540 * @event Player#volumechange
12541 * @type {EventTarget~Event}
12542 */
12543
12544_component2['default'].registerComponent('Player', Player);
12545exports['default'] = Player;
12546
12547},{"1":1,"4":4,"41":41,"44":44,"45":45,"46":46,"5":5,"50":50,"55":55,"59":59,"60":60,"61":61,"62":62,"63":63,"68":68,"69":69,"71":71,"76":76,"78":78,"79":79,"8":8,"81":81,"82":82,"83":83,"85":85,"86":86,"87":87,"88":88,"89":89,"90":90,"91":91,"94":94,"95":95,"97":97}],52:[function(_dereq_,module,exports){
12548'use strict';
12549
12550exports.__esModule = true;
12551
12552var _player = _dereq_(51);
12553
12554var _player2 = _interopRequireDefault(_player);
12555
12556function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
12557
12558/**
12559 * The method for registering a video.js plugin. {@link videojs:videojs.registerPlugin].
12560 *
12561 * @param {string} name
12562 *        The name of the plugin that is being registered
12563 *
12564 * @param {plugins:PluginFn} init
12565 *        The function that gets run when a `Player` initializes.
12566 */
12567var plugin = function plugin(name, init) {
12568  _player2['default'].prototype[name] = init;
12569}; /**
12570    * @file plugins.js
12571    * @module plugins
12572    */
12573exports['default'] = plugin;
12574
12575},{"51":51}],53:[function(_dereq_,module,exports){
12576'use strict';
12577
12578exports.__esModule = true;
12579
12580var _clickableComponent = _dereq_(3);
12581
12582var _clickableComponent2 = _interopRequireDefault(_clickableComponent);
12583
12584var _component = _dereq_(5);
12585
12586var _component2 = _interopRequireDefault(_component);
12587
12588function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
12589
12590function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
12591
12592function _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; }
12593
12594function _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; } /**
12595                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file popup-button.js
12596                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
12597
12598
12599/**
12600 * A button class for use with {@link Popup} controls
12601 *
12602 * @extends ClickableComponent
12603 */
12604var PopupButton = function (_ClickableComponent) {
12605  _inherits(PopupButton, _ClickableComponent);
12606
12607  /**
12608   * Create an instance of this class.
12609   *
12610   * @param {Player} player
12611   *        The `Player` that this class should be attached to.
12612   *
12613   * @param {Object} [options]
12614   *        The key/value store of player options.
12615   */
12616  function PopupButton(player) {
12617    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
12618
12619    _classCallCheck(this, PopupButton);
12620
12621    var _this = _possibleConstructorReturn(this, _ClickableComponent.call(this, player, options));
12622
12623    _this.update();
12624    return _this;
12625  }
12626
12627  /**
12628   * Update the `Popup` that this button is attached to.
12629   */
12630
12631
12632  PopupButton.prototype.update = function update() {
12633    var popup = this.createPopup();
12634
12635    if (this.popup) {
12636      this.removeChild(this.popup);
12637    }
12638
12639    this.popup = popup;
12640    this.addChild(popup);
12641
12642    if (this.items && this.items.length === 0) {
12643      this.hide();
12644    } else if (this.items && this.items.length > 1) {
12645      this.show();
12646    }
12647  };
12648
12649  /**
12650   * Create a `Popup`. - Override with specific functionality for component
12651   *
12652   * @abstract
12653   */
12654
12655
12656  PopupButton.prototype.createPopup = function createPopup() {};
12657
12658  /**
12659   * Create the `PopupButton`s DOM element.
12660   *
12661   * @return {Element}
12662   *         The element that gets created.
12663   */
12664
12665
12666  PopupButton.prototype.createEl = function createEl() {
12667    return _ClickableComponent.prototype.createEl.call(this, 'div', {
12668      className: this.buildCSSClass()
12669    });
12670  };
12671
12672  /**
12673   * Builds the default DOM `className`.
12674   *
12675   * @return {string}
12676   *         The DOM `className` for this object.
12677   */
12678
12679
12680  PopupButton.prototype.buildCSSClass = function buildCSSClass() {
12681    var menuButtonClass = 'vjs-menu-button';
12682
12683    // If the inline option is passed, we want to use different styles altogether.
12684    if (this.options_.inline === true) {
12685      menuButtonClass += '-inline';
12686    } else {
12687      menuButtonClass += '-popup';
12688    }
12689
12690    return 'vjs-menu-button ' + menuButtonClass + ' ' + _ClickableComponent.prototype.buildCSSClass.call(this);
12691  };
12692
12693  return PopupButton;
12694}(_clickableComponent2['default']);
12695
12696_component2['default'].registerComponent('PopupButton', PopupButton);
12697exports['default'] = PopupButton;
12698
12699},{"3":3,"5":5}],54:[function(_dereq_,module,exports){
12700'use strict';
12701
12702exports.__esModule = true;
12703
12704var _component = _dereq_(5);
12705
12706var _component2 = _interopRequireDefault(_component);
12707
12708var _dom = _dereq_(81);
12709
12710var Dom = _interopRequireWildcard(_dom);
12711
12712var _fn = _dereq_(83);
12713
12714var Fn = _interopRequireWildcard(_fn);
12715
12716var _events = _dereq_(82);
12717
12718var Events = _interopRequireWildcard(_events);
12719
12720function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
12721
12722function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
12723
12724function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
12725
12726function _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; }
12727
12728function _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; } /**
12729                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file popup.js
12730                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
12731
12732
12733/**
12734 * The Popup component is used to build pop up controls.
12735 *
12736 * @extends Component
12737 */
12738var Popup = function (_Component) {
12739  _inherits(Popup, _Component);
12740
12741  function Popup() {
12742    _classCallCheck(this, Popup);
12743
12744    return _possibleConstructorReturn(this, _Component.apply(this, arguments));
12745  }
12746
12747  /**
12748   * Add a popup item to the popup
12749   *
12750   * @param {Object|string} component
12751   *        Component or component type to add
12752   *
12753   */
12754  Popup.prototype.addItem = function addItem(component) {
12755    this.addChild(component);
12756    component.on('click', Fn.bind(this, function () {
12757      this.unlockShowing();
12758    }));
12759  };
12760
12761  /**
12762   * Create the `PopupButton`s DOM element.
12763   *
12764   * @return {Element}
12765   *         The element that gets created.
12766   */
12767
12768
12769  Popup.prototype.createEl = function createEl() {
12770    var contentElType = this.options_.contentElType || 'ul';
12771
12772    this.contentEl_ = Dom.createEl(contentElType, {
12773      className: 'vjs-menu-content'
12774    });
12775
12776    var el = _Component.prototype.createEl.call(this, 'div', {
12777      append: this.contentEl_,
12778      className: 'vjs-menu'
12779    });
12780
12781    el.appendChild(this.contentEl_);
12782
12783    // Prevent clicks from bubbling up. Needed for Popup Buttons,
12784    // where a click on the parent is significant
12785    Events.on(el, 'click', function (event) {
12786      event.preventDefault();
12787      event.stopImmediatePropagation();
12788    });
12789
12790    return el;
12791  };
12792
12793  return Popup;
12794}(_component2['default']);
12795
12796_component2['default'].registerComponent('Popup', Popup);
12797exports['default'] = Popup;
12798
12799},{"5":5,"81":81,"82":82,"83":83}],55:[function(_dereq_,module,exports){
12800'use strict';
12801
12802exports.__esModule = true;
12803
12804var _clickableComponent = _dereq_(3);
12805
12806var _clickableComponent2 = _interopRequireDefault(_clickableComponent);
12807
12808var _component = _dereq_(5);
12809
12810var _component2 = _interopRequireDefault(_component);
12811
12812var _fn = _dereq_(83);
12813
12814var Fn = _interopRequireWildcard(_fn);
12815
12816var _dom = _dereq_(81);
12817
12818var Dom = _interopRequireWildcard(_dom);
12819
12820var _browser = _dereq_(78);
12821
12822var browser = _interopRequireWildcard(_browser);
12823
12824function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
12825
12826function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
12827
12828function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
12829
12830function _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; }
12831
12832function _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; } /**
12833                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file poster-image.js
12834                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
12835
12836
12837/**
12838 * A `ClickableComponent` that handles showing the poster image for the player.
12839 *
12840 * @extends ClickableComponent
12841 */
12842var PosterImage = function (_ClickableComponent) {
12843  _inherits(PosterImage, _ClickableComponent);
12844
12845  /**
12846   * Create an instance of this class.
12847   *
12848   * @param {Player} player
12849   *        The `Player` that this class should attach to.
12850   *
12851   * @param {Object} [options]
12852   *        The key/value store of player options.
12853   */
12854  function PosterImage(player, options) {
12855    _classCallCheck(this, PosterImage);
12856
12857    var _this = _possibleConstructorReturn(this, _ClickableComponent.call(this, player, options));
12858
12859    _this.update();
12860    player.on('posterchange', Fn.bind(_this, _this.update));
12861    return _this;
12862  }
12863
12864  /**
12865   * Clean up and dispose of the `PosterImage`.
12866   */
12867
12868
12869  PosterImage.prototype.dispose = function dispose() {
12870    this.player().off('posterchange', this.update);
12871    _ClickableComponent.prototype.dispose.call(this);
12872  };
12873
12874  /**
12875   * Create the `PosterImage`s DOM element.
12876   *
12877   * @return {Element}
12878   *         The element that gets created.
12879   */
12880
12881
12882  PosterImage.prototype.createEl = function createEl() {
12883    var el = Dom.createEl('div', {
12884      className: 'vjs-poster',
12885
12886      // Don't want poster to be tabbable.
12887      tabIndex: -1
12888    });
12889
12890    // To ensure the poster image resizes while maintaining its original aspect
12891    // ratio, use a div with `background-size` when available. For browsers that
12892    // do not support `background-size` (e.g. IE8), fall back on using a regular
12893    // img element.
12894    if (!browser.BACKGROUND_SIZE_SUPPORTED) {
12895      this.fallbackImg_ = Dom.createEl('img');
12896      el.appendChild(this.fallbackImg_);
12897    }
12898
12899    return el;
12900  };
12901
12902  /**
12903   * An {@link EventTarget~EventListener} for {@link Player#posterchange} events.
12904   *
12905   * @listens Player#posterchange
12906   *
12907   * @param {EventTarget~Event} [event]
12908   *        The `Player#posterchange` event that triggered this function.
12909   */
12910
12911
12912  PosterImage.prototype.update = function update(event) {
12913    var url = this.player().poster();
12914
12915    this.setSrc(url);
12916
12917    // If there's no poster source we should display:none on this component
12918    // so it's not still clickable or right-clickable
12919    if (url) {
12920      this.show();
12921    } else {
12922      this.hide();
12923    }
12924  };
12925
12926  /**
12927   * Set the source of the `PosterImage` depending on the display method.
12928   *
12929   * @param {string} url
12930   *        The URL to the source for the `PosterImage`.
12931   */
12932
12933
12934  PosterImage.prototype.setSrc = function setSrc(url) {
12935    if (this.fallbackImg_) {
12936      this.fallbackImg_.src = url;
12937    } else {
12938      var backgroundImage = '';
12939
12940      // Any falsey values should stay as an empty string, otherwise
12941      // this will throw an extra error
12942      if (url) {
12943        backgroundImage = 'url("' + url + '")';
12944      }
12945
12946      this.el_.style.backgroundImage = backgroundImage;
12947    }
12948  };
12949
12950  /**
12951   * An {@link EventTarget~EventListener} for clicks on the `PosterImage`. See
12952   * {@link ClickableComponent#handleClick} for instances where this will be triggered.
12953   *
12954   * @listens tap
12955   * @listens click
12956   * @listens keydown
12957   *
12958   * @param {EventTarget~Event} event
12959   +        The `click`, `tap` or `keydown` event that caused this function to be called.
12960   */
12961
12962
12963  PosterImage.prototype.handleClick = function handleClick(event) {
12964    // We don't want a click to trigger playback when controls are disabled
12965    if (!this.player_.controls()) {
12966      return;
12967    }
12968
12969    if (this.player_.paused()) {
12970      this.player_.play();
12971    } else {
12972      this.player_.pause();
12973    }
12974  };
12975
12976  return PosterImage;
12977}(_clickableComponent2['default']);
12978
12979_component2['default'].registerComponent('PosterImage', PosterImage);
12980exports['default'] = PosterImage;
12981
12982},{"3":3,"5":5,"78":78,"81":81,"83":83}],56:[function(_dereq_,module,exports){
12983'use strict';
12984
12985exports.__esModule = true;
12986exports.hasLoaded = exports.autoSetupTimeout = exports.autoSetup = undefined;
12987
12988var _dom = _dereq_(81);
12989
12990var Dom = _interopRequireWildcard(_dom);
12991
12992var _events = _dereq_(82);
12993
12994var Events = _interopRequireWildcard(_events);
12995
12996var _document = _dereq_(94);
12997
12998var _document2 = _interopRequireDefault(_document);
12999
13000var _window = _dereq_(95);
13001
13002var _window2 = _interopRequireDefault(_window);
13003
13004function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
13005
13006function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
13007
13008/**
13009 * @file setup.js - Functions for setting up a player without
13010 * user interaction based on the data-setup `attribute` of the video tag.
13011 *
13012 * @module setup
13013 */
13014var _windowLoaded = false;
13015var videojs = void 0;
13016
13017/**
13018 * Set up any tags that have a data-setup `attribute` when the player is started.
13019 */
13020var autoSetup = function autoSetup() {
13021
13022  // Protect against breakage in non-browser environments.
13023  if (!Dom.isReal()) {
13024    return;
13025  }
13026
13027  // One day, when we stop supporting IE8, go back to this, but in the meantime...*hack hack hack*
13028  // var vids = Array.prototype.slice.call(document.getElementsByTagName('video'));
13029  // var audios = Array.prototype.slice.call(document.getElementsByTagName('audio'));
13030  // var mediaEls = vids.concat(audios);
13031
13032  // Because IE8 doesn't support calling slice on a node list, we need to loop
13033  // through each list of elements to build up a new, combined list of elements.
13034  var vids = _document2['default'].getElementsByTagName('video');
13035  var audios = _document2['default'].getElementsByTagName('audio');
13036  var mediaEls = [];
13037
13038  if (vids && vids.length > 0) {
13039    for (var i = 0, e = vids.length; i < e; i++) {
13040      mediaEls.push(vids[i]);
13041    }
13042  }
13043
13044  if (audios && audios.length > 0) {
13045    for (var _i = 0, _e = audios.length; _i < _e; _i++) {
13046      mediaEls.push(audios[_i]);
13047    }
13048  }
13049
13050  // Check if any media elements exist
13051  if (mediaEls && mediaEls.length > 0) {
13052
13053    for (var _i2 = 0, _e2 = mediaEls.length; _i2 < _e2; _i2++) {
13054      var mediaEl = mediaEls[_i2];
13055
13056      // Check if element exists, has getAttribute func.
13057      // IE seems to consider typeof el.getAttribute == 'object' instead of
13058      // 'function' like expected, at least when loading the player immediately.
13059      if (mediaEl && mediaEl.getAttribute) {
13060
13061        // Make sure this player hasn't already been set up.
13062        if (mediaEl.player === undefined) {
13063          var options = mediaEl.getAttribute('data-setup');
13064
13065          // Check if data-setup attr exists.
13066          // We only auto-setup if they've added the data-setup attr.
13067          if (options !== null) {
13068            // Create new video.js instance.
13069            videojs(mediaEl);
13070          }
13071        }
13072
13073        // If getAttribute isn't defined, we need to wait for the DOM.
13074      } else {
13075        autoSetupTimeout(1);
13076        break;
13077      }
13078    }
13079
13080    // No videos were found, so keep looping unless page is finished loading.
13081  } else if (!_windowLoaded) {
13082    autoSetupTimeout(1);
13083  }
13084};
13085
13086/**
13087 * Wait until the page is loaded before running autoSetup. This will be called in
13088 * autoSetup if `hasLoaded` returns false.
13089 *
13090 * @param {number} wait
13091 *        How long to wait in ms
13092 *
13093 * @param {videojs} [vjs]
13094 *        The videojs library function
13095 */
13096function autoSetupTimeout(wait, vjs) {
13097  if (vjs) {
13098    videojs = vjs;
13099  }
13100
13101  _window2['default'].setTimeout(autoSetup, wait);
13102}
13103
13104if (Dom.isReal() && _document2['default'].readyState === 'complete') {
13105  _windowLoaded = true;
13106} else {
13107  /**
13108   * Listen for the load event on window, and set _windowLoaded to true.
13109   *
13110   * @listens load
13111   */
13112  Events.one(_window2['default'], 'load', function () {
13113    _windowLoaded = true;
13114  });
13115}
13116
13117/**
13118 * check if the document has been loaded
13119 */
13120var hasLoaded = function hasLoaded() {
13121  return _windowLoaded;
13122};
13123
13124exports.autoSetup = autoSetup;
13125exports.autoSetupTimeout = autoSetupTimeout;
13126exports.hasLoaded = hasLoaded;
13127
13128},{"81":81,"82":82,"94":94,"95":95}],57:[function(_dereq_,module,exports){
13129'use strict';
13130
13131exports.__esModule = true;
13132
13133var _component = _dereq_(5);
13134
13135var _component2 = _interopRequireDefault(_component);
13136
13137var _dom = _dereq_(81);
13138
13139var Dom = _interopRequireWildcard(_dom);
13140
13141var _obj = _dereq_(88);
13142
13143function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
13144
13145function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
13146
13147function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
13148
13149function _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; }
13150
13151function _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, { c
13151onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
13152                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file slider.js
13153                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
13154
13155
13156/**
13157 * The base functionality for a slider. Can be vertical or horizontal.
13158 * For instance the volume bar or the seek bar on a video is a slider.
13159 *
13160 * @extends Component
13161 */
13162var Slider = function (_Component) {
13163  _inherits(Slider, _Component);
13164
13165  /**
13166   * Create an instance of this class
13167   *
13168   * @param {Player} player
13169   *        The `Player` that this class should be attached to.
13170   *
13171   * @param {Object} [options]
13172   *        The key/value store of player options.
13173   */
13174  function Slider(player, options) {
13175    _classCallCheck(this, Slider);
13176
13177    // Set property names to bar to match with the child Slider class is looking for
13178    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
13179
13180    _this.bar = _this.getChild(_this.options_.barName);
13181
13182    // Set a horizontal or vertical class on the slider depending on the slider type
13183    _this.vertical(!!_this.options_.vertical);
13184
13185    _this.on('mousedown', _this.handleMouseDown);
13186    _this.on('touchstart', _this.handleMouseDown);
13187    _this.on('focus', _this.handleFocus);
13188    _this.on('blur', _this.handleBlur);
13189    _this.on('click', _this.handleClick);
13190
13191    _this.on(player, 'controlsvisible', _this.update);
13192    _this.on(player, _this.playerEvent, _this.update);
13193    return _this;
13194  }
13195
13196  /**
13197   * Create the `Button`s DOM element.
13198   *
13199   * @param {string} type
13200   *        Type of element to create.
13201   *
13202   * @param {Object} [props={}]
13203   *        List of properties in Object form.
13204   *
13205   * @param {Object} [attributes={}]
13206   *        list of attributes in Object form.
13207   *
13208   * @return {Element}
13209   *         The element that gets created.
13210   */
13211
13212
13213  Slider.prototype.createEl = function createEl(type) {
13214    var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
13215    var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
13216
13217    // Add the slider element class to all sub classes
13218    props.className = props.className + ' vjs-slider';
13219    props = (0, _obj.assign)({
13220      tabIndex: 0
13221    }, props);
13222
13223    attributes = (0, _obj.assign)({
13224      'role': 'slider',
13225      'aria-valuenow': 0,
13226      'aria-valuemin': 0,
13227      'aria-valuemax': 100,
13228      'tabIndex': 0
13229    }, attributes);
13230
13231    return _Component.prototype.createEl.call(this, type, props, attributes);
13232  };
13233
13234  /**
13235   * Handle `mousedown` or `touchstart` events on the `Slider`.
13236   *
13237   * @param {EventTarget~Event} event
13238   *        `mousedown` or `touchstart` event that triggered this function
13239   *
13240   * @listens mousedown
13241   * @listens touchstart
13242   * @fires Slider#slideractive
13243   */
13244
13245
13246  Slider.prototype.handleMouseDown = function handleMouseDown(event) {
13247    var doc = this.bar.el_.ownerDocument;
13248
13249    event.preventDefault();
13250    Dom.blockTextSelection();
13251
13252    this.addClass('vjs-sliding');
13253    /**
13254     * Triggered when the slider is in an active state
13255     *
13256     * @event Slider#slideractive
13257     * @type {EventTarget~Event}
13258     */
13259    this.trigger('slideractive');
13260
13261    this.on(doc, 'mousemove', this.handleMouseMove);
13262    this.on(doc, 'mouseup', this.handleMouseUp);
13263    this.on(doc, 'touchmove', this.handleMouseMove);
13264    this.on(doc, 'touchend', this.handleMouseUp);
13265
13266    this.handleMouseMove(event);
13267  };
13268
13269  /**
13270   * Handle the `mousemove`, `touchmove`, and `mousedown` events on this `Slider`.
13271   * The `mousemove` and `touchmove` events will only only trigger this function during
13272   * `mousedown` and `touchstart`. This is due to {@link Slider#handleMouseDown} and
13273   * {@link Slider#handleMouseUp}.
13274   *
13275   * @param {EventTarget~Event} event
13276   *        `mousedown`, `mousemove`, `touchstart`, or `touchmove` event that triggered
13277   *        this function
13278   *
13279   * @listens mousemove
13280   * @listens touchmove
13281   */
13282
13283
13284  Slider.prototype.handleMouseMove = function handleMouseMove(event) {};
13285
13286  /**
13287   * Handle `mouseup` or `touchend` events on the `Slider`.
13288   *
13289   * @param {EventTarget~Event} event
13290   *        `mouseup` or `touchend` event that triggered this function.
13291   *
13292   * @listens touchend
13293   * @listens mouseup
13294   * @fires Slider#sliderinactive
13295   */
13296
13297
13298  Slider.prototype.handleMouseUp = function handleMouseUp() {
13299    var doc = this.bar.el_.ownerDocument;
13300
13301    Dom.unblockTextSelection();
13302
13303    this.removeClass('vjs-sliding');
13304    /**
13305     * Triggered when the slider is no longer in an active state.
13306     *
13307     * @event Slider#sliderinactive
13308     * @type {EventTarget~Event}
13309     */
13310    this.trigger('sliderinactive');
13311
13312    this.off(doc, 'mousemove', this.handleMouseMove);
13313    this.off(doc, 'mouseup', this.handleMouseUp);
13314    this.off(doc, 'touchmove', this.handleMouseMove);
13315    this.off(doc, 'touchend', this.handleMouseUp);
13316
13317    this.update();
13318  };
13319
13320  /**
13321   * Update the progress bar of the `Slider`.
13322   */
13323
13324
13325  Slider.prototype.update = function update() {
13326    // In VolumeBar init we have a setTimeout for update that pops and update to the end of the
13327    // execution stack. The player is destroyed before then update will cause an error
13328    if (!this.el_) {
13329      return;
13330    }
13331
13332    // If scrubbing, we could use a cached value to make the handle keep up with the user's mouse.
13333    // On HTML5 browsers scrubbing is really smooth, but some flash players are slow, so we might want to utilize this later.
13334    // var progress =  (this.player_.scrubbing()) ? this.player_.getCache().currentTime / this.player_.duration() : this.player_.currentTime() / this.player_.duration();
13335    var progress = this.getPercent();
13336    var bar = this.bar;
13337
13338    // If there's no bar...
13339    if (!bar) {
13340      return;
13341    }
13342
13343    // Protect against no duration and other division issues
13344    if (typeof progress !== 'number' || progress !== progress || progress < 0 || progress === Infinity) {
13345      progress = 0;
13346    }
13347
13348    // Convert to a percentage for setting
13349    var percentage = (progress * 100).toFixed(2) + '%';
13350
13351    // Set the new bar width or height
13352    if (this.vertical()) {
13353      bar.el().style.height = percentage;
13354    } else {
13355      bar.el().style.width = percentage;
13356    }
13357  };
13358
13359  /**
13360   * Calculate distance for slider
13361   *
13362   * @param {EventTarget~Event} event
13363   *        The event that caused this function to run.
13364   *
13365   * @return {number}
13366   *         The current position of the Slider.
13367   *         - postition.x for vertical `Slider`s
13368   *         - postition.y for horizontal `Slider`s
13369   */
13370
13371
13372  Slider.prototype.calculateDistance = function calculateDistance(event) {
13373    var position = Dom.getPointerPosition(this.el_, event);
13374
13375    if (this.vertical()) {
13376      return position.y;
13377    }
13378    return position.x;
13379  };
13380
13381  /**
13382   * Handle a `focus` event on this `Slider`.
13383   *
13384   * @param {EventTarget~Event} event
13385   *        The `focus` event that caused this function to run.
13386   *
13387   * @listens focus
13388   */
13389
13390
13391  Slider.prototype.handleFocus = function handleFocus() {
13392    this.on(this.bar.el_.ownerDocument, 'keydown', this.handleKeyPress);
13393  };
13394
13395  /**
13396   * Handle a `keydown` event on the `Slider`. Watches for left, rigth, up, and down
13397   * arrow keys. This function will only be called when the slider has focus. See
13398   * {@link Slider#handleFocus} and {@link Slider#handleBlur}.
13399   *
13400   * @param {EventTarget~Event} event
13401   *        the `keydown` event that caused this function to run.
13402   *
13403   * @listens keydown
13404   */
13405
13406
13407  Slider.prototype.handleKeyPress = function handleKeyPress(event) {
13408    // Left and Down Arrows
13409    if (event.which === 37 || event.which === 40) {
13410      event.preventDefault();
13411      this.stepBack();
13412
13413      // Up and Right Arrows
13414    } else if (event.which === 38 || event.which === 39) {
13415      event.preventDefault();
13416      this.stepForward();
13417    }
13418  };
13419
13420  /**
13421   * Handle a `blur` event on this `Slider`.
13422   *
13423   * @param {EventTarget~Event} event
13424   *        The `blur` event that caused this function to run.
13425   *
13426   * @listens blur
13427   */
13428
13429  Slider.prototype.handleBlur = function handleBlur() {
13430    this.off(this.bar.el_.ownerDocument, 'keydown', this.handleKeyPress);
13431  };
13432
13433  /**
13434   * Listener for click events on slider, used to prevent clicks
13435   *   from bubbling up to parent elements like button menus.
13436   *
13437   * @param {Object} event
13438   *        Event that caused this object to run
13439   */
13440
13441
13442  Slider.prototype.handleClick = function handleClick(event) {
13443    event.stopImmediatePropagation();
13444    event.preventDefault();
13445  };
13446
13447  /**
13448   * Get/set if slider is horizontal for vertical
13449   *
13450   * @param {boolean} [bool]
13451   *        - true if slider is vertical,
13452   *        - false is horizontal
13453   *
13454   * @return {boolean|Slider}
13455   *         - true if slider is vertical, and getting
13456   *         - false is horizontal, and getting
13457   *         - a reference to this object when setting
13458   */
13459
13460
13461  Slider.prototype.vertical = function vertical(bool) {
13462    if (bool === undefined) {
13463      return this.vertical_ || false;
13464    }
13465
13466    this.vertical_ = !!bool;
13467
13468    if (this.vertical_) {
13469      this.addClass('vjs-slider-vertical');
13470    } else {
13471      this.addClass('vjs-slider-horizontal');
13472    }
13473
13474    return this;
13475  };
13476
13477  return Slider;
13478}(_component2['default']);
13479
13480_component2['default'].registerComponent('Slider', Slider);
13481exports['default'] = Slider;
13482
13483},{"5":5,"81":81,"88":88}],58:[function(_dereq_,module,exports){
13484'use strict';
13485
13486exports.__esModule = true;
13487/**
13488 * @file flash-rtmp.js
13489 * @module flash-rtmp
13490 */
13491
13492/**
13493 * Add RTMP properties to the {@link Flash} Tech.
13494 *
vendor: 4,097 bytes, lines 13495-13665
13495 * @param {Flash} Flash
13496 *        The flash tech class.
13497 *
13498 * @mixin FlashRtmpDecorator
13499 */
13500function FlashRtmpDecorator(Flash) {
13501  Flash.streamingFormats = {
13502    'rtmp/mp4': 'MP4',
13503    'rtmp/flv': 'FLV'
13504  };
13505
13506  /**
13507   * Join connection and stream with an ampersand.
13508   *
13509   * @param {string} connection
13510   *        The connection string.
13511   *
13512   * @param {string} stream
13513   *        The stream string.
13514   */
13515  Flash.streamFromParts = function (connection, stream) {
13516    return connection + '&' + stream;
13517  };
13518
13519  /**
13520   * The flash parts object that contains connection and stream info.
13521   *
13522   * @typedef {Object} Flash~PartsObject
13523   *
13524   * @property {string} connection
13525   *           The connection string of a source, defaults to an empty string.
13526   *
13527   * @property {string} stream
13528   *           The stream string of the source, defaults to an empty string.
13529   */
13530
13531  /**
13532   * Convert a source url into a stream and connection parts.
13533   *
13534   * @param {string} src
13535   *        the source url
13536   *
13537   * @return {Flash~PartsObject}
13538   *         The parts object that contains a connection and a stream
13539   */
13540  Flash.streamToParts = function (src) {
13541    var parts = {
13542      connection: '',
13543      stream: ''
13544    };
13545
13546    if (!src) {
13547      return parts;
13548    }
13549
13550    // Look for the normal URL separator we expect, '&'.
13551    // If found, we split the URL into two pieces around the
13552    // first '&'.
13553    var connEnd = src.search(/&(?!\w+=)/);
13554    var streamBegin = void 0;
13555
13556    if (connEnd !== -1) {
13557      streamBegin = connEnd + 1;
13558    } else {
13559      // If there's not a '&', we use the last '/' as the delimiter.
13560      connEnd = streamBegin = src.lastIndexOf('/') + 1;
13561      if (connEnd === 0) {
13562        // really, there's not a '/'?
13563        connEnd = streamBegin = src.length;
13564      }
13565    }
13566
13567    parts.connection = src.substring(0, connEnd);
13568    parts.stream = src.substring(streamBegin, src.length);
13569
13570    return parts;
13571  };
13572
13573  /**
13574   * Check if the source type is a streaming type.
13575   *
13576   * @param {string} srcType
13577   *        The mime type to check.
13578   *
13579   * @return {boolean}
13580   *          - True if the source type is a streaming type.
13581   *          - False if the source type is not a streaming type.
13582   */
13583  Flash.isStreamingType = function (srcType) {
13584    return srcType in Flash.streamingFormats;
13585  };
13586
13587  // RTMP has four variations, any string starting
13588  // with one of these protocols should be valid
13589
13590  /**
13591   * Regular expression used to check if the source is an rtmp source.
13592   *
13593   * @property {RegExp} Flash.RTMP_RE
13594   */
13595  Flash.RTMP_RE = /^rtmp[set]?:\/\//i;
13596
13597  /**
13598   * Check if the source itself is a streaming type.
13599   *
13600   * @param {string} src
13601   *        The url to the source.
13602   *
13603   * @return {boolean}
13604   *          - True if the source url indicates that the source is streaming.
13605   *          - False if the shource url indicates that the source url is not streaming.
13606   */
13607  Flash.isStreamingSrc = function (src) {
13608    return Flash.RTMP_RE.test(src);
13609  };
13610
13611  /**
13612   * A source handler for RTMP urls
13613   * @type {Object}
13614   */
13615  Flash.rtmpSourceHandler = {};
13616
13617  /**
13618   * Check if Flash can play the given mime type.
13619   *
13620   * @param {string} type
13621   *        The mime type to check
13622   *
13623   * @return {string}
13624   *         'maybe', or '' (empty string)
13625   */
13626  Flash.rtmpSourceHandler.canPlayType = function (type) {
13627    if (Flash.isStreamingType(type)) {
13628      return 'maybe';
13629    }
13630
13631    return '';
13632  };
13633
13634  /**
13635   * Check if Flash can handle the source natively
13636   *
13637   * @param {Object} source
13638   *        The source object
13639   *
13640   * @param {Object} [options]
13641   *        The options passed to the tech
13642   *
13643   * @return {string}
13644   *         'maybe', or '' (empty string)
13645   */
13646  Flash.rtmpSourceHandler.canHandleSource = function (source, options) {
13647    var can = Flash.rtmpSourceHandler.canPlayType(source.type);
13648
13649    if (can) {
13650      return can;
13651    }
13652
13653    if (Flash.isStreamingSrc(source.src)) {
13654      return 'maybe';
13655    }
13656
13657    return '';
13658  };
13659
13660  /**
13661   * Pass the source to the flash object.
13662   *
13663   * @param {Object} source
13664   *        The source object
13665   *
13666   * @param {Flash} tech
13667   *        The instance of the Flash tech
13668   *
13669   * @param {Object} [options]
13670   *        The options to pass to the source
13671   */
13672  Flash.rtmpSourceHandler.handleSource = function (source, tech, options) {
13673    var srcParts = Flash.streamToParts(source.src);
13674
13675    tech.setRtmpConnection(srcParts.connection);
13676    tech.setRtmpStream(srcParts.stream);
13677  };
13678
13679  // Register the native source handler
13680  Flash.registerSourceHandler(Flash.rtmpSourceHandler);
13681
13682  return Flash;
13683}
13684
13685exports['default'] = FlashRtmpDecorator;
13686
13687},{}],59:[function(_dereq_,module,exports){
13688'use strict';
13689
13690exports.__esModule = true;
13691
13692var _tech = _dereq_(62);
13693
13694var _tech2 = _interopRequireDefault(_tech);
13695
13696var _dom = _dereq_(81);
13697
13698var Dom = _interopRequireWildcard(_dom);
13699
13700var _url = _dereq_(92);
13701
13702var Url = _interopRequireWildcard(_url);
13703
13704var _timeRanges = _dereq_(90);
13705
13706var _flashRtmp = _dereq_(58);
13707
13708var _flashRtmp2 = _interopRequireDefault(_flashRtmp);
13709
13710var _component = _dereq_(5);
13711
13712var _component2 = _interopRequireDefault(_component);
13713
13714var _window = _dereq_(95);
13715
13716var _window2 = _interopRequireDefault(_window);
13717
13718var _obj = _dereq_(88);
13719
13720function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
13721
13722function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
13723
13724function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
13725
13726function _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; }
13727
13728function _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; } /**
13729                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file flash.js
13730                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * VideoJS-SWF - Custom Flash Player with HTML5-ish API
13731                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * https://github.com/zencoder/video-js-swf
13732                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Not using setupTriggers. Using global onEvent func to distribute events
13733                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
13734
13735var navigator = _window2['default'].navigator;
13736
13737/**
13738 * Flash Media Controller - Wrapper for Flash Media API
13739 *
13740 * @mixes FlashRtmpDecorator
13741 * @mixes Tech~SouceHandlerAdditions
13742 * @extends Tech
13743 */
13744
13745var Flash = function (_Tech) {
13746  _inherits(Flash, _Tech);
13747
13748  /**
13749   * Create an instance of this Tech.
13750   *
13751   * @param {Object} [options]
13752   *        The key/value store of player options.
13753   *
13754   * @param {Component~ReadyCallback} ready
13755   *        Callback function to call when the `Flash` Tech is ready.
13756   */
13757  function Flash(options, ready) {
13758    _classCallCheck(this, Flash);
13759
13760    // Set the source when ready
13761    var _this = _possibleConstructorReturn(this, _Tech.call(this, options, ready));
13762
13763    if (options.source) {
13764      _this.ready(function () {
13765        this.setSource(options.source);
13766      }, true);
13767    }
13768
13769    // Having issues with Flash reloading on certain page actions (hide/resize/fullscreen) in certain browsers
13770    // This allows resetting the playhead when we catch the reload
13771    if (options.startTime) {
13772      _this.ready(function () {
13773        this.load();
13774        this.play();
13775        this.currentTime(options.startTime);
13776      }, true);
13777    }
13778
13779    // Add global window functions that the swf expects
13780    // A 4.x workflow we weren't able to solve for in 5.0
13781    // because of the need to hard code these functions
13782    // into the swf for security reasons
13783    _window2['default'].videojs = _window2['default'].videojs || {};
13784    _window2['default'].videojs.Flash = _window2['default'].videojs.Flash || {};
13785    _window2['default'].videojs.Flash.onReady = Flash.onReady;
13786    _window2['default'].videojs.Flash.onEvent = Flash.onEvent;
13787    _window2['default'].videojs.Flash.onError = Flash.onError;
13788
13789    _this.on('seeked', function () {
13790      this.lastSeekTarget_ = undefined;
13791    });
13792
13793    return _this;
13794  }
13795
13796  /**
13797   * Create the `Flash` Tech's DOM element.
13798   *
13799   * @return {Element}
13800   *         The element that gets created.
13801   */
13802
13803
13804  Flash.prototype.createEl = function createEl() {
13805    var options = this.options_;
13806
13807    // If video.js is hosted locally you should also set the location
13808    // for the hosted swf, which should be relative to the page (not video.js)
13809    // Otherwise this adds a CDN url.
13810    // The CDN also auto-adds a swf URL for that specific version.
13811    if (!options.swf) {
13812      var ver = '5.4.1';
13813
13814      options.swf = '//vjs.zencdn.net/swf/' + ver + '/video-js.swf';
13815    }
13816
13817    // Generate ID for swf object
13818    var objId = options.techId;
13819
13820    // Merge default flashvars with ones passed in to init
13821    var flashVars = (0, _obj.assign)({
13822
13823      // SWF Callback Functions
13824      readyFunction: 'videojs.Flash.onReady',
13825      eventProxyFunction: 'videojs.Flash.onEvent',
13826      errorEventProxyFunction: 'videojs.Flash.onError',
13827
13828      // Player Settings
13829      autoplay: options.autoplay,
13830      preload: options.preload,
13831      loop: options.loop,
13832      muted: options.muted
13833
13834    }, options.flashVars);
13835
13836    // Merge default parames with ones passed in
13837    var params = (0, _obj.assign)({
13838      // Opaque is needed to overlay controls, but can affect playback performance
13839      wmode: 'opaque',
13840      // Using bgcolor prevents a white flash when the object is loading
13841      bgcolor: '#000000'
13842    }, options.params);
13843
13844    // Merge default attributes with ones passed in
13845    var attributes = (0, _obj.assign)({
13846      // Both ID and Name needed or swf to identify itself
13847      id: objId,
13848      name: objId,
13849      'class': 'vjs-tech'
13850    }, options.attributes);
13851
13852    this.el_ = Flash.embed(options.swf, flashVars, params, attributes);
13853    this.el_.tech = this;
13854
13855    return this.el_;
13856  };
13857
13858  /**
13859   * Called by {@link Player#play} to play using the `Flash` `Tech`.
13860   */
13861
13862
13863  Flash.prototype.play = function play() {
13864    if (this.ended()) {
13865      this.setCurrentTime(0);
13866    }
13867    this.el_.vjs_play();
13868  };
13869
13870  /**
13871   * Called by {@link Player#pause} to pause using the `Flash` `Tech`.
13872   */
13873
13874
13875  Flash.prototype.pause = function pause() {
13876    this.el_.vjs_pause();
13877  };
13878
13879  /**
13880   * A getter/setter for the `Flash` Tech's source object.
13881   * > Note: Please use {@link Flash#setSource}
13882   *
13883   * @param {Tech~SourceObject} [src]
13884   *        The source object you want to set on the `Flash` techs.
13885   *
13886   * @return {Tech~SourceObject|undefined}
13887   *         - The current source object when a source is not passed in.
13888   *         - undefined when setting
13889   *
13890   * @deprecated Since version 5.
13891   */
13892
13893
13894  Flash.prototype.src = function src(_src) {
13895    if (_src === undefined) {
13896      return this.currentSrc();
13897    }
13898
13899    // Setting src through `src` not `setSrc` will be deprecated
13900    return this.setSrc(_src);
13901  };
13902
13903  /**
13904   * A getter/setter for the `Flash` Tech's source object.
13905   *
13906   * @param {Tech~SourceObject} [src]
13907   *        The source object you want to set on the `Flash` techs.
13908   *
13909   * @return {Tech~SourceObject|undefined}
13910   *         - The current source object when a source is not passed in.
13911   *         - undefined when setting
13912   */
13913
13914
13915  Flash.prototype.setSrc = function setSrc(src) {
13916    var _this2 = this;
13917
13918    // Make sure source URL is absolute.
13919    src = Url.getAbsoluteURL(src);
13920    this.el_.vjs_src(src);
13921
13922    // Currently the SWF doesn't autoplay if you load a source later.
13923    // e.g. Load player w/ no source, wait 2s, set src.
13924    if (this.autoplay()) {
13925      this.setTimeout(function () {
13926        return _this2.play();
13927      }, 0);
13928    }
13929  };
13930
13931  /**
13932   * Indicates whether the media is currently seeking to a new position or not.
13933   *
13934   * @return {boolean}
13935   *         - True if seeking to a new position
13936   *         - False otherwise
13937   */
13938
13939
13940  Flash.prototype.seeking = function seeking() {
13941    return this.lastSeekTarget_ !== undefined;
13942  };
13943
13944  /**
13945   * Returns the current time in seconds that the media is at in playback.
13946   *
13947   * @param {number} time
13948   *        Current playtime of the media in seconds.
13949   */
13950
13951
13952  Flash.prototype.setCurrentTime = function setCurrentTime(time) {
13953    var seekable = this.seekable();
13954
13955    if (seekable.length) {
13956      // clamp to the current seekable range
13957      time = time > seekable.start(0) ? time : seekable.start(0);
13958      time = time < seekable.end(seekable.length - 1) ? time : seekable.end(seekable.length - 1);
13959
13960      this.lastSeekTarget_ = time;
13961      this.trigger('seeking');
13962      this.el_.vjs_setProperty('currentTime', time);
13963      _Tech.prototype.setCurrentTime.call(this);
13964    }
13965  };
13966
13967  /**
13968   * Get the current playback time in seconds
13969   *
13970   * @return {number}
13971   *         The current time of playback in seconds.
13972   */
13973
13974
13975  Flash.prototype.currentTime = function currentTime() {
13976    // when seeking make the reported time keep up with the requested time
13977    // by reading the time we're seeking to
13978    if (this.seeking()) {
13979      return this.lastSeekTarget_ || 0;
13980    }
13981    return this.el_.vjs_getProperty('currentTime');
13982  };
13983
13984  /**
13985   * Get the current source
13986   *
13987   * @method currentSrc
13988   * @return {Tech~SourceObject}
13989   *         The current source
13990   */
13991
13992
13993  Flash.prototype.currentSrc = function currentSrc() {
13994    if (this.currentSource_) {
13995      return this.currentSource_.src;
13996    }
13997    return this.el_.vjs_getProperty('currentSrc');
13998  };
13999
14000  /**
14001   * Get the total duration of the current media.
14002   *
14003   * @return {number}
14004   8          The total duration of the current media.
14005   */
14006
14007
14008  Flash.prototype.duration = function duration() {
14009    if (this.readyState() === 0) {
14010      return NaN;
14011    }
14012    var duration = this.el_.vjs_getProperty('duration');
14013
14014    return duration >= 0 ? duration : Infinity;
14015  };
14016
14017  /**
14018   * Load media into Tech.
14019   */
14020
14021
14022  Flash.prototype.load = function load() {
14023    this.el_.vjs_load();
14024  };
14025
14026  /**
14027   * Get the poster image that was set on the tech.
14028   */
14029
14030
14031  Flash.prototype.poster = function poster() {
14032    this.el_.vjs_getProperty('poster');
14033  };
14034
14035  /**
14036   * Poster images are not handled by the Flash tech so make this is a no-op.
14037   */
14038
14039
14040  Flash.prototype.setPoster = function setPoster() {};
14041
14042  /**
14043   * Determine the time ranges that can be seeked to in the media.
14044   *
14045   * @return {TimeRange}
14046   *         Returns the time ranges that can be seeked to.
14047   */
14048
14049
14050  Flash.prototype.seekable = function seekable() {
14051    var duration = this.duration();
14052
14053    if (duration === 0) {
14054      return (0, _timeRanges.createTimeRange)();
14055    }
14056    return (0, _timeRanges.createTimeRange)(0, duration);
14057  };
14058
14059  /**
14060   * Get and create a `TimeRange` object for buffering.
14061   *
14062   * @return {TimeRange}
14063   *         The time range object that was created.
14064   */
14065
14066
14067  Flash.prototype.buffered = function buffered() {
14068    var ranges = this.el_.vjs_getProperty('buffered');
14069
14070    if (ranges.length === 0) {
14071      return (0, _timeRanges.createTimeRange)();
14072    }
14073    return (0, _timeRanges.createTimeRange)(ranges[0][0], ranges[0][1]);
14074  };
14075
14076  /**
14077   * Get fullscreen support -
14078   *
14079   * Flash does not allow fullscreen through javascript
14080   * so this always returns false.
14081   *
14082   * @return {boolean}
14083   *         The Flash tech does not support fullscreen, so it will always return false.
14084   */
14085
14086
14087  Flash.prototype.supportsFullScreen = function supportsFullScreen() {
14088    // Flash does not allow fullscreen through javascript
14089    return false;
14090  };
14091
14092  /**
14093   * Flash does not allow fullscreen through javascript
14094   * so this always returns false.
14095   *
14096   * @return {boolean}
14097   *         The Flash tech does not support fullscreen, so it will always return false.
14098   */
14099
14100
14101  Flash.prototype.enterFullScreen = function enterFullScreen() {
14102    return false;
14103  };
14104
14105  /**
14106   * Gets available media playback quality metrics as specified by the W3C's Media
14107   * Playback Quality API.
14108   *
14109   * @see [Spec]{@link https://wicg.github.io/media-playback-quality}
14110   *
14111   * @return {Object}
14112   *         An object with supported media playback quality metrics
14113   */
14114
14115
14116  Flash.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() {
14117    var videoPlaybackQuality = this.el_.vjs_getProperty('getVideoPlaybackQuality');
14118
14119    if (_window2['default'].performance && typeof _window2['default'].performance.now === 'function') {
14120      videoPlaybackQuality.creationTime = _window2['default'].performance.now();
14121    } else if (_window2['default'].performance && _window2['default'].performance.timing && typeof _window2['default'].performance.timing.navigationStart === 'number') {
14122      videoPlaybackQuality.creationTime = _window2['default'].Date.now() - _window2['default'].performance.timing.navigationStart;
14123    }
14124
14125    return videoPlaybackQuality;
14126  };
14127
14128  return Flash;
14129}(_tech2['default']);
14130
14131// Create setters and getters for attributes
14132
14133
14134var _api = Flash.prototype;
14135var _readWrite = 'rtmpConnection,rtmpStream,preload,defaultPlaybackRate,playbackRate,autoplay,loop,mediaGroup,controller,controls,volume,muted,defaultMuted'.split(',');
14136var _readOnly = 'networkState,readyState,initialTime,startOffsetTime,paused,ended,videoWidth,videoHeight'.split(',');
14137
14138function _createSetter(attr) {
14139  var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1);
14140
14141  _api['set' + attrUpper] = function (val) {
14142    return this.el_.vjs_setProperty(attr, val);
14143  };
14144}
vendor: 12,234 bytes, lines 14145-14546
14145
14146function _createGetter(attr) {
14147  _api[attr] = function () {
14148    return this.el_.vjs_getProperty(attr);
14149  };
14150}
14151
14152// Create getter and setters for all read/write attributes
14153for (var i = 0; i < _readWrite.length; i++) {
14154  _createGetter(_readWrite[i]);
14155  _createSetter(_readWrite[i]);
14156}
14157
14158// Create getters for read-only attributes
14159for (var _i = 0; _i < _readOnly.length; _i++) {
14160  _createGetter(_readOnly[_i]);
14161}
14162
14163/** ------------------------------ Getters ------------------------------ **/
14164/**
14165 * Get the value of `rtmpConnection` from the swf.
14166 *
14167 * @method Flash#rtmpConnection
14168 * @return {string}
14169 *         The current value of `rtmpConnection` on the swf.
14170 */
14171
14172/**
14173 * Get the value of `rtmpStream` from the swf.
14174 *
14175 * @method Flash#rtmpStream
14176 * @return {string}
14177 *         The current value of `rtmpStream` on the swf.
14178 */
14179
14180/**
14181 * Get the value of `preload` from the swf. `preload` indicates
14182 * what should download before the media is interacted with. It can have the following
14183 * values:
14184 * - none: nothing should be downloaded
14185 * - metadata: poster and the first few frames of the media may be downloaded to get
14186 *   media dimensions and other metadata
14187 * - auto: allow the media and metadata for the media to be downloaded before
14188 *    interaction
14189 *
14190 * @method Flash#preload
14191 * @return {string}
14192 *         The value of `preload` from the swf. Will be 'none', 'metadata',
14193 *         or 'auto'.
14194 */
14195
14196/**
14197 * Get the value of `defaultPlaybackRate` from the swf.
14198 *
14199 * @method Flash#defaultPlaybackRate
14200 * @return {number}
14201 *         The current value of `defaultPlaybackRate` on the swf.
14202 */
14203
14204/**
14205 * Get the value of `playbackRate` from the swf. `playbackRate` indicates
14206 * the rate at which the media is currently playing back. Examples:
14207 *   - if playbackRate is set to 2, media will play twice as fast.
14208 *   - if playbackRate is set to 0.5, media will play half as fast.
14209 *
14210 * @method Flash#playbackRate
14211 * @return {number}
14212 *         The value of `playbackRate` from the swf. A number indicating
14213 *         the current playback speed of the media, where 1 is normal speed.
14214 */
14215
14216/**
14217 * Get the value of `autoplay` from the swf. `autoplay` indicates
14218 * that the media should start to play as soon as the page is ready.
14219 *
14220 * @method Flash#autoplay
14221 * @return {boolean}
14222 *         - The value of `autoplay` from the swf.
14223 *         - True indicates that the media ashould start as soon as the page loads.
14224 *         - False indicates that the media should not start as soon as the page loads.
14225 */
14226
14227/**
14228 * Get the value of `loop` from the swf. `loop` indicates
14229 * that the media should return to the start of the media and continue playing once
14230 * it reaches the end.
14231 *
14232 * @method Flash#loop
14233 * @return {boolean}
14234 *         - The value of `loop` from the swf.
14235 *         - True indicates that playback should seek back to start once
14236 *           the end of a media is reached.
14237 *         - False indicates that playback should not loop back to the start when the
14238 *           end of the media is reached.
14239 */
14240
14241/**
14242 * Get the value of `mediaGroup` from the swf.
14243 *
14244 * @method Flash#mediaGroup
14245 * @return {string}
14246 *         The current value of `mediaGroup` on the swf.
14247 */
14248
14249/**
14250 * Get the value of `controller` from the swf.
14251 *
14252 * @method Flash#controller
14253 * @return {string}
14254 *         The current value of `controller` on the swf.
14255 */
14256
14257/**
14258 * Get the value of `controls` from the swf. `controls` indicates
14259 * whether the native flash controls should be shown or hidden.
14260 *
14261 * @method Flash#controls
14262 * @return {boolean}
14263 *         - The value of `controls` from the swf.
14264 *         - True indicates that native controls should be showing.
14265 *         - False indicates that native controls should be hidden.
14266 */
14267
14268/**
14269 * Get the value of the `volume` from the swf. `volume` indicates the current
14270 * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and
14271 * so on.
14272 *
14273 * @method Flash#volume
14274 * @return {number}
14275 *         The volume percent as a decimal. Value will be between 0-1.
14276 */
14277
14278/**
14279 * Get the value of the `muted` from the swf. `muted` indicates the current
14280 * audio level should be silent.
14281 *
14282 * @method Flash#muted
14283 * @return {boolean}
14284 *         - True if the audio should be set to silent
14285 *         - False otherwise
14286 */
14287
14288/**
14289 * Get the value of `defaultMuted` from the swf. `defaultMuted` indicates
14290 * whether the media should start muted or not. Only changes the default state of the
14291 * media. `muted` and `defaultMuted` can have different values. `muted` indicates the
14292 * current state.
14293 *
14294 * @method Flash#defaultMuted
14295 * @return {boolean}
14296 *         - The value of `defaultMuted` from the swf.
14297 *         - True indicates that the media should start muted.
14298 *         - False indicates that the media should not start muted.
14299 */
14300
14301/**
14302 * Get the value of `networkState` from the swf. `networkState` indicates
14303 * the current network state. It returns an enumeration from the following list:
14304 * - 0: NETWORK_EMPTY
14305 * - 1: NEWORK_IDLE
14306 * - 2: NETWORK_LOADING
14307 * - 3: NETWORK_NO_SOURCE
14308 *
14309 * @method Flash#networkState
14310 * @return {number}
14311 *         The value of `networkState` from the swf. This will be a number
14312 *         from the list in the description.
14313 */
14314
14315/**
14316 * Get the value of `readyState` from the swf. `readyState` indicates
14317 * the current state of the media element. It returns an enumeration from the
14318 * following list:
14319 * - 0: HAVE_NOTHING
14320 * - 1: HAVE_METADATA
14321 * - 2: HAVE_CURRENT_DATA
14322 * - 3: HAVE_FUTURE_DATA
14323 * - 4: HAVE_ENOUGH_DATA
14324 *
14325 * @method Flash#readyState
14326 * @return {number}
14327 *         The value of `readyState` from the swf. This will be a number
14328 *         from the list in the description.
14329 */
14330
14331/**
14332 * Get the value of `readyState` from the swf. `readyState` indicates
14333 * the current state of the media element. It returns an enumeration from the
14334 * following list:
14335 * - 0: HAVE_NOTHING
14336 * - 1: HAVE_METADATA
14337 * - 2: HAVE_CURRENT_DATA
14338 * - 3: HAVE_FUTURE_DATA
14339 * - 4: HAVE_ENOUGH_DATA
14340 *
14341 * @method Flash#readyState
14342 * @return {number}
14343 *         The value of `readyState` from the swf. This will be a number
14344 *         from the list in the description.
14345 */
14346
14347/**
14348 * Get the value of `initialTime` from the swf.
14349 *
14350 * @method Flash#initialTime
14351 * @return {number}
14352 *         The `initialTime` proprety on the swf.
14353 */
14354
14355/**
14356 * Get the value of `startOffsetTime` from the swf.
14357 *
14358 * @method Flash#startOffsetTime
14359 * @return {number}
14360 *         The `startOffsetTime` proprety on the swf.
14361 */
14362
14363/**
14364 * Get the value of `paused` from the swf. `paused` indicates whether the swf
14365 * is current paused or not.
14366 *
14367 * @method Flash#paused
14368 * @return {boolean}
14369 *         The value of `paused` from the swf.
14370 */
14371
14372/**
14373 * Get the value of `ended` from the swf. `ended` indicates whether
14374 * the media has reached the end or not.
14375 *
14376 * @method Flash#ended
14377 * @return {boolean}
14378 *         - True indicates that the media has ended.
14379 *         - False indicates that the media has not ended.
14380 *
14381 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended}
14382 */
14383
14384/**
14385 * Get the value of `videoWidth` from the swf. `videoWidth` indicates
14386 * the current width of the media in css pixels.
14387 *
14388 * @method Flash#videoWidth
14389 * @return {number}
14390 *         The value of `videoWidth` from the swf. This will be a number
14391 *         in css pixels.
14392 */
14393
14394/**
14395 * Get the value of `videoHeight` from the swf. `videoHeigth` indicates
14396 * the current height of the media in css pixels.
14397 *
14398 * @method Flassh.prototype.videoHeight
14399 * @return {number}
14400 *         The value of `videoHeight` from the swf. This will be a number
14401 *         in css pixels.
14402 */
14403/** ------------------------------ Setters ------------------------------ **/
14404
14405/**
14406 * Set the value of `rtmpConnection` on the swf.
14407 *
14408 * @method Flash#setRtmpConnection
14409 * @param {string} rtmpConnection
14410 *        New value to set the `rtmpConnection` property to.
14411 */
14412
14413/**
14414 * Set the value of `rtmpStream` on the swf.
14415 *
14416 * @method Flash#setRtmpStream
14417 * @param {string} rtmpStream
14418 *        New value to set the `rtmpStream` property to.
14419 */
14420
14421/**
14422 * Set the value of `preload` on the swf. `preload` indicates
14423 * what should download before the media is interacted with. It can have the following
14424 * values:
14425 * - none: nothing should be downloaded
14426 * - metadata: poster and the first few frames of the media may be downloaded to get
14427 *   media dimensions and other metadata
14428 * - auto: allow the media and metadata for the media to be downloaded before
14429 *    interaction
14430 *
14431 * @method Flash#setPreload
14432 * @param {string} preload
14433 *        The value of `preload` to set on the swf. Should be 'none', 'metadata',
14434 *        or 'auto'.
14435 */
14436
14437/**
14438 * Set the value of `defaultPlaybackRate` on the swf.
14439 *
14440 * @method Flash#setDefaultPlaybackRate
14441 * @param {number} defaultPlaybackRate
14442 *        New value to set the `defaultPlaybackRate` property to.
14443 */
14444
14445/**
14446 * Set the value of `playbackRate` on the swf. `playbackRate` indicates
14447 * the rate at which the media is currently playing back. Examples:
14448 *   - if playbackRate is set to 2, media will play twice as fast.
14449 *   - if playbackRate is set to 0.5, media will play half as fast.
14450 *
14451 * @method Flash#setPlaybackRate
14452 * @param {number} playbackRate
14453 *        New value of `playbackRate` on the swf. A number indicating
14454 *        the current playback speed of the media, where 1 is normal speed.
14455 */
14456
14457/**
14458 * Set the value of `autoplay` on the swf. `autoplay` indicates
14459 * that the media should start to play as soon as the page is ready.
14460 *
14461 * @method Flash#setAutoplay
14462 * @param {boolean} autoplay
14463 *        - The value of `autoplay` from the swf.
14464 *        - True indicates that the media ashould start as soon as the page loads.
14465 *        - False indicates that the media should not start as soon as the page loads.
14466 */
14467
14468/**
14469 * Set the value of `loop` on the swf. `loop` indicates
14470 * that the media should return to the start of the media and continue playing once
14471 * it reaches the end.
14472 *
14473 * @method Flash#setLoop
14474 * @param {boolean} loop
14475 *        - True indicates that playback should seek back to start once
14476 *          the end of a media is reached.
14477 *        - False indicates that playback should not loop back to the start when the
14478 *          end of the media is reached.
14479 */
14480
14481/**
14482 * Set the value of `mediaGroup` on the swf.
14483 *
14484 * @method Flash#setMediaGroup
14485 * @param {string} mediaGroup
14486 *        New value of `mediaGroup` to set on the swf.
14487 */
14488
14489/**
14490 * Set the value of `controller` on the swf.
14491 *
14492 * @method Flash#setController
14493 * @param {string} controller
14494 *        New value the current value of `controller` on the swf.
14495 */
14496
14497/**
14498 * Get the value of `controls` from the swf. `controls` indicates
14499 * whether the native flash controls should be shown or hidden.
14500 *
14501 * @method Flash#controls
14502 * @return {boolean}
14503 *         - The value of `controls` from the swf.
14504 *         - True indicates that native controls should be showing.
14505 *         - False indicates that native controls should be hidden.
14506 */
14507
14508/**
14509 * Set the value of the `volume` on the swf. `volume` indicates the current
14510 * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and
14511 * so on.
14512 *
14513 * @method Flash#setVolume
14514 * @param {number} percentAsDecimal
14515 *         The volume percent as a decimal. Value will be between 0-1.
14516 */
14517
14518/**
14519 * Set the value of the `muted` on the swf. `muted` indicates that the current
14520 * audio level should be silent.
14521 *
14522 * @method Flash#setMuted
14523 * @param {boolean} muted
14524 *         - True if the audio should be set to silent
14525 *         - False otherwise
14526 */
14527
14528/**
14529 * Set the value of `defaultMuted` on the swf. `defaultMuted` indicates
14530 * whether the media should start muted or not. Only changes the default state of the
14531 * media. `muted` and `defaultMuted` can have different values. `muted` indicates the
14532 * current state.
14533 *
14534 * @method Flash#setDefaultMuted
14535 * @param {boolean} defaultMuted
14536 *         - True indicates that the media should start muted.
14537 *         - False indicates that the media should not start muted.
14538 */
14539
14540/* Flash Support Testing -------------------------------------------------------- */
14541
14542/**
14543 * Check if the Flash tech is currently supported.
14544 *
14545 * @return {boolean}
14546 *          - True 
14546if the flash tech is supported.
14547 *          - False otherwise.
14548 */
14549Flash.isSupported = function () {
14550  return Flash.version()[0] >= 10;
14551  // return swfobject.hasFlashPlayerVersion('10');
14552};
14553
14554// Add Source Handler pattern functions to this tech
14555_tech2['default'].withSourceHandlers(Flash);
14556
14557/*
14558 * Native source handler for flash,  simply passes the source to the swf element.
14559 *
14560 * @property {Tech~SourceObject} source
14561 *           The source object
14562 *
14563 * @property {Flash} tech
14564 *           The instance of the Flash tech
14565 */
14566Flash.nativeSourceHandler = {};
14567
14568/**
14569 * Check if the Flash can play the given mime type.
14570 *
14571 * @param {string} type
14572 *        The mimetype to check
14573 *
14574 * @return {string}
14575 *         'maybe', or '' (empty string)
14576 */
14577Flash.nativeSourceHandler.canPlayType = function (type) {
14578  if (type in Flash.formats) {
14579    return 'maybe';
14580  }
14581
14582  return '';
14583};
14584
14585/**
14586 * Check if the media element can handle a source natively.
14587 *
14588 * @param {Tech~SourceObject} source
14589 *         The source object
14590 *
14591 * @param {Object} [options]
14592 *         Options to be passed to the tech.
14593 *
14594 * @return {string}
14595 *         'maybe', or '' (empty string).
14596 */
14597Flash.nativeSourceHandler.canHandleSource = function (source, options) {
14598  var type = void 0;
14599
14600  function guessMimeType(src) {
14601    var ext = Url.getFileExtension(src);
14602
14603    if (ext) {
14604      return 'video/' + ext;
14605    }
14606    return '';
14607  }
14608
14609  if (!source.type) {
14610    type = guessMimeType(source.src);
14611  } else {
14612    // Strip code information from the type because we don't get that specific
14613    type = source.type.replace(/;.*/, '').toLowerCase();
14614  }
14615
14616  return Flash.nativeSourceHandler.canPlayType(type);
14617};
14618
14619/**
14620 * Pass the source to the swf.
14621 *
14622 * @param {Tech~SourceObject} source
14623 *        The source object
14624 *
14625 * @param {Flash} tech
14626 *        The instance of the Flash tech
14627 *
14628 * @param {Object} [options]
14629 *        The options to pass to the source
14630 */
14631Flash.nativeSourceHandler.handleSource = function (source, tech, options) {
14632  tech.setSrc(source.src);
14633};
14634
14635/**
14636 * noop for native source handler dispose, as cleanup will happen automatically.
14637 */
14638Flash.nativeSourceHandler.dispose = function () {};
14639
14640// Register the native source handler
14641Flash.registerSourceHandler(Flash.nativeSourceHandler);
14642
14643/**
14644 * Flash supported mime types.
14645 *
14646 * @constant {Object}
14647 */
14648Flash.formats = {
14649  'video/flv': 'FLV',
14650  'video/x-flv': 'FLV',
14651  'video/mp4': 'MP4',
14652  'video/m4v': 'MP4'
14653};
14654
14655/**
14656 * Called when the the swf is "ready", and makes sure that the swf is really
14657 * ready using {@link Flash#checkReady}
14658 */
14659Flash.onReady = function (currSwf) {
14660  var el = Dom.getEl(currSwf);
14661  var tech = el && el.tech;
14662
14663  // if there is no el then the tech has been disposed
14664  // and the tech element was removed from the player div
14665  if (tech && tech.el()) {
14666    // check that the flash object is really ready
14667    Flash.checkReady(tech);
14668  }
14669};
14670
14671/**
14672 * The SWF isn't always ready when it says it is. Sometimes the API functions still
14673 * need to be added to the object. If it's not ready, we set a timeout to check again
14674 * shortly.
14675 *
14676 * @param {Flash} tech
14677 *        The instance of the flash tech to check.
14678 */
14679Flash.checkReady = function (tech) {
14680  // stop worrying if the tech has been disposed
14681  if (!tech.el()) {
14682    return;
14683  }
14684
14685  // check if API property exists
14686  if (tech.el().vjs_getProperty) {
14687    // tell tech it's ready
14688    tech.triggerReady();
14689  } else {
14690    // wait longer
14691    this.setTimeout(function () {
14692      Flash.checkReady(tech);
14693    }, 50);
14694  }
14695};
14696
14697/**
14698 * Trigger events from the swf on the Flash Tech.
14699 *
14700 * @param {number} swfID
14701 *        The id of the swf that had the event
14702 *
14703 * @param {string} eventName
14704 *        The name of the event to trigger
14705 */
14706Flash.onEvent = function (swfID, eventName) {
14707  var tech = Dom.getEl(swfID).tech;
14708  var args = Array.prototype.slice.call(arguments, 2);
14709
14710  // dispatch Flash events asynchronously for two reasons:
14711  // - Flash swallows any exceptions generated by javascript it
14712  //   invokes
14713  // - Flash is suspended until the javascript returns which may cause
14714  //   playback performance issues
14715  tech.setTimeout(function () {
14716    tech.trigger(eventName, args);
14717  }, 1);
14718};
14719
14720/**
14721 * Log errors from the swf on the Flash tech.
14722 *
14723 * @param {number} swfID
14724 *        The id of the swf that had an error.
14725 *
14726 * @param {string} The error string
14727 *        The error to set on the Flash Tech.
14728 *
14729 * @return {MediaError|undefined}
14730 *          - Returns a MediaError when err is 'srcnotfound'
14731 *          - Returns undefined otherwise.
14732 */
14733Flash.onError = function (swfID, err) {
14734  var tech = Dom.getEl(swfID).tech;
14735
14736  // trigger MEDIA_ERR_SRC_NOT_SUPPORTED
14737  if (err === 'srcnotfound') {
14738    return tech.error(4);
14739  }
14740
14741  // trigger a custom error
14742  tech.error('FLASH: ' + err);
14743};
14744
14745/**
14746 * Get the current version of Flash that is in use on the page.
14747 *
14748 * @return {Array}
14749 *          an array of versions that are available.
14750 */
14751Flash.version = function () {
14752  var version = '0,0,0';
14753
14754  // IE
14755  try {
14756    version = new _window2['default'].ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
14757
14758    // other browsers
14759  } catch (e) {
14760    try {
14761      if (navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin) {
14762        version = (navigator.plugins['Shockwave Flash 2.0'] || navigator.plugins['Shockwave Flash']).description.replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
14763      }
14764    } catch (err) {
14765      // satisfy linter
14766    }
14767  }
14768  return version.split(',');
14769};
14770
14771/**
14772 * Only use for non-iframe embeds.
14773 *
14774 * @param {Object} swf
14775 *        The videojs-swf object.
14776 *
14777 * @param {Object} flashVars
14778 *        Names and values to use as flash option variables.
14779 *
14780 * @param {Object} params
14781 *        Style parameters to set on the object.
14782 *
14783 * @param {Object} attributes
14784 *        Attributes to set on the element.
14785 *
14786 * @return {Element}
14787 *          The embeded Flash DOM element.
14788 */
14789Flash.embed = function (swf, flashVars, params, attributes) {
14790  var code = Flash.getEmbedCode(swf, flashVars, params, attributes);
14791
14792  // Get element by embedding code and retrieving created element
14793  var obj = Dom.createEl('div', { innerHTML: code }).childNodes[0];
14794
14795  return obj;
14796};
14797
14798/**
14799 * Only use for non-iframe embeds.
14800 *
14801 * @param {Object} swf
14802 *        The videojs-swf object.
14803 *
14804 * @param {Object} flashVars
14805 *        Names and values to use as flash option variables.
14806 *
14807 * @param {Object} params
14808 *        Style parameters to set on the object.
14809 *
14810 * @param {Object} attributes
14811 *        Attributes to set on the element.
14812 *
14813 * @return {Element}
14814 *          The embeded Flash DOM element.
14815 */
14816Flash.getEmbedCode = function (swf, flashVars, params, attributes) {
14817  var objTag = '<object type="application/x-shockwave-flash" ';
14818  var flashVarsString = '';
14819  var paramsString = '';
14820  var attrsString = '';
14821
14822  // Convert flash vars to string
14823  if (flashVars) {
14824    Object.getOwnPropertyNames(flashVars).forEach(function (key) {
14825      flashVarsString += key + '=' + flashVars[key] + '&amp;';
14826    });
14827  }
14828
14829  // Add swf, flashVars, and other default params
14830  params = (0, _obj.assign)({
14831    movie: swf,
14832    flashvars: flashVarsString,
14833    // Required to talk to swf
14834    allowScriptAccess: 'always',
14835    // All should be default, but having security issues.
14836    allowNetworking: 'all'
14837  }, params);
14838
14839  // Create param tags string
14840  Object.getOwnPropertyNames(params).forEach(function (key) {
14841    paramsString += '<param name="' + key + '" value="' + params[key] + '" />';
14842  });
14843
14844  attributes = (0, _obj.assign)({
14845    // Add swf to attributes (need both for IE and Others to work)
14846    data: swf,
14847
14848    // Default to 100% width/height
14849    width: '100%',
14850    height: '100%'
14851
14852  }, attributes);
14853
14854  // Create Attributes string
14855  Object.getOwnPropertyNames(attributes).forEach(function (key) {
14856    attrsString += key + '="' + attributes[key] + '" ';
14857  });
14858
14859  return '' + objTag + attrsString + '>' + paramsString + '</object>';
14860};
14861
14862// Run Flash through the RTMP decorator
14863(0, _flashRtmp2['default'])(Flash);
14864
14865_component2['default'].registerComponent('Flash', Flash);
14866_tech2['default'].registerTech('Flash', Flash);
14867exports['default'] = Flash;
14868
14869},{"5":5,"58":58,"62":62,"81":81,"88":88,"90":90,"92":92,"95":95}],60:[function(_dereq_,module,exports){
14870'use strict';
14871
14872exports.__esModule = true;
14873
14874var _templateObject = _taggedTemplateLiteralLoose(['Text Tracks are being loaded from another origin but the crossorigin attribute isn\'t used.\n            This may prevent text tracks from loading.'], ['Text Tracks are being loaded from another origin but the crossorigin attribute isn\'t used.\n            This may prevent text tracks from loading.']);
14875
14876var _tech = _dereq_(62);
14877
14878var _tech2 = _interopRequireDefault(_tech);
14879
14880var _component = _dereq_(5);
14881
14882var _component2 = _interopRequireDefault(_component);
14883
14884var _dom = _dereq_(81);
14885
14886var Dom = _interopRequireWildcard(_dom);
14887
14888var _url = _dereq_(92);
14889
14890var Url = _interopRequireWildcard(_url);
14891
14892var _fn = _dereq_(83);
14893
14894var Fn = _interopRequireWildcard(_fn);
14895
14896var _log = _dereq_(86);
14897
14898var _log2 = _interopRequireDefault(_log);
14899
14900var _tsml = _dereq_(98);
14901
14902var _tsml2 = _interopRequireDefault(_tsml);
14903
14904var _browser = _dereq_(78);
14905
14906var browser = _interopRequireWildcard(_browser);
14907
14908var _document = _dereq_(94);
14909
14910var _document2 = _interopRequireDefault(_document);
14911
14912var _window = _dereq_(95);
14913
14914var _window2 = _interopRequireDefault(_window);
14915
14916var _obj = _dereq_(88);
14917
14918var _mergeOptions = _dereq_(87);
14919
14920var _mergeOptions2 = _interopRequireDefault(_mergeOptions);
14921
14922var _toTitleCase = _dereq_(91);
14923
14924var _toTitleCase2 = _interopRequireDefault(_toTitleCase);
14925
14926function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
14927
14928function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
14929
14930function _taggedTemplateLiteralLoose(strings, raw) { strings.raw = raw; return strings; }
14931
14932function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
14933
14934function _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; }
14935
14936function _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, { c
14936onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
14937                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file html5.js
14938                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
14939
14940
14941/**
14942 * HTML5 Media Controller - Wrapper for HTML5 Media API
14943 *
14944 * @mixes Tech~SouceHandlerAdditions
14945 * @extends Tech
14946 */
14947var Html5 = function (_Tech) {
14948  _inherits(Html5, _Tech);
14949
14950  /**
14951   * Create an instance of this Tech.
14952   *
14953   * @param {Object} [options]
14954   *        The key/value store of player options.
14955   *
14956   * @param {Component~ReadyCallback} ready
14957   *        Callback function to call when the `HTML5` Tech is ready.
14958   */
14959  function Html5(options, ready) {
14960    _classCallCheck(this, Html5);
14961
14962    var _this = _possibleConstructorReturn(this, _Tech.call(this, options, ready));
14963
14964    var source = options.source;
14965    var crossoriginTracks = false;
14966
14967    // Set the source if one is provided
14968    // 1) Check if the source is new (if not, we want to keep the original so playback isn't interrupted)
14969    // 2) Check to see if the network state of the tag was failed at init, and if so, reset the source
14970    // anyway so the error gets fired.
14971    if (source && (_this.el_.currentSrc !== source.src || options.tag && options.tag.
14971initNetworkState_ === 3)) {
14972      _this.setSource(source);
14973    } else {
14974      _this.handleLateInit_(_this.el_);
14975    }
14976
14977    if (_this.el_.hasChildNodes()) {
14978
14979      var nodes = _this.el_.childNodes;
14980      var nodesLength = nodes.length;
14981      var removeNodes = [];
14982
14983      while (nodesLength--) {
14984        var node = nodes[nodesLength];
14985        var nodeName = node.nodeName.toLowerCase();
14986
14987        if (nodeName === 'track') {
14988          if (!_this.featuresNativeTextTracks) {
14989            // Empty video tag tracks so the built-in player doesn't use them also.
14990            // This may not be fast enough to stop HTML5 browsers from reading the tags
14991            // so we'll need to turn off any default tracks if we're manually doing
14992            // captions and subtitles. videoElement.textTracks
14993            removeNodes.push(node);
14994          } else {
14995            // store HTMLTrackElement and TextTrack to remote list
14996            _this.remoteTextTrackEls().addTrackElement_(node);
14997            _this.remoteTextTracks().addTrack_(node.track);
14998            if (!crossoriginTracks && !_this.el_.hasAttribute('crossorigin') && Url.isCrossOrigin(node.src)) {
14999              crossoriginTracks = true;
15000            }
15001          }
15002        }
15003      }
15004
15005      for (var i = 0; i < removeNodes.length; i++) {
15006        _this.el_.removeChild(removeNodes[i]);
15007      }
15008    }
15009
15010    // TODO: add text tracks into this list
15011    var trackTypes = ['audio', 'video'];
15012
15013    // ProxyNative Video/Audio Track
15014    trackTypes.forEach(function (type) {
15015      var elTracks = _this.el()[type + 'Tracks'];
15016      var techTracks = _this[type + 'Tracks']();
15017      var capitalType = (0, _toTitleCase2['default'])(type);
15018
15019      if (!_this['featuresNative' + capitalType + 'Tracks'] || !elTracks || !elTracks.addEventListener) {
15020        return;
15021      }
15022
15023      _this['handle' + capitalType + 'TrackChange_'] = function (e) {
15024        techTracks.trigger({
15025          type: 'change',
15026          target: techTracks,
15027          currentTarget: techTracks,
15028          srcElement: techTracks
15029        });
15030      };
15031
15032      _this['handle' + capitalType + 'TrackAdd_'] = function (e) {
15033        return techTracks.addTrack(e.track);
15034      };
15035      _this['handle' + capitalType + 'TrackRemove_'] = function (e) {
15036        return techTracks.removeTrack(e.track);
15037      };
15038
15039      elTracks.addEventListener('change', _this['handle' + capitalType + 'TrackChange_']);
15040      elTracks.addEventListener('addtrack', _this['handle' + capitalType + 'TrackAdd_']);
15041      elTracks.addEventListener('removetrack', _this['handle' + capitalType + 'TrackRemove_']);
15042      _this['removeOld' + capitalType + 'Tracks_'] = function (e) {
15043        return _this.removeOldTracks_(techTracks, elTracks);
15044      };
15045
15046      // Remove (native) tracks that are not used anymore
15047      _this.on('loadstart', _this['removeOld' + capitalType + 'Tracks_']);
15048    });
15049
15050    if (_this.featuresNativeTextTracks) {
15051      if (crossoriginTracks) {
15052        _log2['default'].warn((0, _tsml2['default'])(_templateObject));
15053      }
15054
15055      _this.handleTextTrackChange_ = Fn.bind(_this, _this.handleTextTrackChange);
15056      _this.handleTextTrackAdd_ = Fn.bind(_this, _this.handleTextTrackAdd);
15057      _this.handleTextTrackRemove_ = Fn.bind(_this, _this.handleTextTrackRemove);
15058      _this.proxyNativeTextTracks_();
15059    }
15060
15061    // Determine if native controls should be used
15062    // Our goal should be to get the custom controls on mobile solid everywhere
15063    // so we can remove this all together. Right now this will block custom
15064    // controls on touch enabled laptops like the Chrome Pixel
15065    if ((browser.TOUCH_ENABLED || browser.IS_IPHONE || browser.IS_NATIVE_ANDROID) && options.nativeControlsForTouch === true) {
15066      _this.setControls(true);
15067    }
15068
15069    // on iOS, we want to proxy `webkitbeginfullscreen` and `webkitendfullscreen`
15070    // into a `fullscreenchange` event
15071    _this.proxyWebkitFullscreen_();
15072
15073    _this.triggerReady();
15074    return _this;
15075  }
15076
15077  /**
15078   * Dispose of `HTML5` media element and remove all tracks.
15079   */
15080
15081
15082  Html5.prototype.dispose = function dispose() {
15083    var _this2 = this;
15084
15085    // Un-ProxyNativeTracks
15086    ['audio', 'video', 'text'].forEach(function (type) {
15087      var capitalType = (0, _toTitleCase2['default'])(type);
15088      var tl = _this2.el_[type + 'Tracks'];
15089
15090      if (tl && tl.removeEventListener) {
15091        tl.removeEventListener('change', _this2['handle' + capitalType + 'TrackChange_']);
15092        tl.removeEventListener('addtrack', _this2['handle' + capitalType + 'TrackAdd_']);
15093        tl.removeEventListener('removetrack', _this2['handle' + capitalType + 'TrackRemove_']);
15094      }
15095
15096      // Stop removing old text tracks
15097      if (tl) {
15098        _this2.off('loadstart', _this2['removeOld' + capitalType + 'Tracks_']);
15099      }
15100    });
15101
15102    Html5.disposeMediaElement(this.el_);
15103    // tech will handle clearing of the emulated track list
15104    _Tech.prototype.dispose.call(this);
15105  };
15106
15107  /**
15108   * Create the `Html5` Tech's DOM element.
15109   *
15110   * @return {Element}
15111   *         The element that gets created.
15112   */
15113
15114
15115  Html5.prototype.createEl = function createEl() {
15116    var el = this.options_.tag;
15117
15118    // Check if this browser supports moving the element into the box.
15119    // On the iPhone video will break if you move the element,
15120    // So we have to create a brand new element.
15121    // If we ingested the player div, we do not need to move the media element.
15122    if (!el || !(this.options_.playerElIngest || this.movingMediaElementInDOM)) {
15123
15124      // If the original tag is still there, clone and remove it.
15125      if (el) {
15126        var clone = el.cloneNode(true);
15127
15128        if (el.parentNode) {
15129          el.parentNode.insertBefore(clone, el);
15130        }
15131        Html5.disposeMediaElement(el);
15132        el = clone;
15133      } else {
15134        el = _document2['default'].createElement('video');
15135
15136        // determine if native controls should be used
15137        var tagAttributes = this.options_.tag && Dom.getElAttributes(this.options_.tag);
15138        var attributes = (0, _mergeOptions2['default'])({}, tagAttributes);
15139
15140        if (!browser.TOUCH_ENABLED || this.options_.nativeControlsForTouch !== true) {
15141          delete attributes.controls;
15142        }
15143
15144        Dom.setElAttributes(el, (0, _obj.assign)(attributes, {
15145          id: this.options_.techId,
15146          'class': 'vjs-tech'
15147        }));
15148      }
15149
15150      el.playerId = this.options_.playerId;
15151    }
15152
15153    // Update specific tag settings, in case they were overridden
15154    var settingsAttrs = ['autoplay', 'preload', 'loop', 'muted', 'playsinline'];
15155
15156    for (var i = settingsAttrs.length - 1; i >= 0; i--) {
15157      var attr = settingsAttrs[i];
15158      var overwriteAttrs = {};
15159
15160      if (typeof this.options_[attr] !== 'undefined') {
15161        overwriteAttrs[attr] = this.options_[attr];
15162      }
15163      Dom.setElAttributes(el, overwriteAttrs);
15164    }
15165
15166    return el;
15167  };
15168
15169  /**
15170   * This will be triggered if the loadstart event has already fired, before videojs was
15171   * ready. Two known examples of when this can happen are:
15172   * 1. If we're loading the playback object after it has started loading
15173   * 2. The media is already playing the (often with autoplay on) then
15174   *
15175   * This function will fire another loadstart so that videojs can catchup.
15176   *
15177   * @fires Tech#loadstart
15178   *
15179   * @return {undefined}
15180   *         returns nothing.
15181   */
15182
15183
15184  Html5.prototype.handleLateInit_ = function handleLateInit_(el) {
15185    if (el.networkState === 0 || el.networkState === 3) {
15186      // The video element hasn't started loading the source yet
15187      // or didn't find a source
15188      return;
15189    }
15190
15191    if (el.readyState === 0) {
15192      // NetworkState is set synchronously BUT loadstart is fired at the
15193      // end of the current stack, usually before setInterval(fn, 0).
15194      // So at this point we know loadstart may have already fired or is
15195      // about to fire, and either way the player hasn't seen it yet.
15196      // We don't want to fire loadstart prematurely here and cause a
15197      // double loadstart so we'll wait and see if it happens between now
15198      // and the next loop, and fire it if not.
15199      // HOWEVER, we also want to make sure it fires before loadedmetadata
15200      // which could also happen between now and the next loop, so we'll
15201      // watch for that also.
15202      var loadstartFired = false;
vendor: 4,620 bytes, lines 15203-15365
15203      var setLoadstartFired = function setLoadstartFired() {
15204        loadstartFired = true;
15205      };
15206
15207      this.on('loadstart', setLoadstartFired);
15208
15209      var triggerLoadstart = function triggerLoadstart() {
15210        // We did miss the original loadstart. Make sure the player
15211        // sees loadstart before loadedmetadata
15212        if (!loadstartFired) {
15213          this.trigger('loadstart');
15214        }
15215      };
15216
15217      this.on('loadedmetadata', triggerLoadstart);
15218
15219      this.ready(function () {
15220        this.off('loadstart', setLoadstartFired);
15221        this.off('loadedmetadata', triggerLoadstart);
15222
15223        if (!loadstartFired) {
15224          // We did miss the original native loadstart. Fire it now.
15225          this.trigger('loadstart');
15226        }
15227      });
15228
15229      return;
15230    }
15231
15232    // From here on we know that loadstart already fired and we missed it.
15233    // The other readyState events aren't as much of a problem if we double
15234    // them, so not going to go to as much trouble as loadstart to prevent
15235    // that unless we find reason to.
15236    var eventsToTrigger = ['loadstart'];
15237
15238    // loadedmetadata: newly equal to HAVE_METADATA (1) or greater
15239    eventsToTrigger.push('loadedmetadata');
15240
15241    // loadeddata: newly increased to HAVE_CURRENT_DATA (2) or greater
15242    if (el.readyState >= 2) {
15243      eventsToTrigger.push('loadeddata');
15244    }
15245
15246    // canplay: newly increased to HAVE_FUTURE_DATA (3) or greater
15247    if (el.readyState >= 3) {
15248      eventsToTrigger.push('canplay');
15249    }
15250
15251    // canplaythrough: newly equal to HAVE_ENOUGH_DATA (4)
15252    if (el.readyState >= 4) {
15253      eventsToTrigger.push('canplaythrough');
15254    }
15255
15256    // We still need to give the player time to add event listeners
15257    this.ready(function () {
15258      eventsToTrigger.forEach(function (type) {
15259        this.trigger(type);
15260      }, this);
15261    });
15262  };
15263
15264  /**
15265   * Add event listeners to native text track events. This adds the native text tracks
15266   * to our emulated {@link TextTrackList}.
15267   */
15268
15269
15270  Html5.prototype.proxyNativeTextTracks_ = function proxyNativeTextTracks_() {
15271    var tt = this.el().textTracks;
15272
15273    if (tt) {
15274      // Add tracks - if player is initialised after DOM loaded, textTracks
15275      // will not trigger addtrack
15276      for (var i = 0; i < tt.length; i++) {
15277        this.textTracks().addTrack_(tt[i]);
15278      }
15279
15280      if (tt.addEventListener) {
15281        tt.addEventListener('change', this.handleTextTrackChange_);
15282        tt.addEventListener('addtrack', this.handleTextTrackAdd_);
15283        tt.addEventListener('removetrack', this.handleTextTrackRemove_);
15284      }
15285
15286      // Remove (native) texttracks that are not used anymore
15287      this.on('loadstart', this.removeOldTextTracks_);
15288    }
15289  };
15290
15291  /**
15292   * Handle any {@link TextTrackList} `change` event.
15293   *
15294   * @param {EventTarget~Event} e
15295   *        The `change` event that caused this to run.
15296   *
15297   * @listens TextTrackList#change
15298   */
15299
15300
15301  Html5.prototype.handleTextTrackChange = function handleTextTrackChange(e) {
15302    var tt = this.textTracks();
15303
15304    this.textTracks().trigger({
15305      type: 'change',
15306      target: tt,
15307      currentTarget: tt,
15308      srcElement: tt
15309    });
15310  };
15311
15312  /**
15313   * Handle any {@link TextTrackList} `addtrack` event.
15314   *
15315   * @param {EventTarget~Event} e
15316   *        The `addtrack` event that caused this to run.
15317   *
15318   * @listens TextTrackList#addtrack
15319   */
15320
15321
15322  Html5.prototype.handleTextTrackAdd = function handleTextTrackAdd(e) {
15323    this.textTracks().addTrack_(e.track);
15324  };
15325
15326  /**
15327   * Handle any {@link TextTrackList} `removetrack` event.
15328   *
15329   * @param {EventTarget~Event} e
15330   *        The `removetrack` event that caused this to run.
15331   *
15332   * @listens TextTrackList#removetrack
15333   */
15334
15335
15336  Html5.prototype.handleTextTrackRemove = function handleTextTrackRemove(e) {
15337    this.textTracks().removeTrack_(e.track);
15338  };
15339
15340  /**
15341   * This function removes any {@link AudioTrack}s, {@link VideoTrack}s, or
15342   * {@link TextTrack}s that are not in the media elements TrackList.
15343   *
15344   * @param {TrackList} techTracks
15345   *        HTML5 Tech's TrackList to search through
15346   *
15347   * @param {TrackList} elTracks
15348   *        HTML5 media elements TrackList to search trough.
15349   *
15350   * @private
15351   */
15352
15353
15354  Html5.prototype.removeOldTracks_ = function removeOldTracks_(techTracks, elTracks) {
15355    // This will loop over the techTracks and check if they are still used by the HTML5 media element
15356    // If not, they will be removed from the emulated list
15357    var removeTracks = [];
15358
15359    if (!elTracks) {
15360      return;
15361    }
15362
15363    for (var i = 0; i < techTracks.length; i++) {
15364      var techTrack = techTracks[i];
15365      var found = false;
15366
15367      for (var j = 0; j < elTracks.length; j++) {
15368        if (elTracks[j] === techTrack) {
15369          found = true;
15370          break;
15371        }
15372      }
15373
15374      if (!found) {
15375        removeTracks.push(techTrack);
15376      }
15377    }
15378
15379    for (var _i = 0; _i < removeTracks.length; _i++) {
15380      var track = removeTracks[_i];
15381
15382      techTracks.removeTrack_(track);
15383    }
15384  };
15385
15386  /**
15387   * Remove {@link TextTrack}s that dont exist in the native track list from our
15388   * emulated {@link TextTrackList}.
15389   *
15390   * @listens Tech#loadstart
15391   */
15392
15393
15394  Html5.prototype.removeOldTextTracks_ = function removeOldTextTracks_(e) {
15395    var techTracks = this.textTracks();
15396    var elTracks = this.el().textTracks;
15397
15398    this.removeOldTracks_(techTracks, elTracks);
15399  };
15400
15401  /**
15402   * Called by {@link Player#play} to play using the `Html5` `Tech`.
15403   */
15404
15405
15406  Html5.prototype.play = function play() {
15407    var playPromise = this.el_.play();
15408
15409    // Catch/silence error when a pause interrupts a play request
15410    // on browsers which return a promise
15411    if (playPromise !== undefined && typeof playPromise.then === 'function') {
15412      playPromise.then(null, function (e) {});
15413    }
15414  };
15415
15416  /**
15417   * Set current time for the `HTML5` tech.
15418   *
15419   * @param {number} seconds
15420   *        Set the current time of the media to this.
15421   */
15422
15423
15424  Html5.prototype.setCurrentTime = function setCurrentTime(seconds) {
15425    try {
15426      this.el_.currentTime = seconds;
15427    } catch (e) {
15428      (0, _log2['default'])(e, 'Video is not ready. (Video.js)');
15429      // this.warning(VideoJS.warnings.videoNotReady);
15430    }
15431  };
15432
15433  /**
15434   * Get the current duration of the HTML5 media element.
15435   *
15436   * @return {number}
15437   *         The duration of the media or 0 if there is no duration.
15438   */
15439
15440
15441  Html5.prototype.duration = function duration() {
15442    var _this3 = this;
15443
15444    // Android Chrome will report duration as Infinity for VOD HLS until after
15445    // playback has started, which triggers the live display erroneously.
15446    // Return NaN if playback has not started and trigger a durationupdate once
15447    // the duration can be reliably known.
15448    if (this.el_.duration === Infinity && browser.IS_ANDROID && browser.IS_CHROME) {
15449      if (this.el_.currentTime === 0) {
15450        // Wait for the first `timeupdate` with currentTime > 0 - there may be
15451        // several with 0
15452        var checkProgress = function checkProgress() {
15453          if (_this3.el_.currentTime > 0) {
15454            // Trigger durationchange for genuinely live video
15455            if (_this3.el_.duration === Infinity) {
15456              _this3.trigger('durationchange');
15457            }
15458            _this3.off('timeupdate', checkProgress);
15459          }
15460        };
15461
15462        this.on('timeupdate', checkProgress);
15463        return NaN;
15464      }
15465    }
15466    return this.el_.duration || NaN;
15467  };
15468
15469  /**
15470   * Get the current width of the HTML5 media element.
15471   *
15472   * @return {number}
15473   *         The width of the HTML5 media element.
15474   */
15475
15476
15477  Html5.prototype.width = function width() {
15478    return this.el_.offsetWidth;
15479  };
15480
15481  /**
15482   * Get the current height of the HTML5 media element.
15483   *
15484   * @return {number}
15485   *         The heigth of the HTML5 media element.
15486   */
15487
15488
15489  Html5.prototype.height = function height() {
15490    return this.el_.offsetHeight;
15491  };
15492
15493  /**
15494   * Proxy iOS `webkitbeginfullscreen` and `webkitendfullscreen` into
15495   * `fullscreenchange` event.
15496   *
15497   * @private
15498   * @fires fullscreenchange
15499   * @listens webkitendfullscreen
15500   * @listens webkitbeginfullscreen
15501   * @listens webkitbeginfullscreen
15502   */
15503
15504
15505  Html5.prototype.proxyWebkitFullscreen_ = function proxyWebkitFullscreen_() {
15506    var _this4 = this;
15507
15508    if (!('webkitDisplayingFullscreen' in this.el_)) {
15509      return;
15510    }
15511
15512    var endFn = function endFn() {
15513      this.trigger('fullscreenchange', { isFullscreen: false });
15514    };
15515
15516    var beginFn = function beginFn() {
15517      if ('webkitPresentationMode' in this.el_ && this.el_.webkitPresentationMode !== 'picture-in-picture') {
15518        this.one('webkitendfullscreen', endFn);
15519
15520        this.trigger('fullscreenchange', { isFullscreen: true });
15521      }
15522    };
15523
15524    this.on('webkitbeginfullscreen', beginFn);
15525    this.on('dispose', function () {
15526      _this4.off('webkitbeginfullscreen', beginFn);
15527      _this4.off('webkitendfullscreen', endFn);
15528    });
15529  };
15530
15531  /**
15532   * Check if fullscreen is supported on the current playback device.
15533   *
15534   * @return {boolean}
15535   *         - True if fullscreen is supported.
15536   *         - False if fullscreen is not supported.
15537   */
15538
15539
15540  Html5.prototype.supportsFullScreen = function supportsFullScreen() {
15541    if (typeof this.el_.webkitEnterFullScreen === 'function') {
15542      var userAgent = _window2['default'].navigator && _window2['default'].navigator.userAgent || '';
15543
15544      // Seems to be broken in Chromium/Chrome && Safari in Leopard
15545      if (/Android/.test(userAgent) || !/Chrome|Mac OS X 10.5/.test(userAgent)) {
15546        return true;
15547      }
15548    }
15549    return false;
15550  };
15551
15552  /**
15553   * Request that the `HTML5` Tech enter fullscreen.
15554   */
15555
15556
15557  Html5.prototype.enterFullScreen = function enterFullScreen() {
15558    var video = this.el_;
15559
15560    if (video.paused && video.networkState <= video.HAVE_METADATA) {
15561      // attempt to prime the video element for programmatic access
15562      // this isn't necessary on the desktop but shouldn't hurt
15563      this.el_.play();
15564
15565      // playing and pausing synchronously during the transition to fullscreen
15566      // can get iOS ~6.1 devices into a play/pause loop
15567      this.setTimeout(function () {
15568        video.pause();
15569        video.webkitEnterFullScreen();
15570      }, 0);
15571    } else {
15572      video.webkitEnterFullScreen();
15573    }
15574  };
15575
15576  /**
15577   * Request that the `HTML5` Tech exit fullscreen.
15578   */
15579
15580
15581  Html5.prototype.exitFullScreen = function exitFullScreen() {
15582    this.el_.webkitExitFullScreen();
15583  };
15584
15585  /**
15586   * A getter/setter for the `Html5` Tech's source object.
15587   * > Note: Please use {@link Html5#setSource}
15588   *
15589   * @param {Tech~SourceObject} [src]
15590   *        The source object you want to set on the `HTML5` techs element.
15591   *
15592   * @return {Tech~SourceObject|undefined}
15593   *         - The current source object when a source is not passed in.
15594   *         - undefined when setting
15595   *
15596   * @deprecated Since version 5.
15597   */
15598
15599
15600  Html5.prototype.src = function src(_src) {
15601    if (_src === undefined) {
15602      return this.el_.src;
15603    }
15604
15605    // Setting src through `src` instead of `setSrc` will be deprecated
15606    this.setSrc(_src);
15607  };
15608
15609  /**
15610   * Reset the tech by removing all sources and then calling
15611   * {@link Html5.resetMediaElement}.
15612   */
15613
15614
15615  Html5.prototype.reset = function reset() {
15616    Html5.resetMediaElement(this.el_);
15617  };
15618
15619  /**
15620   * Get the current source on the `HTML5` Tech. Falls back to returning the source from
15621   * the HTML5 media element.
15622   *
15623   * @return {Tech~SourceObject}
15624   *         The current source object from the HTML5 tech. With a fallback to the
15625   *         elements source.
15626   */
15627
15628
15629  Html5.prototype.currentSrc = function currentSrc() {
15630    if (this.currentSource_) {
15631      return this.currentSource_.src;
15632    }
15633    return this.el_.currentSrc;
15634  };
15635
15636  /**
15637   * Set controls attribute for the HTML5 media Element.
15638   *
15639   * @param {string} val
15640   *        Value to set the controls attribute to
15641   */
15642
15643
15644  Html5.prototype.setControls = function setControls(val) {
15645    this.el_.controls = !!val;
15646  };
15647
15648  /**
15649   * Create and returns a remote {@link TextTrack} object.
15650   *
15651   * @param {string} kind
15652   *        `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)
15653   *
15654   * @param {string} [label]
15655   *        Label to identify the text track
15656   *
15657   * @param {string} [language]
15658   *        Two letter language abbreviation
15659   *
15660   * @return {TextTrack}
15661   *         The TextTrack that gets created.
15662   */
15663
15664
15665  Html5.prototype.addTextTrack = function addTextTrack(kind, label, language) {
15666    if (!this.featuresNativeTextTracks) {
15667      return _Tech.prototype.addTextTrack.call(this, kind, label, language);
15668    }
15669
15670    return this.el_.addTextTrack(kind, label, language);
15671  };
15672
15673  /**
15674   * Creates either native TextTrack or an emulated TextTrack depending
15675   * on the value of `featuresNativeTextTracks`
15676   *
15677   * @param {Object} options
15678   *        The object should contain the options to intialize the TextTrack with.
15679   *
15680   * @param {string} [options.kind]
15681   *        `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata).
15682   *
15683   * @param {string} [options.label].
15684   *        Label to identify the text track
15685   *
15686   * @param {string} [options.language]
15687   *        Two letter language abbreviation.
15688   *
15689   * @param {boolean} [options.default]
15690   *        Default this track to on.
15691   *
15692   * @param {string} [options.id]
15693   *        The internal id to assign this track.
15694   *
15695   * @param {string} [options.src]
15696   *        A source url for the track.
15697   *
15698   * @return {HTMLTrackElement}
15699   *         The track element that gets created.
15700   */
15701
15702
15703  Html5.prototype.createRemoteTextTrack = function createRemoteTextTrack(options) {
15704    if (!this.featuresNativeTextTracks) {
15705      return _Tech.prototype.createRemoteTextTrack.call(this, options);
15706    }
15707    var htmlTrackElement = _document2['default'].createElement('track');
15708
15709    if (options.kind) {
15710      htmlTrackElement.kind = options.kind;
15711    }
15712    if (options.label) {
15713      htmlTrackElement.label = options.label;
15714    }
15715    if (options.language || options.srclang) {
15716      htmlTrackElement.srclang = options.language || options.srclang;
15717    }
15718    if (options['default']) {
15719      htmlTrackElement['default'] = options['default'];
15720    }
15721    if (options.id) {
15722      htmlTrackElement.id = options.id;
15723    }
15724    if (options.src) {
15725      htmlTrackElement.src = options.src;
15726    }
15727
15728    return htmlTrackElement;
15729  };
15730
15731  /**
15732   * Creates a remote text track object and returns an html track element.
15733   *
15734   * @param {Object} options The object should contain values for
15735   * kind, language, label, and src (location of the WebVTT file)
15736   * @param {Boolean} [manualCleanup=true] if set to false, the TextTrack will be
15737   * automatically removed from the video element whenever the source changes
15738   * @return {HTMLTrackElement} An Html Track Element.
15739   * This can be an emulated {@link HTMLTrackElement} or a native one.
15740   * @deprecated The default value of the "manualCleanup" parameter will default
15741   * to "false" in upcoming versions of Video.js
15742   */
15743
15744
15745  Html5.prototype.addRemoteTextTrack = function addRemoteTextTrack(options, manualCleanup) {
15746    var htmlTrackElement = _Tech.prototype.addRemoteTextTrack.call(this, options, manualCleanup);
15747
15748    if (this.featuresNativeTextTracks) {
15749      this.el().appendChild(htmlTrackElement);
15750    }
15751
15752    return htmlTrackElement;
15753  };
15754
15755  /**
15756   * Remove remote `TextTrack` from `TextTrackList` object
15757   *
15758   * @param {TextTrack} track
15759   *        `TextTrack` object to remove
15760   */
15761
15762
15763  Html5.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) {
15764    _Tech.prototype.removeRemoteTextTrack.call(this, track);
15765
15766    if (this.featuresNativeTextTracks) {
15767      var tracks = this.$$('track');
15768
15769      var i = tracks.length;
15770
15771      while (i--) {
15772        if (track === tracks[i] || track === tracks[i].track) {
15773          this.el().removeChild(tracks[i]);
15774        }
15775      }
15776    }
15777  };
15778
15779  /**
15780   * Get the value of `playsinline` from the media element. `playsinline` indicates
15781   * to the browser that non-fullscreen playback is preferred when fullscreen
15782   * playback is the native default, such as in iOS Safari.
15783   *
15784   * @method Html5#playsinline
15785   * @return {boolean}
15786   *         - The value of `playsinline` from the media element.
15787   *         - True indicates that the media should play inline.
15788   *         - False indicates that the media should not play inline.
15789   *
15790   * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}
15791   */
15792
15793
15794  Html5.prototype.playsinline = function playsinline() {
15795    return this.el_.hasAttribute('playsinline');
15796  };
15797
15798  /**
15799   * Set the value of `playsinline` from the media element. `playsinline` indicates
15800   * to the browser that non-fullscreen playback is preferred when fullscreen
15801   * playback is the native default, such as in iOS Safari.
15802   *
15803   * @method Html5#setPlaysinline
15804   * @param {boolean} playsinline
15805   *         - True indicates that the media should play inline.
15806   *         - False indicates that the media should not play inline.
15807   *
15808   * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}
15809   */
15810
15811
15812  Html5.prototype.setPlaysinline = function setPlaysinline(value) {
15813    if (value) {
15814      this.el_.setAttribute('playsinline', 'playsinline');
15815    } else {
15816      this.el_.removeAttribute('playsinline');
15817    }
15818  };
15819
15820  /**
15821   * Gets available media playback quality metrics as specified by the W3C's Media
15822   * Playback Quality API.
15823   *
15824   * @see [Spec]{@link https://wicg.github.io/media-playback-quality}
15825   *
15826   * @return {Object}
15827   *         An object with supported media playback quality metrics
15828   */
15829
15830
15831  Html5.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() {
15832    if (typeof this.el().getVideoPlaybackQuality === 'function') {
15833      return this.el().getVideoPlaybackQuality();
15834    }
15835
15836    var videoPlaybackQuality = {};
15837
15838    if (typeof this.el().webkitDroppedFrameCount !== 'undefined' && typeof this.el().webkitDecodedFrameCount !== 'undefined') {
15839      videoPlaybackQuality.droppedVideoFrames = this.el().webkitDroppedFrameCount;
15840      videoPlaybackQuality.totalVideoFrames = this.el().webkitDecodedFrameCount;
15841    }
15842
15843    if (_window2['default'].performance && typeof _window2['default'].performance.now === 'function') {
15844      videoPlaybackQuality.creationTime = _window2['default'].performance.now();
15845    } else if (_window2['default'].performance && _window2['default'].performance.timing && typeof _window2['default'].performance.timing.navigationStart === 'number') {
15846      videoPlaybackQuality.creationTime = _window2['default'].Date.now() - _window2['default'].performance.timing.navigationStart;
15847    }
15848
15849    return videoPlaybackQuality;
15850  };
15851
15852  return Html5;
15853}(_tech2['default']);
15854
15855/* HTML5 Support Testing ---------------------------------------------------- */
15856
15857if (Dom.isReal()) {
15858
15859  /**
15860   * Element for testing browser HTML5 media capabilities
15861   *
15862   * @type {Element}
15863   * @constant
15864   * @private
15865   */
15866  Html5.TEST_VID = _document2['default'].createElement('video');
15867  var track = _document2['default'].createElement('track');
15868
15869  track.kind = 'captions';
15870  track.srclang = 'en';
15871  track.label = 'English';
15872  Html5.TEST_VID.appendChild(track);
15873}
15874
15875/**
15876 * Check if HTML5 media is supported by this browser/device.
15877 *
15878 * @return {boolean}
15879 *         - True if HTML5 media is supported.
15880 *         - False if HTML5 media is not supported.
15881 */
15882Html5.isSupported = function () {
15883  // IE9 with no Media Player is a LIAR! (#984)
15884  try {
15885    Html5.TEST_VID.volume = 0.5;
15886  } catch (e) {
15887    return false;
15888  }
15889
15890  return !!(Html5.TEST_VID && Html5.TEST_VID.canPlayType);
15891};
15892
15893/**
15894 * Check if the volume can be changed in this browser/device.
15895 * Volume cannot be changed in a lot of mobile devices.
15896 * Specifically, it can't be changed from 1 on iOS.
15897 *
15898 * @return {boolean}
15899 *         - True if volume can be controlled
15900 *         - False otherwise
15901 */
15902Html5.canControlVolume = function () {
15903  // IE will error if Windows Media Player not installed #3315
15904  try {
15905    var volume = Html5.TEST_VID.volume;
15906
15907    Html5.TEST_VID.volume = volume / 2 + 0.1;
15908    return volume !== Html5.TEST_VID.volume;
15909  } catch (e) {
15910    return false;
15911  }
15912};
15913
15914/**
15915 * Check if the playback rate can be changed in this browser/device.
15916 *
15917 * @return {boolean}
15918 *         - True if playback rate can be controlled
15919 *         - False otherwise
15920 */
15921Html5.canControlPlaybackRate = function () {
15922  // Playback rate API is implemented in Android Chrome, but doesn't do anything
15923  // https://github.com/videojs/video.js/issues/3180
15924  if (browser.IS_ANDROID && browser.IS_CHROME && browser.CHROME_VERSION < 58) {
15925    return false;
15926  }
15927  // IE will error if Windows Media Player not installed #3315
15928  try {
15929    var playbackRate = Html5.TEST_VID.playbackRate;
15930
15931    Html5.TEST_VID.playbackRate = playbackRate / 2 + 0.1;
15932    return playbackRate !== Html5.TEST_VID.playbackRate;
15933  } catch (e) {
15934    return false;
15935  }
15936};
15937
15938/**
15939 * Check to see if native `TextTrack`s are supported by this browser/device.
15940 *
15941 * @return {boolean}
15942 *         - True if native `TextTrack`s are supported.
15943 *         - False otherwise
15944 */
15945Html5.supportsNativeTextTracks = function () {
15946  return browser.IS_ANY_SAFARI;
15947};
15948
15949/**
15950 * Check to see if native `VideoTrack`s are supported by this browser/device
15951 *
15952 * @return {boolean}
15953 *        - True if native `VideoTrack`s are supported.
15954 *        - False otherwise
15955 */
15956Html5.supportsNativeVideoTracks = function () {
15957  return !!(Html5.TEST_VID && Html5.TEST_VID.videoTracks);
15958};
15959
15960/**
15961 * Check to see if native `AudioTrack`s are supported by this browser/device
15962 *
15963 * @return {boolean}
15964 *        - True if native `AudioTrack`s are supported.
15965 *        - False otherwise
15966 */
15967Html5.supportsNativeAudioTracks = function () {
15968  return !!(Html5.TEST_VID && Html5.TEST_VID.audioTracks);
15969};
15970
15971/**
15972 * An array of events available on the Html5 tech.
15973 *
15974 * @private
15975 * @type {Array}
15976 */
15977Html5.Events = ['loadstart', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'waiting', 'seeking', 'seeked', 'ended', 'durationchange', 'timeupdate', 'progress', 'play', 'pause', 'ratechange', 'volumechange'];
15978
15979/**
15980 * Boolean indicating whether the `Tech` supports volume control.
15981 *
15982 * @type {boolean}
15983 * @default {@link Html5.canControlVolume}
15984 */
15985Html5.prototype.featuresVolumeControl = Html5.canControlVolume();
15986
15987/**
15988 * Boolean indicating whether the `Tech` supports changing the speed at which the media
15989 * plays. Examples:
15990 *   - Set player to play 2x (twice) as fast
15991 *   - Set player to play 0.5x (half) as fast
15992 *
15993 * @type {boolean}
15994 * @default {@link Html5.canControlPlaybackRate}
15995 */
15996Html5.prototype.featuresPlaybackRate = Html5.canControlPlaybackRate();
15997
15998/**
15999 * Boolean indicating whether the `HTML5` tech currently supports the media element
16000 * moving in the DOM. iOS breaks if you move the media element, so this is set this to
16001 * false there. Everywhere else this should be true.
16002 *
16003 * @type {boolean}
16004 * @default
16005 */
16006Html5.prototype.movingMediaElementInDOM = !browser.IS_IOS;
16007
16008// TODO: Previous comment: No longer appears to be used. Can probably be removed.
16009//       Is this true?
16010/**
16011 * Boolean indicating whether the `HTML5` tech currently supports automatic media resize
16012 * when going into fullscreen.
16013 *
16014 * @type {boolean}
16015 * @default
16016 */
16017Html5.prototype.featuresFullscreenResize = true;
16018
16019/**
16020 * Boolean indicating whether the `HTML5` tech currently supports the progress event.
16021 * If this is false, manual `progress` events will be triggred instead.
16022 *
16023 * @type {boolean}
16024 * @default
16025 */
16026Html5.prototype.featuresProgressEvents = true;
16027
16028/**
16029 * Boolean indicating whether the `HTML5` tech currently supports the timeupdate event.
16030 * If this is false, manual `timeupdate` events will be triggred instead.
16031 *
16032 * @default
16033 */
16034Html5.prototype.featuresTimeupdateEvents = true;
16035
16036/**
16037 * Boolean indicating whether the `HTML5` tech currently supports native `TextTrack`s.
16038 *
16039 * @type {boolean}
16040 * @default {@link Html5.supportsNativeTextTracks}
16041 */
16042Html5.prototype.featuresNativeTextTracks = Html5.supportsNativeTextTracks();
16043
16044/**
16045 * Boolean indicating whether the `HTML5` tech currently supports native `VideoTrack`s.
16046 *
16047 * @type {boolean}
16048 * @default {@link Html5.supportsNativeVideoTracks}
16049 */
16050Html5.prototype.featuresNativeVideoTracks = Html5.supportsNativeVideoTracks();
16051
16052/**
16053 * Boolean indicating whether the `HTML5` tech currently supports native `AudioTrack`s.
16054 *
16055 * @type {boolean}
16056 * @default {@link Html5.supportsNativeAudioTracks}
16057 */
16058Html5.prototype.featuresNativeAudioTracks = Html5.supportsNativeAudioTracks();
16059
16060// HTML5 Feature detection and Device Fixes --------------------------------- //
16061var canPlayType = Html5.TEST_VID && Html5.TEST_VID.constructor.prototype.canPlayType;
16062var mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i;
16063var mp4RE = /^video\/mp4/i;
16064
16065Html5.patchCanPlayType = function () {
16066
16067  // Android 4.0 and above can play HLS to some extent but it reports being unable to do so
16068  if (browser.ANDROID_VERSION >= 4.0 && !browser.IS_FIREFOX) {
16069    Html5.TEST_VID.constructor.prototype.canPlayType = function (type) {
16070      if (type && mpegurlRE.test(type)) {
16071        return 'maybe';
16072      }
16073      return canPlayType.call(this, type);
16074    };
16075
16076    // Override Android 2.2 and less canPlayType method which is broken
16077  } else if (browser.IS_OLD_ANDROID) {
16078    Html5.TEST_VID.constructor.prototype.canPlayType = function (type) {
16079      if (type && mp4RE.test(type)) {
16080        return 'maybe';
16081      }
16082      return canPlayType.call(this, type);
16083    };
16084  }
16085};
16086
16087Html5.unpatchCanPlayType = function () {
16088  var r = Html5.TEST_VID.constructor.prototype.canPlayType;
16089
16090  Html5.TEST_VID.constructor.prototype.canPlayType = canPlayType;
16091  return r;
16092};
16093
16094// by default, patch the media element
16095Html5.patchCanPlayType();
16096
16097Html5.disposeMediaElement = function (el) {
16098  if (!el) {
16099    return;
16100  }
16101
16102  if (el.parentNode) {
16103    el.parentNode.removeChild(el);
16104  }
16105
16106  // remove any child track or source nodes to prevent their loading
16107  while (el.hasChildNodes()) {
16108    el.removeChild(el.firstChild);
16109  }
16110
16111  // remove any src reference. not setting `src=''` because that causes a warning
16112  // in firefox
16113  el.removeAttribute('src');
16114
16115  // force the media element to update its loading state by calling load()
16116  // however IE on Windows 7N has a bug that throws an error so need a try/catch (#793)
16117  if (typeof el.load === 'function') {
16118    // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473)
16119    (function () {
16120      try {
16121        el.load();
16122      } catch (e) {
16123        // not supported
16124      }
16125    })();
16126  }
16127};
16128
16129Html5.resetMediaElement = function (el) {
16130  if (!el) {
16131    return;
16132  }
16133
16134  var sources = el.querySelectorAll('source');
16135  var i = sources.length;
16136
16137  while (i--) {
16138    el.removeChild(sources[i]);
16139  }
16140
16141  // remove any src reference.
16142  // not setting `src=''` because that throws an error
16143  el.removeAttribute('src');
16144
16145  if (typeof el.load === 'function') {
16146    // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473)
16147    (function () {
16148      try {
16149        el.load();
16150      } catch (e) {
16151        // satisfy linter
16152      }
16153    })();
16154  }
16155};
16156
16157/* Native HTML5 element property wrapping ----------------------------------- */
16158// Wrap native properties with a getter
16159[
16160/**
16161 * Get the value of `paused` from the media element. `paused` indicates whether the media element
16162 * is currently paused or not.
16163 *
16164 * @method Html5#paused
16165 * @return {boolean}
16166 *         The value of `paused` from the media element.
16167 *
16168 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-paused}
16169 */
16170'paused',
16171
16172/**
16173 * Get the value of `currentTime` from the media element. `currentTime` indicates
16174 * the current second that the media is at in playback.
16175 *
16176 * @method Html5#currentTime
16177 * @return {number}
16178 *         The value of `currentTime` from the media element.
16179 *
16180 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-currenttime}
16181 */
16182'currentTime',
16183
16184/**
16185 * Get the value of `buffered` from the media element. `buffered` is a `TimeRange`
16186 * object that represents the parts of the media that are already downloaded and
16187 * available for playback.
16188 *
16189 * @method Html5#buffered
16190 * @return {TimeRange}
16191 *         The value of `buffered` from the media element.
16192 *
16193 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-buffered}
16194 */
16195'buffered',
16196
16197/**
16198 * Get the value of `volume` from the media element. `volume` indicates
16199 * the current playback volume of audio for a media. `volume` will be a value from 0
16200 * (silent) to 1 (loudest and default).
16201 *
16202 * @method Html5#volume
16203 * @return {number}
16204 *         The value of `volume` from the media element. Value will be between 0-1.
16205 *
16206 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume}
16207 */
16208'volume',
16209
16210/**
16211 * Get the value of `muted` from the media element. `muted` indicates
16212 * that the volume for the media should be set to silent. This does not actually change
16213 * the `volume` attribute.
16214 *
16215 * @method Html5#muted
16216 * @return {boolean}
16217 *         - True if the value of `volume` should be ignored and the audio set to silent.
16218 *         - False if the value of `volume` should be used.
16219 *
16220 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted}
16221 */
16222'muted',
16223
16224/**
16225 * Get the value of `poster` from the media element. `poster` indicates
16226 * that the url of an image file that can/will be shown when no media data is available.
16227 *
16228 * @method Html5#poster
16229 * @return {string}
16230 *         The value of `poster` from the media element. Value will be a url to an
16231 *         image.
16232 *
16233 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-video-poster}
16234 */
16235'poster',
16236
16237/**
16238 * Get the value of `preload` from the media element. `preload` indicates
16239 * what should download before the media is interacted with. It can have the following
16240 * values:
16241 * - none: nothing should be downloaded
16242 * - metadata: poster and the first few frames of the media may be downloaded to get
16243 *   media dimensions and other metadata
16244 * - auto: allow the media and metadata for the media to be downloaded before
16245 *    interaction
16246 *
16247 * @method Html5#preload
16248 * @return {string}
16249 *         The value of `preload` from the media element. Will be 'none', 'metadata',
16250 *         or 'auto'.
16251 *
16252 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload}
16253 */
16254'preload',
16255
16256/**
16257 * Get the value of `autoplay` from the media element. `autoplay` indicates
16258 * that the media should start to play as soon as the page is ready.
16259 *
16260 * @method Html5#autoplay
16261 * @return {boolean}
16262 *         - The value of `autoplay` from the media element.
16263 *         - True indicates that the media should start as soon as the page loads.
16264 *         - False indicates that the media should not start as soon as the page loads.
16265 *
16266 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay}
16267 */
16268'autoplay',
16269
16270/**
16271 * Get the value of `controls` from the media element. `controls` indicates
16272 * whether the native media controls should be shown or hidden.
16273 *
16274 * @method Html5#controls
16275 * @return {boolean}
16276 *         - The value of `controls` from the media element.
16277 *         - True indicates that native controls should be showing.
16278 *         - False indicates that native controls should be hidden.
16279 *
16280 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-controls}
16281 */
16282'controls',
16283
16284/**
16285 * Get the value of `loop` from the media element. `loop` indicates
16286 * that the media should return to the start of the media and continue playing once
16287 * it reaches the end.
16288 *
16289 * @method Html5#loop
16290 * @return {boolean}
16291 *         - The value of `loop` from the media element.
16292 *         - True indicates that playback should seek back to start once
16293 *           the end of a media is reached.
16294 *         - False indicates that playback should not loop back to the start when the
16295 *           end of the media is reached.
16296 *
16297 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop}
16298 */
16299'loop',
16300
16301/**
16302 * Get the value of the `error` from the media element. `error` indicates any
16303 * MediaError that may have occured during playback. If error returns null there is no
16304 * current error.
16305 *
16306 * @method Html5#error
16307 * @return {MediaError|null}
16308 *         The value of `error` from the media element. Will be `MediaError` if there
16309 *         is a current error and null otherwise.
16310 *
16311 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-error}
16312 */
16313'error',
16314
16315/**
16316 * Get the value of `seeking` from the media element. `seeking` indicates whether the
16317 * media is currently seeking to a new position or not.
16318 *
16319 * @method Html5#seeking
16320 * @return {boolean}
16321 *         - The value of `seeking` from the media element.
16322 *         - True indicates that the media is currently seeking to a new position.
16323 *         - Flase indicates that the media is not seeking to a new position at this time.
16324 *
16325 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seeking}
16326 */
16327'seeking',
16328
16329/**
16330 * Get the value of `seekable` from the media element. `seekable` returns a
16331 * `TimeRange` object indicating ranges of time that can currently be `seeked` to.
16332 *
16333 * @method Html5#seekable
16334 * @return {TimeRange}
16335 *         The value of `seekable` from the media element. A `TimeRange` object
16336 *         indicating the current ranges of time that can be seeked to.
16337 *
16338 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seekable}
16339 */
16340'seekable',
16341
16342/**
16343 * Get the value of `ended` from the media element. `ended` indicates whether
16344 * the media has reached the end or not.
16345 *
16346 * @method Html5#ended
16347 * @return {boolean}
16348 *         - The value of `ended` from the media element.
16349 *         - True indicates that the media has ended.
16350 *         - False indicates that the media has not ended.
16351 *
16352 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended}
16353 */
16354'ended',
16355
16356/**
16357 * Get the value of `defaultMuted` from the media element. `defaultMuted` indicates
16358 * whether the media should start muted or not. Only changes the default state of the
16359 * media. `muted` and `defaultMuted` can have different values. `muted` indicates the
16360 * current state.
16361 *
16362 * @method Html5#defaultMuted
16363 * @return {boolean}
16364 *         - The value of `defaultMuted` from the media element.
16365 *         - True indicates that the media should start muted.
16366 *         - False indicates that the media should not start muted
16367 *
16368 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted}
16369 */
16370'defaultMuted',
16371
16372/**
16373 * Get the value of `playbackRate` from the media element. `playbackRate` indicates
16374 * the rate at which the media is currently playing back. Examples:
16375 *   - if playbackRate is set to 2, media will play twice as fast.
16376 *   - if playbackRate is set to 0.5, media will play half as fast.
16377 *
16378 * @method Html5#playbackRate
16379 * @return {number}
16380 *         The value of `playbackRate` from the media element. A number indicating
16381 *         the current playback speed of the media, where 1 is normal speed.
16382 *
16383 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}
16384 */
16385'playbackRate',
16386
16387/**
16388 * Get the value of `played` from the media element. `played` returns a `TimeRange`
16389 * object representing points in the media timeline that have been played.
16390 *
16391 * @method Html5#played
16392 * @return {TimeRange}
16393 *         The value of `played` from the media element. A `TimeRange` object indicating
16394 *         the ranges of time that have been played.
16395 *
16396 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-played}
16397 */
16398'played',
16399
16400/**
16401 * Get the value of `networkState` from the media element. `networkState` indicates
16402 * the current network state. It returns an enumeration from the following list:
16403 * - 0: NETWORK_EMPTY
16404 * - 1: NEWORK_IDLE
16405 * - 2: NETWORK_LOADING
16406 * - 3: NETWORK_NO_SOURCE
16407 *
16408 * @method Html5#networkState
16409 * @return {number}
16410 *         The value of `networkState` from the media element. This will be a number
16411 *         from the list in the description.
16412 *
16413 * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-networkstate}
16414 */
16415'networkState',
16416
16417/**
16418 * Get the value of `readyState` from the media element. `readyState` indicates
16419 * the current state of the media element. It returns an enumeration from the
16420 * following list:
16421 * - 0: HAVE_NOTHING
16422 * - 1: HAVE_METADATA
16423 * - 2: HAVE_CURRENT_DATA
16424 * - 3: HAVE_FUTURE_DATA
16425 * - 4: HAVE_ENOUGH_DATA
16426 *
16427 * @method Html5#readyState
16428 * @return {number}
16429 *         The value of `readyState` from the media element. This will be a number
16430 *         from the list in the description.
16431 *
16432 * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#ready-states}
16433 */
16434'readyState',
16435
16436/**
16437 * Get the value of `videoWidth` from the video element. `videoWidth` indicates
16438 * the current width of the video in css pixels.
16439 *
16440 * @method Html5#videoWidth
16441 * @return {number}
16442 *         The value of `videoWidth` from the video element. This will be a number
16443 *         in css pixels.
16444 *
16445 * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth}
16446 */
16447'videoWidth',
16448
16449/**
16450 * Get the value of `videoHeight` from the video element. `videoHeigth` indicates
16451 * the current height of the video in css pixels.
16452 *
16453 * @method Html5#videoHeight
16454 * @return {number}
16455 *         The value of `videoHeight` from the video element. This will be a number
16456 *         in css pixels.
16457 *
16458 * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth}
16459 */
16460'videoHeight'].forEach(function (prop) {
16461  Html5.prototype[prop] = function () {
16462    return this.el_[prop];
16463  };
16464});
16465
16466// Wrap native properties with a setter in this format:
16467// set + toTitleCase(name)
16468[
16469/**
16470 * Set the value of `volume` on the media element. `volume` indicates the current
16471 * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and
16472 * so on.
16473 *
16474 * @method Html5#setVolume
16475 * @param {number} percentAsDecimal
16476 *        The volume percent as a decimal. Valid range is from 0-1.
16477 *
16478 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume}
16479 */
16480'volume',
16481
16482/**
16483 * Set the value of `muted` on the media element. `muted` indicates the current
16484 * audio level should be silent.
16485 *
16486 * @method Html5#setMuted
16487 * @param {boolean} muted
16488 *        - True if the audio should be set to silent
16489 *        - False otherwise
16490 *
16491 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted}
16492 */
16493'muted',
16494
16495/**
16496 * Set the value of `src` on the media element. `src` indicates the current
16497 * {@link Tech~SourceObject} for the media.
16498 *
16499 * @method Html5#setSrc
16500 * @param {Tech~SourceObject} src
16501 *        The source object to set as the current source.
16502 *
16503 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-src}
16504 */
16505'src',
16506
16507/**
16508 * Set the value of `poster` on the media element. `poster` is the url to
16509 * an image file that can/will be shown when no media data is available.
16510 *
16511 * @method Html5#setPoster
16512 * @param {string} poster
16513 *        The url to an image that should be used as the `poster` for the media
16514 *        element.
16515 *
16516 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-poster}
16517 */
16518'poster',
16519
16520/**
16521 * Set the value of `preload` on the media element. `preload` indicates
16522 * what should download before the media is interacted with. It can have the following
16523 * values:
16524 * - none: nothing should be downloaded
16525 * - metadata: poster and the first few frames of the media may be downloaded to get
16526 *   media dimensions and other metadata
16527 * - auto: allow the media and metadata for the media to be downloaded before
16528 *    interaction
16529 *
16530 * @method Html5#setPreload
16531 * @param {string} preload
16532 *         The value of `preload` to set on the media element. Must be 'none', 'metadata',
16533 *         or 'auto'.
16534 *
16535 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload}
16536 */
16537'preload',
16538
16539/**
16540 * Set the value of `autoplay` on the media element. `autoplay` indicates
16541 * that the media should start to play as soon as the page is ready.
16542 *
16543 * @method Html5#setAutoplay
16544 * @param {boolean} autoplay
16545 *         - True indicates that the media should start as soon as the page loads.
16546 *         - False indicates that the media should not start as soon as the page loads.
16547 *
16548 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay}
16549 */
16550'autoplay',
16551
16552/**
16553 * Set the value of `loop` on the media element. `loop` indicates
16554 * that the media should return to the start of the media and continue playing once
16555 * it reaches the end.
16556 *
16557 * @method Html5#setLoop
16558 * @param {boolean} loop
16559 *         - True indicates that playback should seek back to start once
16560 *           the end of a media is reached.
16561 *         - False indicates that playback should not loop back to the start when the
16562 *           end of the media is reached.
16563 *
16564 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop}
16565 */
16566'loop',
16567
16568/**
16569 * Set the value of `playbackRate` on the media element. `playbackRate` indicates
16570 * the rate at which the media should play back. Examples:
16571 *   - if playbackRate is set to 2, media will play twice as fast.
16572 *   - if playbackRate is set to 0.5, media will play half as fast.
16573 *
16574 * @method Html5#setPlaybackRate
16575 * @return {number}
16576 *         The value of `playbackRate` from the media element. A number indicating
16577 *         the current playback speed of the media, where 1 is normal speed.
16578 *
16579 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}
16580 */
16581'playbackRate'].forEach(function (prop) {
16582  Html5.prototype['set' + (0, _toTitleCase2['default'])(prop)] = function (v) {
16583    this.el_[prop] = v;
16584  };
16585});
16586
16587// wrap native functions with a function
16588[
16589/**
16590 * A wrapper around the media elements `pause` function. This will call the `HTML5`
16591 * media elements `pause` function.
16592 *
16593 * @method Html5#pause
16594 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-pause}
16595 */
16596'pause',
16597
16598/**
16599 * A wrapper around the media elements `load` function. This will call the `HTML5`s
16600 * media element `load` function.
16601 *
16602 * @method Html5#load
16603 * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-load}
16604 */
16605'load'].forEach(function (prop) {
16606  Html5.prototype[prop] = function () {
16607    return this.el_[prop]();
16608  };
16609});
16610
16611_tech2['default'].withSourceHandlers(Html5);
16612
16613/**
16614 * Native source handler for Html5, simply passes the source to the media element.
16615 *
16616 * @proprety {Tech~SourceObject} source
16617 *        The source object
16618 *
16619 * @proprety {Html5} tech
16620 *        The instance of the HTML5 tech.
16621 */
16622Html5.nativeSourceHandler = {};
16623
16624/**
16625 * Check if the media element can play the given mime type.
16626 *
16627 * @param {string} type
16628 *        The mimetype to check
16629 *
16630 * @return {string}
16631 *         'probably', 'maybe', or '' (empty string)
16632 */
16633Html5.nativeSourceHandler.canPlayType = function (type) {
16634  // IE9 on Windows 7 without MediaPlayer throws an error here
16635  // https://github.com/videojs/video.js/issues/519
16636  try {
16637    return Html5.TEST_VID.canPlayType(type);
16638  } catch (e) {
16639    return '';
16640  }
16641};
16642
16643/**
16644 * Check if the media element can handle a source natively.
16645 *
16646 * @param {Tech~SourceObject} source
16647 *         The source object
16648 *
16649 * @param {Object} [options]
16650 *         Options to be passed to the tech.
16651 *
16652 * @return {string}
16653 *         'probably', 'maybe', or '' (empty string).
16654 */
16655Html5.nativeSourceHandler.canHandleSource = function (source, options) {
16656
16657  // If a type was provided we should rely on that
16658  if (source.type) {
16659    return Html5.nativeSourceHandler.canPlayType(source.type);
16660
16661    // If no type, fall back to checking 'video/[EXTENSION]'
16662  } else if (source.src) {
16663    var ext = Url.getFileExtension(source.src);
16664
16665    return Html5.nativeSourceHandler.canPlayType('video/' + ext);
16666  }
16667
16668  return '';
16669};
16670
16671/**
16672 * Pass the source to the native media element.
16673 *
16674 * @param {Tech~SourceObject} source
16675 *        The source object
16676 *
16677 * @param {Html5} tech
16678 *        The instance of the Html5 tech
16679 *
16680 * @param {Object} [options]
16681 *        The options to pass to the source
16682 */
16683Html5.nativeSourceHandler.handleSource = function (source, tech, options) {
16684  tech.setSrc(source.src);
16685};
16686
16687/**
16688 * A noop for the native dispose function, as cleanup is not needed.
16689 */
16690Html5.nativeSourceHandler.dispose = function () {};
16691
16692// Register the native source handler
16693Html5.registerSourceHandler(Html5.nativeSourceHandler);
16694
16695_component2['default'].registerComponent('Html5', Html5);
16696_tech2['default'].registerTech('Html5', Html5);
16697exports['default'] = Html5;
16698
16699},{"5":5,"62":62,"78":78,"81":81,"83":83,"86":86,"87":87,"88":88,"91":91,"92":92,"94":94,"95":95,"98":98}],61:[function(_dereq_,module,exports){
16700'use strict';
16701
16702exports.__esModule = true;
16703
16704var _component = _dereq_(5);
16705
16706var _component2 = _interopRequireDefault(_component);
16707
16708var _tech = _dereq_(62);
16709
16710var _tech2 = _interopRequireDefault(_tech);
16711
16712var _toTitleCase = _dereq_(91);
16713
16714var _toTitleCase2 = _interopRequireDefault(_toTitleCase);
16715
16716function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
16717
16718function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
16719
16720function _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; }
16721
16722function _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; } /**
16723                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file loader.js
16724                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
16725
16726
16727/**
16728 * The `MediaLoader` is the `Component` that decides which playback technology to load
16729 * when a player is initialized.
16730 *
16731 * @extends Component
16732 */
16733var MediaLoader = function (_Component) {
16734  _inherits(MediaLoader, _Component);
16735
16736  /**
16737   * Create an instance of this class.
16738   *
16739   * @param {Player} player
16740   *        The `Player` that this class should attach to.
16741   *
16742   * @param {Object} [options]
16743   *        The key/value stroe of player options.
16744   *
16745   * @param {Component~ReadyCallback} [ready]
16746   *        The function that is run when this component is ready.
16747   */
16748  function MediaLoader(player, options, ready) {
16749    _classCallCheck(this, MediaLoader);
16750
16751    // If there are no sources when the player is initialized,
16752    // load the first supported playback technology.
16753
16754    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options, ready));
16755
16756    if (!options.playerOptions.sources || options.playerOptions.sources.length === 0) {
16757      for (var i = 0, j = options.playerOptions.techOrder; i < j.length; i++) {
16758        var techName = (0, _toTitleCase2['default'])(j[i]);
16759        var tech = _tech2['default'].getTech(techName);
16760
16761        // Support old behavior of techs being registered as components.
16762        // Remove once that deprecated behavior is removed.
16763        if (!techName) {
16764          tech = _component2['default'].getComponent(techName);
16765        }
16766
16767        // Check if the browser supports this technology
16768        if (tech && tech.isSupported()) {
16769          player.loadTech_(techName);
16770          break;
16771        }
16772      }
16773    } else {
16774      // Loop through playback technologies (HTML5, Flash) and check for support.
16775      // Then load the best source.
16776      // A few assumptions here:
16777      //   All playback technologies respect preload false.
16778      player.src(options.playerOptions.sources);
16779    }
16780    return _this;
16781  }
16782
16783  return MediaLoader;
16784}(_component2['default']);
16785
16786_component2['default'].registerComponent('MediaLoader', MediaLoader);
16787exports['default'] = MediaLoader;
16788
16789},{"5":5,"62":62,"91":91}],62:[function(_dereq_,module,exports){
16790'use strict';
16791
16792exports.__esModule = true;
16793
16794var _component = _dereq_(5);
16795
16796var _component2 = _interopRequireDefault(_component);
16797
16798var _htmlTrackElement = _dereq_(66);
16799
16800var _htmlTrackElement2 = _interopRequireDefault(_htmlTrackElement);
16801
16802var _htmlTrackElementList = _dereq_(65);
16803
16804var _htmlTrackElementList2 = _interopRequireDefault(_htmlTrackElementList);
16805
16806var _mergeOptions = _dereq_(87);
16807
16808var _mergeOptions2 = _interopRequireDefault(_mergeOptions);
16809
16810var _textTrack = _dereq_(72);
16811
16812var _textTrack2 = _interopRequireDefault(_textTrack);
16813
16814var _textTrackList = _dereq_(70);
16815
16816var _textTrackList2 = _interopRequireDefault(_textTrackList);
16817
16818var _videoTrackList = _dereq_(76);
16819
16820var _videoTrackList2 = _interopRequireDefault(_videoTrackList);
16821
16822var _audioTrackList = _dereq_(63);
16823
16824var _audioTrackList2 = _interopRequireDefault(_audioTrackList);
16825
16826var _fn = _dereq_(83);
16827
16828var Fn = _interopRequireWildcard(_fn);
16829
16830var _log = _dereq_(86);
16831
16832var _log2 = _interopRequireDefault(_log);
16833
16834var _timeRanges = _dereq_(90);
16835
16836var _buffer = _dereq_(79);
16837
16838var _mediaError = _dereq_(46);
16839
16840var _mediaError2 = _interopRequireDefault(_mediaError);
16841
16842var _window = _dereq_(95);
16843
16844var _window2 = _interopRequireDefault(_window);
16845
16846var _document = _dereq_(94);
16847
16848var _document2 = _interopRequireDefault(_document);
16849
16850var _obj = _dereq_(88);
16851
16852function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
16853
16854function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
16855
16856function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
16857
16858function _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; }
16859
16860function _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; } /**
16861                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file tech.js
16862                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
16863
16864/**
16865 * An Object containing a structure like: `{src: 'url', type: 'mimetype'}` or string
16866 * that just contains the src url alone.
16867 * * `var SourceObject = {src: 'http://ex.com/video.mp4', type: 'video/mp4'};`
16868   * `var SourceString = 'http://example.com/some-video.mp4';`
16869 *
16870 * @typedef {Object|string} Tech~SourceObject
16871 *
16872 * @property {string} src
16873 *           The url to the source
16874 *
16875 * @property {string} type
16876 *           The mime type of the source
16877 */
16878
16879/**
16880 * A function used by {@link Tech} to create a new {@link TextTrack}.
16881 *
16882 * @param {Tech} self
16883 *        An instance of the Tech class.
16884 *
16885 * @param {string} kind
16886 *        `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)
16887 *
16888 * @param {string} [label]
16889 *        Label to identify the text track
16890 *
16891 * @param {string} [language]
16892 *        Two letter language abbreviation
16893 *
16894 * @param {Object} [options={}]
16895 *        An object with additional text track options
16896 *
16897 * @return {TextTrack}
16898 *          The text track that was created.
16899 */
16900function createTrackHelper(self, kind, label, language) {
16901  var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
16902
16903  var tracks = self.textTracks();
16904
16905  options.kind = kind;
16906
16907  if (label) {
16908    options.label = label;
16909  }
16910  if (language) {
16911    options.language = language;
16912  }
16913  options.tech = self;
16914
16915  var track = new _textTrack2['default'](options);
16916
16917  tracks.addTrack_(track);
16918
16919  return track;
16920}
16921
16922/**
16923 * This is the base class for media playback technology controllers, such as
16924 * {@link Flash} and {@link HTML5}
16925 *
16926 * @extends Component
16927 */
16928
16929var Tech = function (_Component) {
16930  _inherits(Tech, _Component);
16931
16932  /**
16933   * Create an instance of this Tech.
16934   *
16935   * @param {Object} [options]
16936   *        The key/value store of player options.
16937   *
16938   * @param {Component~ReadyCallback} ready
16939   *        Callback function to call when the `HTML5` Tech is ready.
16940   */
16941  function Tech() {
16942    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
16943    var ready = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
16944
16945    _classCallCheck(this, Tech);
16946
16947    // we don't want the tech to report user activity automatically.
16948    // This is done manually in addControlsListeners
16949    options.reportTouchActivity = false;
16950
16951    // keep track of whether the current source has played at all to
16952    // implement a very limited played()
16953    var _this = _possibleConstructorReturn(this, _Component.call(this, null, options, ready));
16954
16955    _this.hasStarted_ = false;
16956    _this.on('playing', function () {
16957      this.hasStarted_ = true;
16958    });
16959    _this.on('loadstart', function () {
16960      this.hasStarted_ = false;
16961    });
16962
16963    _this.textTracks_ = options.textTracks;
16964    _this.videoTracks_ = options.videoTracks;
16965    _this.audioTracks_ = options.audioTracks;
16966
16967    // Manually track progress in cases where the browser/flash player doesn't report it.
16968    if (!_this.featuresProgressEvents) {
16969      _this.manualProgressOn();
16970    }
16971
16972    // Manually track timeupdates in cases where the browser/flash player doesn't report it.
16973    if (!_this.featuresTimeupdateEvents) {
16974      _this.manualTimeUpdatesOn();
16975    }
16976
16977    ['Text', 'Audio', 'Video'].forEach(function (track) {
16978      if (options['native' + track + 'Tracks'] === false) {
16979        _this['featuresNative' + track + 'Tracks'] = false;
16980      }
16981    });
16982
16983    if (options.nativeCaptions === false) {
16984      _this.featuresNativeTextTracks = false;
16985    }
16986
16987    if (!_this.featuresNativeTextTracks) {
16988      _this.emulateTextTracks();
16989    }
16990
16991    _this.autoRemoteTextTracks_ = new _textTrackList2['default']();
16992
16993    _this.initTextTrackListeners();
16994    _this.initTrackListeners();
16995
16996    // Turn on component tap events only if not using native controls
16997    if (!options.nativeControlsForTouch) {
16998      _this.emitTapEvents();
16999    }
17000
17001    if (_this.constructor) {
17002      _this.name_ = _this.constructor.name || 'Unknown Tech';
17003    }
17004    return _this;
17005  }
17006
17007  /* Fallbacks for unsupported event types
17008  ================================================================================ */
17009
17010  /**
17011   * Polyfill the `progress` event for browsers that don't support it natively.
17012   *
17013   * @see {@link Tech#trackProgress}
17014   */
17015
17016
17017  Tech.prototype.manualProgressOn = function manualProgressOn() {
17018    this.on('durationchange', this.onDurationChange);
17019
17020    this.manualProgress = true;
17021
17022    // Trigger progress watching when a source begins loading
17023    this.one('ready', this.trackProgress);
17024  };
17025
17026  /**
17027   * Turn off the polyfill for `progress` events that was created in
17028   * {@link Tech#manualProgressOn}
17029   */
17030
17031
17032  Tech.prototype.manualProgressOff = function manualProgressOff() {
17033    this.manualProgress = false;
17034    this.stopTrackingProgress();
17035
17036    this.off('durationchange', this.onDurationChange);
17037  };
17038
17039  /**
17040   * This is used to trigger a `progress` event when the buffered percent changes. It
17041   * sets an interval function that will be called every 500 milliseconds to check if the
17042   * buffer end percent has changed.
17043   *
17044   * > This function is called by {@link Tech#manualProgressOn}
17045   *
17046   * @param {EventTarget~Event} event
17047   *        The `ready` event that caused this to run.
17048   *
17049   * @listens Tech#ready
17050   * @fires Tech#progress
17051   */
17052
17053
17054  Tech.prototype.trackProgress = function trackProgress(event) {
17055    this.stopTrackingProgress();
17056    this.progressInterval = this.setInterval(Fn.bind(this, function () {
17057      // Don't trigger unless buffered amount is greater than last time
17058
17059      var numBufferedPercent = this.bufferedPercent();
17060
17061      if (this.bufferedPercent_ !== numBufferedPercent) {
17062        /**
17063         * See {@link Player#progress}
17064         *
17065         * @event Tech#progress
17066         * @type {EventTarget~Event}
17067         */
17068        this.trigger('progress');
17069      }
17070
17071      this.bufferedPercent_ = numBufferedPercent;
17072
17073      if (numBufferedPercent === 1) {
17074        this.stopTrackingProgress();
17075      }
17076    }), 500);
17077  };
17078
17079  /**
17080   * Update our internal duration on a `durationchange` event by calling
17081   * {@link Tech#duration}.
17082   *
17083   * @param {EventTarget~Event} event
17084   *        The `durationchange` event that caused this to run.
17085   *
17086   * @listens Tech#durationchange
17087   */
17088
17089
17090  Tech.prototype.onDurationChange = function onDurationChange(event) {
17091    this.duration_ = this.duration();
17092  };
17093
17094  /**
17095   * Get and create a `TimeRange` object for buffering.
17096   *
17097   * @return {TimeRange}
17098   *         The time range object that was created.
17099   */
17100
17101
17102  Tech.prototype.buffered = function buffered() {
17103    return (0, _timeRanges.createTimeRange)(0, 0);
17104  };
17105
17106  /**
17107   * Get the percentage of the current video that is currently buffered.
17108   *
17109   * @return {number}
17110   *         A number from 0 to 1 that represents the decimal percentage of the
17111   *         video that is buffered.
17112   *
17113   */
17114
17115
17116  Tech.prototype.bufferedPercent = function bufferedPercent() {
17117    return (0, _buffer.bufferedPercent)(this.buffered(), this.duration_);
17118  };
17119
17120  /**
17121   * Turn off the polyfill for `progress` events that was created in
17122   * {@link Tech#manualProgressOn}
17123   * Stop manually tracking progress events by clearing the interval that was set in
17124   * {@link Tech#trackProgress}.
17125   */
17126
17127
17128  Tech.prototype.stopTrackingProgress = function stopTrackingProgress() {
17129    this.clearInterval(this.progressInterval);
17130  };
17131
17132  /**
17133   * Polyfill the `timeupdate` event for browsers that don't support it.
17134   *
17135   * @see {@link Tech#trackCurrentTime}
17136   */
17137
17138
17139  Tech.prototype.manualTimeUpdatesOn = function manualTimeUpdatesOn() {
17140    this.manualTimeUpdates = true;
17141
17142    this.on('play', this.trackCurrentTime);
17143    this.on('pause', this.stopTrackingCurrentTime);
17144  };
17145
17146  /**
17147   * Turn off the polyfill for `timeupdate` events that was created in
17148   * {@link Tech#manualTimeUpdatesOn}
17149   */
17150
17151
17152  Tech.prototype.manualTimeUpdatesOff = function manualTimeUpdatesOff() {
17153    this.manualTimeUpdates = false;
17154    this.stopTrackingCurrentTime();
17155    this.off('play', this.trackCurrentTime);
17156    this.off('pause', this.stopTrackingCurrentTime);
17157  };
17158
17159  /**
17160   * Sets up an interval function to track current time and trigger `timeupdate` every
17161   * 250 milliseconds.
17162   *
17163   * @listens Tech#play
17164   * @triggers Tech#timeupdate
17165   */
17166
17167
17168  Tech.prototype.trackCurrentTime = function trackCurrentTime() {
17169    if (this.currentTimeInterval) {
17170      this.stopTrackingCurrentTime();
17171    }
17172    this.currentTimeInterval = this.setInterval(function () {
17173      /**
17174       * Triggered at an interval of 250ms to indicated that time is passing in the video.
17175       *
17176       * @event Tech#timeupdate
17177       * @type {EventTarget~Event}
17178       */
17179      this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
17180
17181      // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
17182    }, 250);
17183  };
17184
17185  /**
17186   * Stop the interval function created in {@link Tech#trackCurrentTime} so that the
17187   * `timeupdate` event is no longer triggered.
17188   *
17189   * @listens {Tech#pause}
17190   */
17191
17192
17193  Tech.prototype.stopTrackingCurrentTime = function stopTrackingCurrentTime() {
17194    this.clearInterval(this.currentTimeInterval);
17195
17196    // #1002 - if the video ends right before the next timeupdate would happen,
17197    // the progress bar won't make it all the way to the end
17198    this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
17199  };
17200
17201  /**
17202   * Turn off all event polyfills, clear the `Tech`s {@link AudioTrackList},
17203   * {@link VideoTrackList}, and {@link TextTrackList}, and dispose of this Tech.
17204   *
17205   * @fires Component#dispose
17206   */
17207
17208
17209  Tech.prototype.dispose = function dispose() {
17210
17211    // clear out all tracks because we can't reuse them between techs
17212    this.clearTracks(['audio', 'video', 'text']);
17213
17214    // Turn off any manual progress or timeupdate tracking
17215    if (this.manualProgress) {
17216      this.manualProgressOff();
17217    }
17218
17219    if (this.manualTimeUpdates) {
17220      this.manualTimeUpdatesOff();
17221    }
17222
17223    _Component.prototype.dispose.call(this);
17224  };
17225
17226  /**
17227   * Clear out a single `TrackList` or an array of `TrackLists` given their names.
17228   *
17229   * > Note: Techs without source handlers should call this between sources for `video`
17230   *         & `audio` tracks. You don't want to use them between tracks!
17231   *
17232   * @param {string[]|string} types
17233   *        TrackList names to clear, valid names are `video`, `audio`, and
17234   *        `text`.
17235   */
17236
17237
17238  Tech.prototype.clearTracks = function clearTracks(types) {
17239    var _this2 = this;
17240
17241    types = [].concat(types);
17242    // clear out all tracks because we can't reuse them between techs
17243    types.forEach(function (type) {
17244      var list = _this2[type + 'Tracks']() || [];
17245      var i = list.length;
17246
17247      while (i--) {
17248        var track = list[i];
17249
17250        if (type === 'text') {
17251          _this2.removeRemoteTextTrack(track);
17252        }
17253        list.removeTrack_(track);
17254      }
17255    });
17256  };
17257
17258  /**
17259   * Remove any TextTracks added via addRemoteTextTrack that are
17260   * flagged for automatic garbage collection
17261   */
17262
17263
17264  Tech.prototype.cleanupAutoTextTracks = function cleanupAutoTextTracks() {
17265    var list = this.autoRemoteTextTracks_ || [];
17266    var i = list.length;
17267
17268    while (i--) {
17269      var track = list[i];
17270
17271      this.removeRemoteTextTrack(track);
17272    }
17273  };
17274
17275  /**
17276   * Reset the tech, which will removes all sources and reset the internal readyState.
17277   *
17278   * @abstract
17279   */
17280
17281
17282  Tech.prototype.reset = function reset() {};
17283
17284  /**
17285   * Get or set an error on the Tech.
17286   *
17287   * @param {MediaError} [err]
17288   *        Error to set on the Tech
17289   *
17290   * @return {MediaError|null}
17291   *         The current error object on the tech, or null if there isn't one.
17292   */
17293
17294
17295  Tech.prototype.error = function error(err) {
17296    if (err !== undefined) {
17297      this.error_ = new _mediaError2['default'](err);
17298      this.trigger('error');
17299    }
17300    return this.error_;
17301  };
17302
17303  /**
17304   * Returns the `TimeRange`s that have been played through for the current source.
17305   *
17306   * > NOTE: This implementation is incomplete. It does not track the played `TimeRange`.
17307   *         It only checks wether the source has played at all or not.
17308   *
17309   * @return {TimeRange}
17310   *         - A single time range if this video has played
17311   *         - An empty set of ranges if not.
17312   */
17313
17314
17315  Tech.prototype.played = function played() {
17316    if (this.hasStarted_) {
17317      return (0, _timeRanges.createTimeRange)(0, 0);
17318    }
17319    return (0, _timeRanges.createTimeRange)();
17320  };
17321
17322  /**
17323   * Causes a manual time update to occur if {@link Tech#manualTimeUpdatesOn} was
17324   * previously called.
17325   *
17326   * @fires Tech#timeupdate
17327   */
17328
17329
17330  Tech.prototype.setCurrentTime = function setCurrentTime() {
17331    // improve the accuracy of manual timeupdates
17332    if (this.manualTimeUpdates) {
17333      /**
17334       * A manual `timeupdate` event.
17335       *
17336       * @event Tech#timeupdate
17337       * @type {EventTarget~Event}
17338       */
17339      this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
17340    }
17341  };
17342
17343  /**
17344   * Turn on listeners for {@link TextTrackList} events. This adds
17345   * {@link EventTarget~EventListeners} for `texttrackchange`, `addtrack` and
17346   * `removetrack`.
17347   *
17348   * @fires Tech#texttrackchange
17349   */
17350
17351
17352  Tech.prototype.initTextTrackListeners = function initTextTrackListeners() {
17353    var textTrackListChanges = Fn.bind(this, function () {
17354      /**
17355       * Triggered when tracks are added or removed on the Tech {@link TextTrackList}
17356       *
17357       * @event Tech#texttrackchange
17358       * @type {EventTarget~Event}
17359       */
17360      this.trigger('texttrackchange');
17361    });
17362
17363    var tracks = this.textTracks();
17364
17365    if (!tracks) {
17366      return;
17367    }
17368
17369    tracks.addEventListener('removetrack', textTrackListChanges);
17370    tracks.addEventListener('addtrack', textTrackListChanges);
17371
17372    this.on('dispose', Fn.bind(this, function () {
17373      tracks.removeEventListener('removetrack', textTrackListChanges);
17374      tracks.removeEventListener('addtrack', textTrackListChanges);
17375    }));
17376  };
17377
17378  /**
17379   * Turn on listeners for {@link VideoTrackList} and {@link {AudioTrackList} events.
17380   * This adds {@link EventTarget~EventListeners} for `addtrack`, and  `removetrack`.
17381   *
17382   * @fires Tech#audiotrackchange
17383   * @fires Tech#videotrackchange
17384   */
17385
17386
17387  Tech.prototype.initTrackListeners = function initTrackListeners() {
17388    var _this3 = this;
17389
17390    var trackTypes = ['video', 'audio'];
17391
17392    trackTypes.forEach(function (type) {
17393      /**
17394       * Triggered when tracks are added or removed on the Tech {@link AudioTrackList}
17395       *
17396       * @event Tech#audiotrackchange
17397       * @type {EventTarget~Event}
17398       */
17399
17400      /**
17401       * Triggered when tracks are added or removed on the Tech {@link VideoTrackList}
17402       *
17403       * @event Tech#videotrackchange
17404       * @type {EventTarget~Event}
17405       */
17406      var trackListChanges = function trackListChanges() {
17407        _this3.trigger(type + 'trackchange');
17408      };
17409
17410      var tracks = _this3[type + 'Tracks']();
17411
17412      tracks.addEventListener('removetrack', trackListChanges);
17413      tracks.addEventListener('addtrack', trackListChanges);
17414
17415      _this3.on('dispose', function () {
17416        tracks.removeEventListener('removetrack', trackListChanges);
17417        tracks.removeEventListener('addtrack', trackListChanges);
17418      });
17419    });
17420  };
17421
17422  /**
17423   * Emulate TextTracks using vtt.js if necessary
17424   *
17425   * @fires Tech#vttjsloaded
17426   * @fires Tech#vttjserror
17427   */
17428
17429
17430  Tech.prototype.addWebVttScript_ = function addWebVttScript_() {
17431    var _this4 = this;
17432
17433    if (_window2['default'].WebVTT) {
17434      return;
17435    }
17436
17437    // Initially, Tech.el_ is a child of a dummy-div wait until the Component system
17438    // signals that the Tech is ready at which point Tech.el_ is part of the DOM
17439    // before inserting the WebVTT script
17440    if (_document2['default'].body.contains(this.el())) {
17441      var vtt = _dereq_(99);
17442
17443      // load via require if available and vtt.js script location was not passed in
17444      // as an option. novtt builds will turn the above require call into an empty object
17445      // which will cause this if check to always fail.
17446      if (!this.options_['vtt.js'] && (0, _obj.isPlain)(vtt) && Object.keys(vtt).length > 0) {
17447        this.trigger('vttjsloaded');
17448        return;
17449      }
17450
17451      // load vtt.js via the script location option or the cdn of no location was
17452      // passed in
17453      var script = _document2['default'].createElement('script');
17454
17455      script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.12.4/vtt.min.js';
17456      script.onload = function () {
17457        /**
17458         * Fired when vtt.js is loaded.
17459         *
17460         * @event Tech#vttjsloaded
17461         * @type {EventTarget~Event}
17462         */
17463        _this4.trigger('vttjsloaded');
17464      };
17465      script.onerror = function () {
17466        /**
17467         * Fired when vtt.js was not loaded due to an error
17468         *
17469         * @event Tech#vttjsloaded
17470         * @type {EventTarget~Event}
17471         */
17472        _this4.trigger('vttjserror');
17473      };
17474      this.on('dispose', function () {
17475        script.onload = null;
17476        script.onerror = null;
17477      });
17478      // but have not loaded yet and we set it to true before the inject so that
17479      // we don't overwrite the injected window.WebVTT if it loads right away
17480      _window2['default'].WebVTT = true;
17481      this.el().parentNode.appendChild(script);
17482    } else {
17483      this.ready(this.addWebVttScript_);
17484    }
17485  };
17486
17487  /**
17488   * Emulate texttracks
17489   *
17490   * @method emulateTextTracks
17491   */
17492
17493
17494  Tech.prototype.emulateTextTracks = function emulateTextTracks() {
17495    var _this5 = this;
17496
17497    var tracks = this.textTracks();
17498
17499    if (!tracks) {
17500      return;
17501    }
17502
17503    var remoteTracks = this.remoteTextTracks();
17504    var handleAddTrack = function handleAddTrack(e) {
17505      return tracks.addTrack_(e.track);
17506    };
17507    var handleRemoveTrack = function handleRemoveTrack(e) {
17508      return tracks.removeTrack_(e.track);
17509    };
17510
17511    remoteTracks.on('addtrack', handleAddTrack);
17512    remoteTracks.on('removetrack', handleRemoveTrack);
17513
17514    this.addWebVttScript_();
17515
17516    var updateDisplay = function updateDisplay() {
17517      return _this5.trigger('texttrackchange');
17518    };
17519
17520    var textTracksChanges = function textTracksChanges() {
17521      updateDisplay();
17522
17523      for (var i = 0; i < tracks.length; i++) {
17524        var track = tracks[i];
17525
17526        track.removeEventListener('cuechange', updateDisplay);
17527        if (track.mode === 'showing') {
17528          track.addEventListener('cuechange', updateDisplay);
17529        }
17530      }
17531    };
17532
17533    textTracksChanges();
17534    tracks.addEventListener('change', textTracksChanges);
17535    tracks.addEventListener('addtrack', textTracksChanges);
17536    tracks.addEventListener('removetrack', textTracksChanges);
17537
17538    this.on('dispose', function () {
17539      remoteTracks.off('addtrack', handleAddTrack);
17540      remoteTracks.off('removetrack', handleRemoveTrack);
17541      tracks.removeEventListener('change', textTracksChanges);
17542      tracks.removeEventListener('addtrack', textTracksChanges);
17543      tracks.removeEventListener('removetrack', textTracksChanges);
17544
17545      for (var i = 0; i < tracks.length; i++) {
17546        var track = tracks[i];
17547
17548        track.removeEventListener('cuechange', updateDisplay);
17549      }
17550    });
17551  };
17552
17553  /**
17554   * Get the `Tech`s {@link VideoTrackList}.
17555   *
17556   * @return {VideoTrackList}
17557   *          The video track list that the Tech is currently using.
17558   */
17559
17560
17561  Tech.prototype.videoTracks = function videoTracks() {
17562    this.videoTracks_ = this.videoTracks_ || new _videoTrackList2['default']();
17563    return this.videoTracks_;
17564  };
17565
17566  /**
17567   * Get the `Tech`s {@link AudioTrackList}.
17568   *
17569   * @return {AudioTrackList}
17570   *          The audio track list that the Tech is currently using.
17571   */
17572
17573
17574  Tech.prototype.audioTracks = function audioTracks() {
17575    this.audioTracks_ = this.audioTracks_ || new _audioTrackList2['default']();
17576    return this.audioTracks_;
17577  };
17578
17579  /**
17580   * Get the `Tech`s {@link TextTrackList}.
17581   *
17582   * @return {TextTrackList}
17583   *          The text track list that the Tech is currently using.
17584   */
17585
17586
17587  Tech.prototype.textTracks = function textTracks() {
17588    this.textTracks_ = this.textTracks_ || new _textTrackList2['default']();
17589    return this.textTracks_;
17590  };
17591
17592  /**
17593   * Get the `Tech`s remote {@link TextTrackList}, which is created from elements
17594   * that were added to the DOM.
17595   *
17596   * @return {TextTrackList}
17597   *          The remote text track list that the Tech is currently using.
17598   */
17599
17600
17601  Tech.prototype.remoteTextTracks = function remoteTextTracks() {
17602    this.remoteTextTracks_ = this.remoteTextTracks_ || new _textTrackList2['default']();
17603    return this.remoteTextTracks_;
17604  };
17605
17606  /**
17607   * Get The `Tech`s  {HTMLTrackElementList}, which are the elements in the DOM that are
17608   * being used as TextTracks.
17609   *
17610   * @return {HTMLTrackElementList}
17611   *          The current HTML track elements that exist for the tech.
17612   */
17613
17614
17615  Tech.prototype.remoteTextTrackEls = function remoteTextTrackEls() {
17616    this.remoteTextTrackEls_ = this.remoteTextTrackEls_ || new _htmlTrackElementList2['default']();
17617    return this.remoteTextTrackEls_;
17618  };
17619
17620  /**
17621   * Create and returns a remote {@link TextTrack} object.
17622   *
17623   * @param {string} kind
17624   *        `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)
17625   *
17626   * @param {string} [label]
17627   *        Label to identify the text track
17628   *
17629   * @param {string} [language]
17630   *        Two letter language abbreviation
17631   *
17632   * @return {TextTrack}
17633   *         The TextTrack that gets created.
17634   */
17635
17636
17637  Tech.prototype.addTextTrack = function addTextTrack(kind, label, language) {
17638    if (!kind) {
17639      throw new Error('TextTrack kind is required but was not provided');
17640    }
17641
17642    return createTrackHelper(this, kind, label, language);
17643  };
17644
17645  /**
17646   * Create an emulated TextTrack for use by addRemoteTextTrack
17647   *
17648   * This is intended to be overridden by classes that inherit from
17649   * Tech in order to create native or custom TextTracks.
17650   *
17651   * @param {Object} options
17652   *        The object should contain the options to initialize the TextTrack with.
17653   *
17654   * @param {string} [options.kind]
17655   *        `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata).
17656   *
17657   * @param {string} [options.label].
17658   *        Label to identify the text track
17659   *
17660   * @param {string} [options.language]
17661   *        Two letter language abbreviation.
17662   *
17663   * @return {HTMLTrackElement}
17664   *         The track element that gets created.
17665   */
17666
17667
17668  Tech.prototype.createRemoteTextTrack = function createRemoteTextTrack(options) {
17669    var track = (0, _mergeOptions2['default'])(options, {
17670      tech: this
17671    });
17672
17673    return new _htmlTrackElement2['default'](track);
17674  };
17675
17676  /**
17677   * Creates a remote text track object and returns an html track element.
17678   *
17679   * > Note: This can be an emulated {@link HTMLTrackElement} or a native one.
17680   *
17681   * @param {Object} options
17682   *        See {@link Tech#createRemoteTextTrack} for more detailed properties.
17683   *
17684   * @param {boolean} [manualCleanup=true]
17685   *        - When false: the TextTrack will be automatically removed from the video
17686   *          element whenever the source changes
17687   *        - When True: The TextTrack will have to be cleaned up manually
17688   *
17689   * @return {HTMLTrackElement}
17690   *         An Html Track Element.
17691   *
17692   * @deprecated The default functionality for this function will be equivalent
17693   *             to "manualCleanup=false" in the future. The manualCleanup parameter will
17694   *             also be removed.
17695   */
17696
17697
17698  Tech.prototype.addRemoteTextTrack = function addRemoteTextTrack() {
17699    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
17700    var manualCleanup = arguments[1];
17701
17702    var htmlTrackElement = this.createRemoteTextTrack(options);
17703
17704    if (manualCleanup !== true && manualCleanup !== false) {
17705      // deprecation warning
17706      _log2['default'].warn('Calling addRemoteTextTrack without explicitly setting the "manualCleanup" parameter to `true` is deprecated and default to `false` in future version of video.js');
17707      manualCleanup = true;
17708    }
17709
17710    // store HTMLTrackElement and TextTrack to remote list
17711    this.remoteTextTrackEls().addTrackElement_(htmlTrackElement);
17712    this.remoteTextTracks().addTrack_(htmlTrackElement.track);
17713
17714    if (manualCleanup !== true) {
17715      // create the TextTrackList if it doesn't exist
17716      this.autoRemoteTextTracks_.addTrack_(htmlTrackElement.track);
17717    }
17718
17719    return htmlTrackElement;
17720  };
17721
17722  /**
17723   * Remove a remote text track from the remote `TextTrackList`.
17724   *
17725   * @param {TextTrack} track
17726   *        `TextTrack` to remove from the `TextTrackList`
17727   */
17728
17729
17730  Tech.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) {
17731    var trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track);
17732
17733    // remove HTMLTrackElement and TextTrack from remote list
17734    this.remoteTextTrackEls().removeTrackElement_(trackElement);
17735    this.remoteTextTracks().removeTrack_(track);
17736    this.autoRemoteTextTracks_.removeTrack_(track);
17737  };
17738
17739  /**
17740   * Gets available media playback quality metrics as specified by the W3C's Media
17741   * Playback Quality API.
17742   *
17743   * @see [Spec]{@link https://wicg.github.io/media-playback-quality}
17744   *
17745   * @return {Object}
17746   *         An object with supported media playback quality metrics
17747   *
17748   * @abstract
17749   */
17750
17751
17752  Tech.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() {
17753    return {};
17754  };
17755
17756  /**
17757   * A method to set a poster from a `Tech`.
17758   *
17759   * @abstract
17760   */
17761
17762
17763  Tech.prototype.setPoster = function setPoster() {};
17764
17765  /**
17766   * A method to check for the presence of the 'playsinine' <video> attribute.
17767   *
17768   * @abstract
17769   */
17770
17771
17772  Tech.prototype.playsinline = function playsinline() {};
17773
17774  /**
17775   * A method to set or unset the 'playsinine' <video> attribute.
17776   *
17777   * @abstract
17778   */
17779
17780
17781  Tech.prototype.setPlaysinline = function setPlaysinline() {};
17782
17783  /*
17784   * Check if the tech can support the given mime-type.
17785   *
17786   * The base tech does not support any type, but source handlers might
17787   * overwrite this.
17788   *
17789   * @param  {string} type
17790   *         The mimetype to check for support
17791   *
17792   * @return {string}
17793   *         'probably', 'maybe', or empty string
17794   *
17795   * @see [Spec]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType}
17796   *
17797   * @abstract
17798   */
17799
17800
17801  Tech.prototype.canPlayType = function canPlayType() {
17802    return '';
17803  };
17804
17805  /*
17806   * Return whether the argument is a Tech or not.
17807   * Can be passed either a Class like `Html5` or a instance like `player.tech_`
17808   *
17809   * @param {Object} component
17810   *        The item to check
17811   *
17812   * @return {boolean}
17813   *         Whether it is a tech or not
17814   *         - True if it is a tech
17815   *         - False if it is not
17816   */
17817
17818
17819  Tech.isTech = function isTech(component) {
17820    return component.prototype instanceof Tech || component instanceof Tech || component === Tech;
17821  };
17822
17823  /**
17824   * Registers a `Tech` into a shared list for videojs.
17825   *
17826   * @param {string} name
17827   *        Name of the `Tech` to register.
17828   *
17829   * @param {Object} tech
17830   *        The `Tech` class to register.
17831   */
17832
17833
17834  Tech.registerTech = function registerTech(name, tech) {
17835    if (!Tech.techs_) {
17836      Tech.techs_ = {};
17837    }
17838
17839    if (!Tech.isTech(tech)) {
17840      throw new Error('Tech ' + name + ' must be a Tech');
17841    }
17842
17843    Tech.techs_[name] = tech;
17844    return tech;
17845  };
17846
17847  /**
17848   * Get a `Tech` from the shared list by name.
17849   *
17850   * @param {string} name
17851   *        Name of the component to get
17852   *
17853   * @return {Tech|undefined}
17854   *         The `Tech` or undefined if there was no tech with the name requsted.
17855   */
17856
17857
17858  Tech.getTech = function getTech(name) {
17859    if (Tech.techs_ && Tech.techs_[name]) {
17860      return Tech.techs_[name];
17861    }
17862
17863    if (_window2['default'] && _window2['default'].videojs && _window2['default'].videojs[name]) {
17864      _log2['default'].warn('The ' + name + ' tech was added to the videojs object when it should be registered using videojs.registerTech(name, tech)');
17865      return _window2['default'].videojs[name];
17866    }
17867  };
17868
17869  return Tech;
17870}(_component2['default']);
17871
17872/**
17873 * List of associated text tracks.
17874 *
17875 * @type {TextTrackList}
17876 * @private
17877 */
17878
17879
17880Tech.prototype.textTracks_; // eslint-disable-line
17881
17882/**
17883 * List of associated audio tracks.
17884 *
17885 * @type {AudioTrackList}
17886 * @private
17887 */
17888Tech.prototype.audioTracks_; // eslint-disable-line
17889
17890/**
17891 * List of associated video tracks.
17892 *
17893 * @type {VideoTrackList}
17894 * @private
17895 */
17896Tech.prototype.videoTracks_; // eslint-disable-line
17897
17898/**
17899 * Boolean indicating wether the `Tech` supports volume control.
17900 *
17901 * @type {boolean}
17902 * @default
17903 */
17904Tech.prototype.featuresVolumeControl = true;
17905
17906/**
17907 * Boolean indicating wether the `Tech` support fullscreen resize control.
17908 * Resizing plugins using request fullscreen reloads the plugin
17909 *
17910 * @type {boolean}
17911 * @default
17912 */
17913Tech.prototype.featuresFullscreenResize = false;
17914
17915/**
17916 * Boolean indicating wether the `Tech` supports changing the speed at which the video
17917 * plays. Examples:
17918 *   - Set player to play 2x (twice) as fast
17919 *   - Set player to play 0.5x (half) as fast
17920 *
17921 * @type {boolean}
17922 * @default
17923 */
17924Tech.prototype.featuresPlaybackRate = false;
17925
17926/**
17927 * Boolean indicating wether the `Tech` supports the `progress` event. This is currently
17928 * not triggered by video-js-swf. This will be used to determine if
17929 * {@link Tech#manualProgressOn} should be called.
17930 *
17931 * @type {boolean}
17932 * @default
17933 */
17934Tech.prototype.featuresProgressEvents = false;
17935
17936/**
17937 * Boolean indicating wether the `Tech` supports the `timeupdate` event. This is currently
17938 * not triggered by video-js-swf. This will be used to determine if
17939 * {@link Tech#manualTimeUpdates} should be called.
17940 *
17941 * @type {boolean}
17942 * @default
17943 */
17944Tech.prototype.featuresTimeupdateEvents = false;
17945
17946/**
17947 * Boolean indicating wether the `Tech` supports the native `TextTrack`s.
17948 * This will help us integrate with native `TextTrack`s if the browser supports them.
17949 *
17950 * @type {boolean}
17951 * @default
17952 */
17953Tech.prototype.featuresNativeTextTracks = false;
17954
17955/**
17956 * A functional mixin for techs that want to use the Source Handler pattern.
17957 * Source handlers are scripts for handling specific formats.
17958 * The source handler pattern is used for adaptive formats (HLS, DASH) that
17959 * manually load video data and feed it into a Source Buffer (Media Source Extensions)
17960 * Example: `Tech.withSourceHandlers.call(MyTech);`
17961 *
17962 * @param {Tech} _Tech
17963 *        The tech to add source handler functions to.
17964 *
17965 * @mixes Tech~SourceHandlerAdditions
17966 */
17967Tech.withSourceHandlers = function (_Tech) {
17968
17969  /**
17970   * Register a source handler
17971   *
17972   * @param {Function} handler
17973   *        The source handler class
17974   *
17975   * @param {number} [index]
17976   *        Register it at the following index
17977   */
17978  _Tech.registerSourceHandler = function (handler, index) {
17979    var handlers = _Tech.sourceHandlers;
17980
17981    if (!handlers) {
17982      handlers = _Tech.sourceHandlers = [];
17983    }
17984
17985    if (index === undefined) {
17986      // add to the end of the list
17987      index = handlers.length;
17988    }
17989
17990    handlers.splice(index, 0, handler);
17991  };
17992
17993  /**
17994   * Check if the tech can support the given type. Also checks the
17995   * Techs sourceHandlers.
17996   *
17997   * @param {string} type
17998   *         The mimetype to check.
17999   *
18000   * @return {string}
18001   *         'probably', 'maybe', or '' (empty string)
18002   */
18003  _Tech.canPlayType = function (type) {
18004    var handlers = _Tech.sourceHandlers || [];
18005    var can = void 0;
18006
18007    for (var i = 0; i < handlers.length; i++) {
18008      can = handlers[i].canPlayType(type);
18009
18010      if (can) {
18011        return can;
18012      }
18013    }
18014
18015    return '';
18016  };
18017
18018  /**
18019   * Returns the first source handler that supports the source.
18020   *
18021   * TODO: Answer question: should 'probably' be prioritized over 'maybe'
18022   *
18023   * @param {Tech~SourceObject} source
18024   *        The source object
18025   *
18026   * @param {Object} options
18027   *        The options passed to the tech
18028   *
18029   * @return {SourceHandler|null}
18030   *          The first source handler that supports the source or null if
18031   *          no SourceHandler supports the source
18032   */
18033  _Tech.selectSourceHandler = function (source, options) {
18034    var handlers = _Tech.sourceHandlers || [];
18035    var can = void 0;
18036
18037    for (var i = 0; i < handlers.length; i++) {
18038      can = handlers[i].canHandleSource(source, options);
18039
18040      if (can) {
18041        return handlers[i];
18042      }
18043    }
18044
18045    return null;
18046  };
18047
18048  /**
18049   * Check if the tech can support the given source.
18050   *
18051   * @param {Tech~SourceObject} srcObj
18052   *        The source object
18053   *
18054   * @param {Object} options
18055   *        The options passed to the tech
18056   *
18057   * @return {string}
18058   *         'probably', 'maybe', or '' (empty string)
18059   */
18060  _Tech.canPlaySource = function (srcObj, options) {
18061    var sh = _Tech.selectSourceHandler(srcObj, options);
18062
18063    if (sh) {
18064      return sh.canHandleSource(srcObj, options);
18065    }
18066
18067    return '';
18068  };
18069
18070  /**
18071   * When using a source handler, prefer its implementation of
18072   * any function normally provided by the tech.
18073   */
18074  var deferrable = ['seekable', 'duration'];
18075
18076  /**
18077   * A wrapper around {@link Tech#seekable} that will call a `SourceHandler`s seekable
18078   * function if it exists, with a fallback to the Techs seekable function.
18079   *
18080   * @method _Tech.seekable
18081   */
18082
18083  /**
18084   * A wrapper around {@link Tech#duration} that will call a `SourceHandler`s duration
18085   * function if it exists, otherwise it will fallback to the techs duration function.
18086   *
18087   * @method _Tech.duration
18088   */
18089
18090  deferrable.forEach(function (fnName) {
18091    var originalFn = this[fnName];
18092
18093    if (typeof originalFn !== 'function') {
18094      return;
18095    }
18096
18097    this[fnName] = function () {
18098      if (this.sourceHandler_ && this.sourceHandler_[fnName]) {
18099        return this.sourceHandler_[fnName].apply(this.sourceHandler_, arguments);
18100      }
18101      return originalFn.apply(this, arguments);
18102    };
18103  }, _Tech.prototype);
18104
18105  /**
18106   * Create a function for setting the source using a source object
18107   * and source handlers.
18108   * Should never be called unless a source handler was found.
18109   *
18110   * @param {Tech~SourceObject} source
18111   *        A source object with src and type keys
18112   *
18113   * @return {Tech}
18114   *         Returns itself; this method is chainable
18115   */
18116  _Tech.prototype.setSource = function (source) {
18117    var sh = _Tech.selectSourceHandler(source, this.options_);
18118
18119    if (!sh) {
18120      // Fall back to a native source hander when unsupported sources are
18121      // deliberately set
18122      if (_Tech.nativeSourceHandler) {
18123        sh = _Tech.nativeSourceHandler;
18124      } else {
18125        _log2['default'].error('No source hander found for the current source.');
18126      }
18127    }
18128
18129    // Dispose any existing source handler
18130    this.disposeSourceHandler();
18131    this.off('dispose', this.disposeSourceHandler);
18132
18133    if (sh !== _Tech.nativeSourceHandler) {
18134      this.currentSource_ = source;
18135
18136      // Catch if someone replaced the src without calling setSource.
18137      // If they do, set currentSource_ to null and dispose our source handler.
18138      this.off(this.el_, 'loadstart', _Tech.prototype.firstLoadStartListener_);
18139      this.off(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_);
18140      this.one(this.el_, 'loadstart', _Tech.prototype.firstLoadStartListener_);
18141    }
18142
18143    this.sourceHandler_ = sh.handleSource(source, this, this.options_);
18144    this.on('dispose', this.disposeSourceHandler);
18145
18146    return this;
18147  };
18148
18149  /**
18150   * Called once for the first loadstart of a video.
18151   *
18152   * @listens Tech#loadstart
18153   */
18154  _Tech.prototype.firstLoadStartListener_ = function () {
18155    this.one(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_);
18156  };
18157
18158  // On successive loadstarts when setSource has not been called again
18159  /**
18160   * Called after the first loadstart for a video occurs.
18161   *
18162   * @listens Tech#loadstart
18163   */
18164  _Tech.prototype.successiveLoadStartListener_ = function () {
18165    this.disposeSourceHandler();
18166    this.one(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_);
18167  };
18168
18169  /**
18170   * Clean up any existing SourceHandlers and listeners when the Tech is disposed.
18171   *
18172   * @listens Tech#dispose
18173   */
18174  _Tech.prototype.disposeSourceHandler = function () {
18175    // if we have a source and get another one
18176    // then we are loading something new
18177    // than clear all of our current tracks
18178    if (this.currentSource_) {
18179      this.clearTracks(['audio', 'video']);
18180      this.currentSource_ = null;
18181    }
18182
18183    // always clean up auto-text tracks
18184    this.cleanupAutoTextTracks();
18185
18186    if (this.sourceHandler_) {
18187      this.off(this.el_, 'loadstart', _Tech.prototype.firstLoadStartListener_);
18188      this.off(this.el_, 'loadstart', _Tech.prototype.successiveLoadStartListener_);
18189
18190      if (this.sourceHandler_.dispose) {
18191        this.sourceHandler_.dispose();
18192      }
18193
18194      this.sourceHandler_ = null;
18195    }
18196  };
18197};
18198
18199_component2['default'].registerComponent('Tech', Tech);
18200// Old name for Tech
18201// @deprecated
18202_component2['default'].registerComponent('MediaTechController', Tech);
18203Tech.registerTech('Tech', Tech);
18204exports['default'] = Tech;
18205
18206},{"46":46,"5":5,"63":63,"65":65,"66":66,"70":70,"72":72,"76":76,"79":79,"83":83,"86":86,"87":87,"88":88,"90":90,"94":94,"95":95,"99":99}],63:[function(_dereq_,module,exports){
18207'use strict';
18208
18209exports.__esModule = true;
18210
18211var _trackList = _dereq_(74);
18212
18213var _trackList2 = _interopRequireDefault(_trackList);
18214
18215var _browser = _dereq_(78);
18216
18217var browser = _interopRequireWildcard(_browser);
18218
18219var _document = _dereq_(94);
18220
18221var _document2 = _interopRequireDefault(_document);
18222
18223function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
18224
18225function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
18226
18227function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
18228
18229function _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; }
18230
18231function _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; } /**
18232                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file audio-track-list.js
18233                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
18234
18235
18236/**
18237 * Anywhere we call this function we diverge from the spec
18238 * as we only support one enabled audiotrack at a time
18239 *
18240 * @param {AudioTrackList} list
18241 *        list to work on
18242 *
18243 * @param {AudioTrack} track
18244 *        The track to skip
18245 *
18246 * @private
18247 */
18248var disableOthers = function disableOthers(list, track) {
18249  for (var i = 0; i < list.length; i++) {
18250    if (track.id === list[i].id) {
18251      continue;
18252    }
18253    // another audio track is enabled, disable it
18254    list[i].enabled = false;
18255  }
18256};
18257
18258/**
18259 * The current list of {@link AudioTrack} for a media file.
18260 *
18261 * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist}
18262 * @extends TrackList
18263 */
18264
18265var AudioTrackList = function (_TrackList) {
18266  _inherits(AudioTrackList, _TrackList);
18267
18268  /**
18269   * Create an instance of this class.
18270   *
18271   * @param {AudioTrack[]} [tracks=[]]
18272   *        A list of `AudioTrack` to instantiate the list with.
18273   */
18274  function AudioTrackList() {
18275    var _this, _ret;
18276
18277    var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
18278
18279    _classCallCheck(this, AudioTrackList);
18280
18281    var list = void 0;
18282
18283    // make sure only 1 track is enabled
18284    // sorted from last index to first index
18285    for (var i = tracks.length - 1; i >= 0; i--) {
18286      if (tracks[i].enabled) {
18287        disableOthers(tracks, tracks[i]);
18288        break;
18289      }
18290    }
18291
18292    // IE8 forces us to implement inheritance ourselves
18293    // as it does not support Object.defineProperty properly
18294    if (browser.IS_IE8) {
18295      list = _document2['default'].createElement('custom');
18296      for (var prop in _trackList2['default'].prototype) {
18297        if (prop !== 'constructor') {
18298          list[prop] = _trackList2['default'].prototype[prop];
18299        }
18300      }
18301      for (var _prop in AudioTrackList.prototype) {
18302        if (_prop !== 'constructor') {
18303          list[_prop] = AudioTrackList.prototype[_prop];
18304        }
18305      }
18306    }
18307
18308    list = (_this = _possibleConstructorReturn(this, _TrackList.call(this, tracks, list)), _this);
18309    list.changing_ = false;
18310
18311    return _ret = list, _possibleConstructorReturn(_this, _ret);
18312  }
18313
18314  /**
18315   * Add an {@link AudioTrack} to the `AudioTrackList`.
18316   *
18317   * @param {AudioTrack} track
18318   *        The AudioTrack to add to the list
18319   *
18320   * @fires Track#addtrack
18321   * @private
18322   */
18323
18324
18325  AudioTrackList.prototype.addTrack_ = function addTrack_(track) {
18326    var _this2 = this;
18327
18328    if (track.enabled) {
18329      disableOthers(this, track);
18330    }
18331
18332    _TrackList.prototype.addTrack_.call(this, track);
18333    // native tracks don't have this
18334    if (!track.addEventListener) {
18335      return;
18336    }
18337
18338    /**
18339     * @listens AudioTrack#enabledchange
18340     * @fires TrackList#change
18341     */
18342    track.addEventListener('enabledchange', function () {
18343      // when we are disabling other tracks (since we don't support
18344      // more than one track at a time) we will set changing_
18345      // to true so that we don't trigger additional change events
18346      if (_this2.changing_) {
18347        return;
18348      }
18349      _this2.changing_ = true;
18350      disableOthers(_this2, track);
18351      _this2.changing_ = false;
18352      _this2.trigger('change');
18353    });
18354  };
18355
18356  /**
18357   * Add an {@link AudioTrack} to the `AudioTrackList`.
18358   *
18359   * @param {AudioTrack} track
18360   *        The AudioTrack to add to the list
18361   *
18362   * @fires Track#addtrack
18363   */
18364
18365
18366  AudioTrackList.prototype.addTrack = function addTrack(track) {
18367    this.addTrack_(track);
18368  };
18369
18370  /**
18371   * Remove an {@link AudioTrack} from the `AudioTrackList`.
18372   *
18373   * @param {AudioTrack} track
18374   *        The AudioTrack to remove from the list
18375   *
18376   * @fires Track#removetrack
18377   */
18378
18379
18380  AudioTrackList.prototype.removeTrack = function removeTrack(track) {
18381    _TrackList.prototype.removeTrack_.call(this, track);
18382  };
18383
18384  return AudioTrackList;
18385}(_trackList2['default']);
18386
18387exports['default'] = AudioTrackList;
18388
18389},{"74":74,"78":78,"94":94}],64:[function(_dereq_,module,exports){
18390'use strict';
18391
18392exports.__esModule = true;
18393
18394var _trackEnums = _dereq_(73);
18395
18396var _track = _dereq_(75);
18397
18398var _track2 = _interopRequireDefault(_track);
18399
18400var _mergeOptions = _dereq_(87);
18401
18402var _mergeOptions2 = _interopRequireDefault(_mergeOptions);
18403
18404var _browser = _dereq_(78);
18405
18406var browser = _interopRequireWildcard(_browser);
18407
18408function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
18409
18410function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
18411
18412function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
18413
18414function _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; }
18415
18416function _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; }
18417
18418/**
18419 * A representation of a single `AudioTrack`. If it is part of an {@link AudioTrackList}
18420 * only one `AudioTrack` in the list will be enabled at a time.
18421 *
18422 * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotrack}
18423 * @extends Track
18424 */
18425var AudioTrack = function (_Track) {
18426  _inherits(AudioTrack, _Track);
18427
18428  /**
18429   * Create an instance of this class.
18430   *
18431   * @param {Object} [options={}]
18432   *        Object of option names and values
18433   *
18434   * @param {AudioTrack~Kind} [options.kind='']
18435   *        A valid audio track kind
18436   *
18437   * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
18438   *        A unique id for this AudioTrack.
18439   *
18440   * @param {string} [options.label='']
18441   *        The menu label for this track.
18442   *
18443   * @param {string} [options.language='']
18444   *        A valid two character language code.
18445   *
18446   * @param {boolean} [options.enabled]
18447   *        If this track is the one that is currently playing. If this track is part of
18448   *        an {@link AudioTrackList}, only one {@link AudioTrack} will be enabled.
18449   */
18450  function AudioTrack() {
18451    var _this, _ret;
18452
18453    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
18454
18455    _classCallCheck(this, AudioTrack);
18456
18457    var settings = (0, _mergeOptions2['default'])(options, {
18458      kind: _trackEnums.AudioTrackKind[options.kind] || ''
18459    });
18460    // on IE8 this will be a document element
18461    // for every other browser this will be a normal object
18462    var track = (_this = _possibleConstructorReturn(this, _Track.call(this, settings)), _this);
18463    var enabled = false;
18464
18465    if (browser.IS_IE8) {
18466      for (var prop in AudioTrack.prototype) {
18467        if (prop !== 'constructor') {
18468          track[prop] = AudioTrack.prototype[prop];
18469        }
18470      }
18471    }
18472    /**
18473     * @member {boolean} enabled
18474     *         If this `AudioTrack` is enabled or not. When setting this will
18475     *         fire {@link AudioTrack#enabledchange} if the state of enabled is changed.
18476     *
18477     * @fires VideoTrack#selectedchange
18478     */
18479    Object.defineProperty(track, 'enabled', {
18480      get: function get() {
18481        return enabled;
18482      },
18483      set: function set(newEnabled) {
18484        // an invalid or unchanged value
18485        if (typeof newEnabled !== 'boolean' || newEnabled === enabled) {
18486          return;
18487        }
18488        enabled = newEnabled;
18489
18490        /**
18491         * An event that fires when enabled changes on this track. This allows
18492         * the AudioTrackList that holds this track to act accordingly.
18493         *
18494         * > Note: This is not part of the spec! Native tracks will do
18495         *         this internally without an event.
18496         *
18497         * @event AudioTrack#enabledchange
18498         * @type {EventTarget~Event}
18499         */
18500        this.trigger('enabledchange');
18501      }
18502    });
18503
18504    // if the user sets this track to selected then
18505    // set selected to that true value otherwise
18506    // we keep it false
18507    if (settings.enabled) {
18508      track.enabled = settings.enabled;
18509    }
18510    track.loaded_ = true;
18511
18512    return _ret = track, _possibleConstructorReturn(_this, _ret);
18513  }
18514
18515  return AudioTrack;
18516}(_track2['default']);
18517
18518exports['default'] = AudioTrack;
18519
18520},{"73":73,"75":75,"78":78,"87":87}],65:[function(_dereq_,module,exports){
18521'use strict';
18522
18523exports.__esModule = true;
18524
18525var _browser = _dereq_(78);
18526
18527var browser = _interopRequireWildcard(_browser);
18528
18529var _document = _dereq_(94);
18530
18531var _document2 = _interopRequireDefault(_document);
18532
18533function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
18534
18535function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
18536
18537function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /**
18538                                                                                                                                                           * @file html-track-element-list.js
18539                                                                                                                                                           */
18540
18541/**
18542 * The current list of {@link HtmlTrackElement}s.
18543 */
18544var HtmlTrackElementList = function () {
18545
18546  /**
18547   * Create an instance of this class.
18548   *
18549   * @param {HtmlTrackElement[]} [tracks=[]]
18550   *        A list of `HtmlTrackElement` to instantiate the list with.
18551   */
18552  function HtmlTrackElementList() {
18553    var trackElements = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
18554
18555    _classCallCheck(this, HtmlTrackElementList);
18556
18557    var list = this; // eslint-disable-line
18558
18559    if (browser.IS_IE8) {
18560      list = _document2['default'].createElement('custom');
18561
18562      for (var prop in HtmlTrackElementList.prototype) {
18563        if (prop !== 'constructor') {
18564          list[prop] = HtmlTrackElementList.prototype[prop];
18565        }
18566      }
18567    }
18568
18569    list.trackElements_ = [];
18570
18571    /**
18572     * @member {number} length
18573     *         The current number of `Track`s in the this Trackist.
18574     */
18575    Object.defineProperty(list, 'length', {
18576      get: function get() {
18577        return this.trackElements_.length;
18578      }
18579    });
18580
18581    for (var i = 0, length = trackElements.length; i < length; i++) {
18582      list.addTrackElement_(trackElements[i]);
18583    }
18584
18585    if (browser.IS_IE8) {
18586      return list;
18587    }
18588  }
18589
18590  /**
18591   * Add an {@link HtmlTrackElement} to the `HtmlTrackElementList`
18592   *
18593   * @param {HtmlTrackElement} trackElement
18594   *        The track element to add to the list.
18595   *
18596   * @private
18597   */
18598
18599
18600  HtmlTrackElementList.prototype.addTrackElement_ = function addTrackElement_(trackElement) {
18601    var index = this.trackElements_.length;
18602
18603    if (!('' + index in this)) {
18604      Object.defineProperty(this, index, {
18605        get: function get() {
18606          return this.trackElements_[index];
18607        }
18608      });
18609    }
18610
18611    // Do not add duplicate elements
18612    if (this.trackElements_.indexOf(trackElement) === -1) {
18613      this.trackElements_.push(trackElement);
18614    }
18615  };
18616
18617  /**
18618   * Get an {@link HtmlTrackElement} from the `HtmlTrackElementList` given an
18619   * {@link TextTrack}.
18620   *
18621   * @param {TextTrack} track
18622   *        The track associated with a track element.
18623   *
18624   * @return {HtmlTrackElement|undefined}
18625   *         The track element that was found or undefined.
18626   *
18627   * @private
18628   */
18629
18630
18631  HtmlTrackElementList.prototype.getTrackElementByTrack_ = function getTrackElementByTrack_(track) {
18632    var trackElement_ = void 0;
18633
18634    for (var i = 0, length = this.trackElements_.length; i < length; i++) {
18635      if (track === this.trackElements_[i].track) {
18636        trackElement_ = this.trackElements_[i];
18637
18638        break;
18639      }
18640    }
18641
18642    return trackElement_;
18643  };
18644
18645  /**
18646   * Remove a {@link HtmlTrackElement} from the `HtmlTrackElementList`
18647   *
18648   * @param {HtmlTrackElement} trackElement
18649   *        The track element to remove from the list.
18650   *
18651   * @private
18652   */
18653
18654
18655  HtmlTrackElementList.prototype.removeTrackElement_ = function removeTrackElement_(trackElement) {
18656    for (var i = 0, length = this.trackElements_.length; i < length; i++) {
18657      if (trackElement === this.trackElements_[i]) {
18658        this.trackElements_.splice(i, 1);
18659
18660        break;
18661      }
18662    }
18663  };
18664
18665  return HtmlTrackElementList;
18666}();
18667
18668exports['default'] = HtmlTrackElementList;
18669
18670},{"78":78,"94":94}],66:[function(_dereq_,module,exports){
18671'use strict';
18672
18673exports.__esModule = true;
18674
18675var _browser = _dereq_(78);
18676
18677var browser = _interopRequireWildcard(_browser);
18678
18679var _document = _dereq_(94);
18680
18681var _document2 = _interopRequireDefault(_document);
18682
18683var _eventTarget = _dereq_(42);
18684
18685var _eventTarget2 = _interopRequireDefault(_eventTarget);
18686
18687var _textTrack = _dereq_(72);
18688
18689var _textTrack2 = _interopRequireDefault(_textTrack);
18690
18691function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
18692
18693function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
18694
18695function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
18696
18697function _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; }
18698
18699function _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; } /**
18700                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file html-track-element.js
18701                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
18702
18703/**
18704 * @typedef {HTMLTrackElement~ReadyState}
18705 * @enum {number}
18706 */
18707var NONE = 0;
18708var LOADING = 1;
18709var LOADED = 2;
18710var ERROR = 3;
18711
18712/**
18713 * A single track represented in the DOM.
18714 *
18715 * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#htmltrackelement}
18716 * @extends EventTarget
18717 */
18718
18719var HTMLTrackElement = function (_EventTarget) {
18720  _inherits(HTMLTrackElement, _EventTarget);
18721
18722  /**
18723   * Create an instance of this class.
18724   *
18725   * @param {Object} options={}
18726   *        Object of option names and values
18727   *
18728   * @param {Tech} options.tech
18729   *        A reference to the tech that owns this HTMLTrackElement.
18730   *
18731   * @param {TextTrack~Kind} [options.kind='subtitles']
18732   *        A valid text track kind.
18733   *
18734   * @param {TextTrack~Mode} [options.mode='disabled']
18735   *        A valid text track mode.
18736   *
18737   * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
18738   *        A unique id for this TextTrack.
18739   *
18740   * @param {string} [options.label='']
18741   *        The menu label for this track.
18742   *
18743   * @param {string} [options.language='']
18744   *        A valid two character language code.
18745   *
18746   * @param {string} [options.srclang='']
18747   *        A valid two character language code. An alternative, but deprioritized
18748   *        vesion of `options.language`
18749   *
18750   * @param {string} [options.src]
18751   *        A url to TextTrack cues.
18752   *
18753   * @param {boolean} [options.default]
18754   *        If this track should default to on or off.
18755   */
18756  function HTMLTrackElement() {
18757    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
18758
18759    _classCallCheck(this, HTMLTrackElement);
18760
18761    var _this = _possibleConstructorReturn(this, _EventTarget.call(this));
18762
18763    var readyState = void 0;
18764    var trackElement = _this; // eslint-disable-line
18765
18766    if (browser.IS_IE8) {
18767      trackElement = _document2['default'].createElement('custom');
18768
18769      for (var prop in HTMLTrackElement.prototype) {
18770        if (prop !== 'constructor') {
18771          trackElement[prop] = HTMLTrackElement.prototype[prop];
18772        }
18773      }
18774    }
18775
18776    var track = new _textTrack2['default'](options);
18777
18778    trackElement.kind = track.kind;
18779    trackElement.src = track.src;
18780    trackElement.srclang = track.language;
18781    trackElement.label = track.label;
18782    trackElement['default'] = track['default'];
18783
18784    /**
18785     * @member {HTMLTrackElement~ReadyState} readyState
18786     *         The current ready state of the track element.
18787     */
18788    Object.defineProperty(trackElement, 'readyState', {
18789      get: function get() {
18790        return readyState;
18791      }
18792    });
18793
18794    /**
18795     * @member {TextTrack} track
18796     *         The underlying TextTrack object.
18797     */
18798    Object.defineProperty(trackElement, 'track', {
18799      get: function get() {
18800        return track;
18801      }
18802    });
18803
18804    readyState = NONE;
18805
18806    /**
18807     * @listens TextTrack#loadeddata
18808     * @fires HTMLTrackElement#load
18809     */
18810    track.addEventListener('loadeddata', function () {
18811      readyState = LOADED;
18812
18813      trackElement.trigger({
18814        type: 'load',
18815        target: trackElement
18816      });
18817    });
18818
18819    if (browser.IS_IE8) {
18820      var _ret;
18821
18822      return _ret = trackElement, _possibleConstructorReturn(_this, _ret);
18823    }
18824    return _this;
18825  }
18826
18827  return HTMLTrackElement;
18828}(_eventTarget2['default']);
18829
18830HTMLTrackElement.prototype.allowedEvents_ = {
18831  load: 'load'
18832};
18833
18834HTMLTrackElement.NONE = NONE;
18835HTMLTrackElement.LOADING = LOADING;
18836HTMLTrackElement.LOADED = LOADED;
18837HTMLTrackElement.ERROR = ERROR;
18838
18839exports['default'] = HTMLTrackElement;
18840
18841},{"42":42,"72":72,"78":78,"94":94}],67:[function(_dereq_,module,exports){
18842'use strict';
18843
18844exports.__esModule = true;
18845
18846var _browser = _dereq_(78);
18847
18848var browser = _interopRequireWildcard(_browser);
18849
18850var _document = _dereq_(94);
18851
18852var _document2 = _interopRequireDefault(_document);
18853
18854function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
18855
18856function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
18857
18858function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /**
18859                                                                                                                                                           * @file text-track-cue-list.js
18860                                                                                                                                                           */
18861
18862
18863/**
18864 * @typedef {Object} TextTrackCue
18865 *
18866 * @property {string} id
18867 *           The unique id for this text track cue
18868 *
18869 * @property {number} startTime
18870 *           The start time for this text track cue
18871 *
18872 * @property {number} endTime
18873 *           The end time for this text track cue
18874 *
18875 * @property {boolean} pauseOnExit
18876 *           Pause when the end time is reached if true.
18877 *
18878 * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcue}
18879 */
18880
18881/**
18882 * A List of TextTrackCues.
18883 *
18884 * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist}
18885 */
18886var TextTrackCueList = function () {
18887
18888  /**
18889   * Create an instance of this class..
18890   *
18891   * @param {Array} cues
18892   *        A list of cues to be initialized with
18893   */
18894  function TextTrackCueList(cues) {
18895    _classCallCheck(this, TextTrackCueList);
18896
18897    var list = this; // eslint-disable-line
18898
18899    if (browser.IS_IE8) {
18900      list = _document2['default'].createElement('custom');
18901
18902      for (var prop in TextTrackCueList.prototype) {
18903        if (prop !== 'constructor') {
18904          list[prop] = TextTrackCueList.prototype[prop];
18905        }
18906      }
18907    }
18908
18909    TextTrackCueList.prototype.setCues_.call(list, cues);
18910
18911    /**
18912     * @member {number} length
18913     *         The current number of `TextTrackCue`s in the TextTrackCueList.
18914     */
18915    Object.defineProperty(list, 'length', {
18916      get: function get() {
18917        return this.length_;
18918      }
18919    });
18920
18921    if (browser.IS_IE8) {
18922      return list;
18923    }
18924  }
18925
18926  /**
18927   * A setter for cues in this list. Creates getters
18928   * an an index for the cues.
18929   *
18930   * @param {Array} cues
18931   *        An array of cues to set
18932   *
18933   * @private
18934   */
18935
18936
18937  TextTrackCueList.prototype.setCues_ = function setCues_(cues) {
18938    var oldLength = this.length || 0;
18939    var i = 0;
18940    var l = cues.length;
18941
18942    this.cues_ = cues;
18943    this.length_ = cues.length;
18944
18945    var defineProp = function defineProp(index) {
18946      if (!('' + index in this)) {
18947        Object.defineProperty(this, '' + index, {
18948          get: function get() {
18949            return this.cues_[index];
18950          }
18951        });
18952      }
18953    };
18954
18955    if (oldLength < l) {
18956      i = oldLength;
18957
18958      for (; i < l; i++) {
18959        defineProp.call(this, i);
18960      }
18961    }
18962  };
18963
18964  /**
18965   * Get a `TextTrackCue` that is currently in the `TextTrackCueList` by id.
18966   *
18967   * @param {string} id
18968   *        The id of the cue that should be searched for.
18969   *
18970   * @return {TextTrackCue|null}
18971   *         A single cue or null if none was found.
18972   */
18973
18974
18975  TextTrackCueList.prototype.getCueById = function getCueById(id) {
18976    var result = null;
18977
18978    for (var i = 0, l = this.length; i < l; i++) {
18979      var cue = this[i];
18980
18981      if (cue.id === id) {
18982        result = cue;
18983        break;
18984      }
18985    }
18986
18987    return result;
18988  };
18989
18990  return TextTrackCueList;
18991}();
18992
18993exports['default'] = TextTrackCueList;
18994
18995},{"78":78,"94":94}],68:[function(_dereq_,module,exports){
18996'use strict';
18997
18998exports.__esModule = true;
18999
19000var _component = _dereq_(5);
19001
19002var _component2 = _interopRequireDefault(_component);
19003
19004var _fn = _dereq_(83);
19005
19006var Fn = _interopRequireWildcard(_fn);
19007
19008var _window = _dereq_(95);
19009
19010var _window2 = _interopRequireDefault(_window);
19011
19012function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
19013
19014function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
19015
19016function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
19017
19018function _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; }
19019
19020function _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, { c
19020onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
19021                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file text-track-display.js
19022                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
19023
19024
19025var darkGray = '#222';
19026var lightGray = '#ccc';
19027var fontMap = {
19028  monospace: 'monospace',
19029  sansSerif: 'sans-serif',
19030  serif: 'serif',
19031  monospaceSansSerif: '"Andale Mono", "Lucida Console", monospace',
19032  monospaceSerif: '"Courier New", monospace',
19033  proportionalSansSerif: 'sans-serif',
19034  proportionalSerif: 'serif',
19035  casual: '"Comic Sans MS", Impact, fantasy',
19036  script: '"Monotype Corsiva", cursive',
19037  smallcaps: '"Andale Mono", "Lucida Console", monospace, sans-serif'
19038};
19039
19040/**
19041 * Construct an rgba color from a given hex color code.
19042 *
19043 * @param {number} color
19044 *        Hex number for color, like #f0e.
19045 *
19046 * @param {number} opacity
19047 *        Value for opacity, 0.0 - 1.0.
19048 *
19049 * @return {string}
19050 *         The rgba color that was created, like 'rgba(255, 0, 0, 0.3)'.
19051 *
19052 * @private
19053 */
19054function constructColor(color, opacity) {
19055  return 'rgba(' +
19056  // color looks like "#f0e"
19057  parseInt(color[1] + color[1], 16) + ',' + parseInt(color[2] + color[2], 16) + ',' + parseInt(color[3] + color[3], 16) + ',' + opacity + ')';
19058}
19059
19060/**
19061 * Try to update the style of a DOM element. Some style changes will throw an error,
19062 * particularly in IE8. Those should be noops.
19063 *
19064 * @param {Element} el
19065 *        The DOM element to be styled.
19066 *
19067 * @param {string} style
19068 *        The CSS property on the element that should be styled.
19069 *
19070 * @param {string} rule
19071 *        The style rule that should be applied to the property.
19072 */
19073function tryUpdateStyle(el, style, rule) {
19074  try {
19075    el.style[style] = rule;
19076  } catch (e) {
19077
19078    // Satisfies linter.
19079    return;
19080  }
19081}
19082
19083/**
19084 * The component for displaying text track cues.
19085 *
19086 * @extends Component
19087 */
19088
19089var TextTrackDisplay = function (_Component) {
19090  _inherits(TextTrackDisplay, _Component);
19091
19092  /**
19093   * Creates an instance of this class.
19094   *
19095   * @param {Player} player
19096   *        The `Player` that this class should be attached to.
19097   *
19098   * @param {Object} [options]
19099   *        The key/value store of player options.
19100   *
19101   * @param {Component~ReadyCallback} [ready]
19102   *        The function to call when `TextTrackDisplay` is ready.
19103   */
19104  function TextTrackDisplay(player, options, ready) {
19105    _classCallCheck(this, TextTrackDisplay);
19106
19107    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options, ready));
19108
19109    player.on('loadstart', Fn.bind(_this, _this.toggleDisplay));
19110    player.on('texttrackchange', Fn.bind(_this, _this.updateDisplay));
19111
19112    // This used to be called during player init, but was causing an error
19113    // if a track should show by default and the display hadn't loaded yet.
19114    // Should probably be moved to an external track loader when we support
19115    // tracks that don't need a display.
19116    player.ready(Fn.bind(_this, function () {
19117      if (player.tech_ && player.tech_.featuresNativeTextTracks) {
19118        this.hide();
19119        return;
19120      }
19121
19122      player.on('fullscreenchange', Fn.bind(this, this.updateDisplay));
19123
19124      var tracks = this.options_.playerOptions.tracks || [];
19125
19126      for (var i = 0; i < tracks.length; i++) {
19127        this.player_.addRemoteTextTrack(tracks[i], true);
19128      }
19129
19130      var modes = { captions: 1, subtitles: 1 };
19131      var trackList = this.player_.textTracks();
19132      var firstDesc = void 0;
19133      var firstCaptions = void 0;
19134
19135      if (trackList) {
19136        for (var _i = 0; _i < trackList.length; _i++) {
19137          var track = trackList[_i];
19138
19139          if (track['default']) {
19140            if (track.kind === 'descriptions' && !firstDesc) {
19141              firstDesc = track;
19142            } else if (track.kind in modes && !firstCaptions) {
19143              firstCaptions = track;
19144            }
19145          }
19146        }
19147
19148        // We want to show the first default track but captions and subtitles
19149        // take precedence over descriptions.
19150        // So, display the first default captions or subtitles track
19151        // and otherwise the first default descriptions track.
19152        if (firstCaptions) {
19153          firstCaptions.mode = 'showing';
19154        } else if (firstDesc) {
19155          firstDesc.mode = 'showing';
19156        }
19157      }
19158    }));
19159    return _this;
19160  }
19161
19162  /**
19163   * Turn display of {@link TextTrack}'s from the current state into the other state.
19164   * There are only two states:
19165   * - 'shown'
19166   * - 'hidden'
19167   *
19168   * @listens Player#loadstart
19169   */
19170
19171
19172  TextTrackDisplay.prototype.toggleDisplay = function toggleDisplay() {
19173    if (this.player_.tech_ && this.player_.tech_.featuresNativeTextTracks) {
19174      this.hide();
19175    } else {
19176      this.show();
19177    }
19178  };
19179
19180  /**
19181   * Create the {@link Component}'s DOM element.
19182   *
19183   * @return {Element}
19184   *         The element that was created.
19185   */
19186
19187
19188  TextTrackDisplay.prototype.createEl = function createEl() {
19189    return _Component.prototype.createEl.call(this, 'div', {
19190      className: 'vjs-text-track-display'
19191    }, {
19192      'aria-live': 'off',
19193      'aria-atomic': 'true'
19194    });
19195  };
19196
19197  /**
19198   * Clear all displayed {@link TextTrack}s.
19199   */
19200
19201
19202  TextTrackDisplay.prototype.clearDisplay = function clearDisplay() {
19203    if (typeof _window2['default'].WebVTT === 'function') {
19204      _window2['default'].WebVTT.processCues(_window2['default'], [], this.el_);
19205    }
19206  };
19207
19208  /**
19209   * Update the displayed TextTrack when a either a {@link Player#texttrackchange} or
19210   * a {@link Player#fullscreenchange} is fired.
19211   *
19212   * @listens Player#texttrackchange
19213   * @listens Player#fullscreenchange
19214   */
19215
19216
19217  TextTrackDisplay.prototype.updateDisplay = function updateDisplay() {
19218    var tracks = this.player_.textTracks();
19219
19220    this.clearDisplay();
19221
19222    if (!tracks) {
19223      return;
19224    }
19225
19226    // Track display prioritization model: if multiple tracks are 'showing',
19227    //  display the first 'subtitles' or 'captions' track which is 'showing',
19228    //  otherwise display the first 'descriptions' track which is 'showing'
19229
19230    var descriptionsTrack = null;
19231    var captionsSubtitlesTrack = null;
19232
19233    var i = tracks.length;
19234
19235    while (i--) {
19236      var track = tracks[i];
19237
19238      if (track.mode === 'showing') {
19239        if (track.kind === 'descriptions') {
19240          descriptionsTrack = track;
19241        } else {
19242          captionsSubtitlesTrack = track;
19243        }
19244      }
19245    }
19246
19247    if (captionsSubtitlesTrack) {
19248      if (this.getAttribute('aria-live') !== 'off') {
19249        this.setAttribute('aria-live', 'off');
19250      }
19251      this.updateForTrack(captionsSubtitlesTrack);
19252    } else if (descriptionsTrack) {
19253      if (this.getAttribute('aria-live') !== 'assertive') {
19254        this.setAttribute('aria-live', 'assertive');
19255      }
19256      this.updateForTrack(descriptionsTrack);
19257    }
19258  };
19259
19260  /**
19261   * Add an {@link Texttrack} to to the {@link Tech}s {@link TextTrackList}.
19262   *
19263   * @param {TextTrack} track
19264   *        Text track object to be added to the list.
19265   */
19266
19267
19268  TextTrackDisplay.prototype.updateForTrack = function updateForTrack(track) {
19269    if (typeof _window2['default'].WebVTT !== 'function' || !track.activeCues) {
19270      return;
19271    }
19272
19273    var overrides = this.player_.textTrackSettings.getValues();
19274    var cues = [];
19275
19276    for (var _i2 = 0; _i2 < track.activeCues.length; _i2++) {
19277      cues.push(track.activeCues[_i2]);
19278    }
19279
19280    _window2['default'].WebVTT.processCues(_window2['default'], cues, this.el_);
19281
19282    var i = cues.length;
19283
19284    while (i--) {
19285      var cue = cues[i];
19286
19287      if (!cue) {
19288        continue;
19289      }
19290
19291      var cueDiv = cue.displayState;
19292
19293      if (overrides.color) {
19294        cueDiv.firstChild.style.color = overrides.color;
19295      }
19296      if (overrides.textOpacity) {
19297        tryUpdateStyle(cueDiv.firstChild, 'color', constructColor(overrides.color || '#fff', overrides.textOpacity));
19298      }
19299      if (overrides.backgroundColor) {
19300        cueDiv.firstChild.style.backgroundColor = overrides.backgroundColor;
19301      }
19302      if (overrides.backgroundOpacity) {
19303        tryUpdateStyle(cueDiv.firstChild, 'backgroundColor', constructColor(overrides.backgroundColor || '#000', overrides.backgroundOpacity));
19304      }
19305      if (overrides.windowColor) {
19306        if (overrides.windowOpacity) {
19307          tryUpdateStyle(cueDiv, 'backgroundColor', constructColor(overrides.windowColor, overrides.windowOpacity));
19308        } else {
19309          cueDiv.style.backgroundColor = overrides.windowColor;
19310        }
19311      }
19312      if (overrides.edgeStyle) {
19313        if (overrides.edgeStyle === 'dropshadow') {
19314          cueDiv.firstChild.style.textShadow = '2px 2px 3px ' + darkGray + ', 2px 2px 4px ' + darkGray + ', 2px 2px 5px ' + darkGray;
19315        } else if (overrides.edgeStyle === 'raised') {
19316          cueDiv.firstChild.style.textShadow = '1px 1px ' + darkGray + ', 2px 2px ' + darkGray + ', 3px 3px ' + darkGray;
19317        } else if (overrides.edgeStyle === 'depressed') {
19318          cueDiv.firstChild.style.textShadow = '1px 1px ' + lightGray + ', 0 1px ' + lightGray + ', -1px -1px ' + darkGray + ', 0 -1px ' + darkGray;
19319        } else if (overrides.edgeStyle === 'uniform') {
19320          cueDiv.firstChild.style.textShadow = '0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray;
19321        }
19322      }
19323      if (overrides.fontPercent && overrides.fontPercent !== 1) {
19324        var fontSize = _window2['default'].parseFloat(cueDiv.style.fontSize);
19325
19326        cueDiv.style.fontSize = fontSize * overrides.fontPercent + 'px';
19327        cueDiv.style.height = 'auto';
19328        cueDiv.style.top = 'auto';
19329        cueDiv.style.bottom = '2px';
19330      }
19331      if (overrides.fontFamily && overrides.fontFamily !== 'default') {
19332        if (overrides.fontFamily === 'small-caps') {
19333          cueDiv.firstChild.style.fontVariant = 'small-caps';
19334        } else {
19335          cueDiv.firstChild.style.fontFamily = fontMap[overrides.fontFamily];
19336        }
19337      }
19338    }
19339  };
19340
19341  return TextTrackDisplay;
19342}(_component2['default']);
19343
19344_component2['default'].registerComponent('TextTrackDisplay', TextTrackDisplay);
19345exports['default'] = TextTrackDisplay;
19346
19347},{"5":5,"83":83,"95":95}],69:[function(_dereq_,module,exports){
19348'use strict';
19349
19350exports.__esModule = true;
19351/**
19352 * @file text-track-list-converter.js Utilities for capturing text track state and
19353 * re-creating tracks based on a capture.
19354 *
19355 * @module text-track-list-converter
19356 */
19357
19358/**
19359 * Examine a single {@link TextTrack} and return a JSON-compatible javascript object that
19360 * represents the {@link TextTrack}'s state.
19361 *
19362 * @param {TextTrack} track
19363 *        The text track to query.
19364 *
19365 * @return {Object}
19366 *         A serializable javascript representation of the TextTrack.
19367 * @private
19368 */
19369var trackToJson_ = function trackToJson_(track) {
19370  var ret = ['kind', 'label', 'language', 'id', 'inBandMetadataTrackDispatchType', 'mode', 'src'].reduce(function (acc, prop, i) {
19371
19372    if (track[prop]) {
19373      acc[prop] = track[prop];
19374    }
19375
19376    return acc;
19377  }, {
19378    cues: track.cues && Array.prototype.map.call(track.cues, function (cue) {
19379      return {
19380        startTime: cue.startTime,
19381        endTime: cue.endTime,
19382        text: cue.text,
19383        id: cue.id
19384      };
19385    })
19386  });
19387
19388  return ret;
19389};
19390
19391/**
19392 * Examine a {@link Tech} and return a JSON-compatible javascript array that represents the
19393 * state of all {@link TextTrack}s currently configured. The return array is compatible with
19394 * {@link text-track-list-converter:jsonToTextTracks}.
19395 *
19396 * @param {Tech} tech
19397 *        The tech object to query
19398 *
19399 * @return {Array}
19400 *         A serializable javascript representation of the {@link Tech}s
19401 *         {@link TextTrackList}.
19402 */
19403var textTracksToJson = function textTracksToJson(tech) {
19404
19405  var trackEls = tech.$$('track');
19406
19407  var trackObjs = Array.prototype.map.call(trackEls, function (t) {
19408    return t.track;
19409  });
19410  var tracks = Array.prototype.map.call(trackEls, function (trackEl) {
19411    var json = trackToJson_(trackEl.track);
19412
19413    if (trackEl.src) {
19414      json.src = trackEl.src;
19415    }
19416    return json;
19417  });
19418
19419  return tracks.concat(Array.prototype.filter.call(tech.textTracks(), function (track) {
19420    return trackObjs.indexOf(track) === -1;
19421  }).map(trackToJson_));
19422};
19423
19424/**
19425 * Create a set of remote {@link TextTrack}s on a {@link Tech} based on an array of javascript
19426 * object {@link TextTrack} representations.
19427 *
19428 * @param {Array} json
19429 *        An array of `TextTrack` representation objects, like those that would be
19430 *        produced by `textTracksToJson`.
19431 *
19432 * @param {Tech} tech
19433 *        The `Tech` to create the `TextTrack`s on.
19434 */
19435var jsonToTextTracks = function jsonToTextTracks(json, tech) {
19436  json.forEach(function (track) {
19437    var addedTrack = tech.addRemoteTextTrack(track).track;
19438
19439    if (!track.src && track.cues) {
19440      track.cues.forEach(function (cue) {
19441        return addedTrack.addCue(cue);
19442      });
19443    }
19444  });
19445
19446  return tech.textTracks();
19447};
19448
19449exports['default'] = { textTracksToJson: textTracksToJson, jsonToTextTracks: jsonToTextTracks, trackToJson_: trackToJson_ };
19450
19451},{}],70:[function(_dereq_,module,exports){
19452'use strict';
19453
19454exports.__esModule = true;
19455
19456var _trackList = _dereq_(74);
19457
19458var _trackList2 = _interopRequireDefault(_trackList);
19459
19460var _fn = _dereq_(83);
19461
19462var Fn = _interopRequireWildcard(_fn);
19463
19464var _browser = _dereq_(78);
19465
19466var browser = _interopRequireWildcard(_browser);
19467
19468var _document = _dereq_(94);
19469
19470var _document2 = _interopRequireDefault(_document);
19471
19472function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
19473
19474function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
19475
19476function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
19477
19478function _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; }
19479
19480function _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; } /**
19481                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file text-track-list.js
19482                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
19483
19484
19485/**
19486 * The current list of {@link TextTrack} for a media file.
19487 *
19488 * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist}
19489 * @extends TrackList
19490 */
19491var TextTrackList = function (_TrackList) {
19492  _inherits(TextTrackList, _TrackList);
19493
19494  /**
19495   * Create an instance of this class.
19496   *
19497   * @param {TextTrack[]} [tracks=[]]
19498   *        A list of `TextTrack` to instantiate the list with.
19499   */
19500  function TextTrackList() {
19501    var _this, _ret;
19502
19503    var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
19504
19505    _classCallCheck(this, TextTrackList);
19506
19507    var list = void 0;
19508
19509    // IE8 forces us to implement inheritance ourselves
19510    // as it does not support Object.defineProperty properly
19511    if (browser.IS_IE8) {
19512      list = _document2['default'].createElement('custom');
19513      for (var prop in _trackList2['default'].prototype) {
19514        if (prop !== 'constructor') {
19515          list[prop] = _trackList2['default'].prototype[prop];
19516        }
19517      }
19518      for (var _prop in TextTrackList.prototype) {
19519        if (_prop !== 'constructor') {
19520          list[_prop] = TextTrackList.prototype[_prop];
19521        }
19522      }
19523    }
19524
19525    list = (_this = _possibleConstructorReturn(this, _TrackList.call(this, tracks, list)), _this);
19526    return _ret = list, _possibleConstructorReturn(_this, _ret);
19527  }
19528
19529  /**
19530   * Add a {@link TextTrack} to the `TextTrackList`
19531   *
19532   * @param {TextTrack} track
19533   *        The text track to add to the list.
19534   *
19535   * @fires TrackList#addtrack
19536   * @private
19537   */
19538
19539
19540  TextTrackList.prototype.addTrack_ = function addTrack_(track) {
19541    _TrackList.prototype.addTrack_.call(this, track);
19542
19543    /**
19544     * @listens TextTrack#modechange
19545     * @fires TrackList#change
19546     */
19547    track.addEventListener('modechange', Fn.bind(this, function () {
19548      this.trigger('change');
19549    }));
19550  };
19551
19552  return TextTrackList;
19553}(_trackList2['default']);
19554
19555exports['default'] = TextTrackList;
19556
19557},{"74":74,"78":78,"83":83,"94":94}],71:[function(_dereq_,module,exports){
19558'use strict';
19559
19560exports.__esModule = true;
19561
19562var _window = _dereq_(95);
19563
19564var _window2 = _interopRequireDefault(_window);
19565
19566var _component = _dereq_(5);
19567
19568var _component2 = _interopRequireDefault(_component);
19569
19570var _dom = _dereq_(81);
19571
19572var _fn = _dereq_(83);
19573
19574var Fn = _interopRequireWildcard(_fn);
19575
19576var _obj = _dereq_(88);
19577
19578var Obj = _interopRequireWildcard(_obj);
19579
19580var _log = _dereq_(86);
19581
19582var _log2 = _interopRequireDefault(_log);
19583
19584function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
19585
19586function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
19587
19588function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
19589
19590function _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; }
19591
19592function _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; } /**
19593                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file text-track-settings.js
19594                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
19595
19596
19597var LOCAL_STORAGE_KEY = 'vjs-text-track-settings';
19598
19599var COLOR_BLACK = ['#000', 'Black'];
19600var COLOR_BLUE = ['#00F', 'Blue'];
19601var COLOR_CYAN = ['#0FF', 'Cyan'];
19602var COLOR_GREEN = ['#0F0', 'Green'];
19603var COLOR_MAGENTA = ['#F0F', 'Magenta'];
19604var COLOR_RED = ['#F00', 'Red'];
19605var COLOR_WHITE = ['#FFF', 'White'];
19606var COLOR_YELLOW = ['#FF0', 'Yellow'];
19607
19608var OPACITY_OPAQUE = ['1', 'Opaque'];
19609var OPACITY_SEMI = ['0.5', 'Semi-Transparent'];
19610var OPACITY_TRANS = ['0', 'Transparent'];
19611
19612// Configuration for the various <select> elements in the DOM of this component.
19613//
19614// Possible keys include:
19615//
19616// `default`:
19617//   The default option index. Only needs to be provided if not zero.
19618// `parser`:
19619//   A function which is used to parse the value from the selected option in
19620//   a customized way.
19621// `selector`:
19622//   The selector used to find the associated <select> element.
19623var selectConfigs = {
19624  backgroundColor: {
19625    selector: '.vjs-bg-color > select',
19626    id: 'captions-background-color-%s',
19627    label: 'Color',
19628    options: [COLOR_BLACK, COLOR_WHITE, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_YELLOW, COLOR_MAGENTA, COLOR_CYAN]
19629  },
19630
19631  backgroundOpacity: {
19632    selector: '.vjs-bg-opacity > select',
19633    id: 'captions-background-opacity-%s',
19634    label: 'Transparency',
19635    options: [OPACITY_OPAQUE, OPACITY_SEMI, OPACITY_TRANS]
19636  },
19637
19638  color: {
19639    selector: '.vjs-fg-color > select',
19640    id: 'captions-foreground-color-%s',
19641    label: 'Color',
19642    options: [COLOR_WHITE, COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_YELLOW, COLOR_MAGENTA, COLOR_CYAN]
19643  },
19644
19645  edgeStyle: {
19646    selector: '.vjs-edge-style > select',
19647    id: '%s',
19648    label: 'Text Edge Style',
19649    options: [['none', 'None'], ['raised', 'Raised'], ['depressed', 'Depressed'], ['uniform', 'Uniform'], ['dropshadow', 'Dropshadow']]
19650  },
19651
19652  fontFamily: {
19653    selector: '.vjs-font-family > select',
19654    id: 'captions-font-family-%s',
19655    label: 'Font Family',
19656    options: [['proportionalSansSerif', 'Proportional Sans-Serif'], ['monospaceSansSerif', 'Monospace Sans-Serif'], ['proportionalSerif', 'Proportional Serif'], ['monospaceSerif', 'Monospace Serif'], ['casual', 'Casual'], ['script', 'Script'], ['small-caps', '
vendor: 4,800 bytes, lines 19656-19845
19656Small Caps']]
19657  },
19658
19659  fontPercent: {
19660    selector: '.vjs-font-percent > select',
19661    id: 'captions-font-size-%s',
19662    label: 'Font Size',
19663    options: [['0.50', '50%'], ['0.75', '75%'], ['1.00', '100%'], ['1.25', '125%'], ['1.50', '150%'], ['1.75', '175%'], ['2.00', '200%'], ['3.00', '300%'], ['4.00', '400%']],
19664    'default': 2,
19665    parser: function parser(v) {
19666      return v === '1.00' ? null : Number(v);
19667    }
19668  },
19669
19670  textOpacity: {
19671    selector: '.vjs-text-opacity > select',
19672    id: 'captions-foreground-opacity-%s',
19673    label: 'Transparency',
19674    options: [OPACITY_OPAQUE, OPACITY_SEMI]
19675  },
19676
19677  // Options for this object are defined below.
19678  windowColor: {
19679    selector: '.vjs-window-color > select',
19680    id: 'captions-window-color-%s',
19681    label: 'Color'
19682  },
19683
19684  // Options for this object are defined below.
19685  windowOpacity: {
19686    selector: '.vjs-window-opacity > select',
19687    id: 'captions-window-opacity-%s',
19688    label: 'Transparency',
19689    options: [OPACITY_TRANS, OPACITY_SEMI, OPACITY_OPAQUE]
19690  }
19691};
19692
19693selectConfigs.windowColor.options = selectConfigs.backgroundColor.options;
19694
19695/**
19696 * Get the actual value of an option.
19697 *
19698 * @param  {string} value
19699 *         The value to get
19700 *
19701 * @param  {Function} [parser]
19702 *         Optional function to adjust the value.
19703 *
19704 * @return {Mixed}
19705 *         - Will be `undefined` if no value exists
19706 *         - Will be `undefined` if the given value is "none".
19707 *         - Will be the actual value otherwise.
19708 *
19709 * @private
19710 */
19711function parseOptionValue(value, parser) {
19712  if (parser) {
19713    value = parser(value);
19714  }
19715
19716  if (value && value !== 'none') {
19717    return value;
19718  }
19719}
19720
19721/**
19722 * Gets the value of the selected <option> element within a <select> element.
19723 *
19724 * @param  {Element} el
19725 *         the element to look in
19726 *
19727 * @param  {Function} [parser]
19728 *         Optional function to adjust the value.
19729 *
19730 * @return {Mixed}
19731 *         - Will be `undefined` if no value exists
19732 *         - Will be `undefined` if the given value is "none".
19733 *         - Will be the actual value otherwise.
19734 *
19735 * @private
19736 */
19737function getSelectedOptionValue(el, parser) {
19738  var value = el.options[el.options.selectedIndex].value;
19739
19740  return parseOptionValue(value, parser);
19741}
19742
19743/**
19744 * Sets the selected <option> element within a <select> element based on a
19745 * given value.
19746 *
19747 * @param {Element} el
19748 *        The element to look in.
19749 *
19750 * @param {string} value
19751 *        the property to look on.
19752 *
19753 * @param {Function} [parser]
19754 *        Optional function to adjust the value before comparing.
19755 *
19756 * @private
19757 */
19758function setSelectedOption(el, value, parser) {
19759  if (!value) {
19760    return;
19761  }
19762
19763  for (var i = 0; i < el.options.length; i++) {
19764    if (parseOptionValue(el.options[i].value, parser) === value) {
19765      el.selectedIndex = i;
19766      break;
19767    }
19768  }
19769}
19770
19771/**
19772 * Manipulate Text Tracks settings.
19773 *
19774 * @extends Component
19775 */
19776
19777var TextTrackSettings = function (_Component) {
19778  _inherits(TextTrackSettings, _Component);
19779
19780  /**
19781   * Creates an instance of this class.
19782   *
19783   * @param {Player} player
19784   *         The `Player` that this class should be attached to.
19785   *
19786   * @param {Object} [options]
19787   *         The key/value store of player options.
19788   */
19789  function TextTrackSettings(player, options) {
19790    _classCallCheck(this, TextTrackSettings);
19791
19792    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
19793
19794    _this.setDefaults();
19795    _this.hide();
19796
19797    _this.updateDisplay = Fn.bind(_this, _this.updateDisplay);
19798
19799    // Grab `persistTextTrackSettings` from the player options if not passed in child options
19800    if (options.persistTextTrackSettings === undefined) {
19801      _this.options_.persistTextTrackSettings = _this.options_.playerOptions.persistTextTrackSettings;
19802    }
19803
19804    _this.on(_this.$('.vjs-done-button'), 'click', function () {
19805      _this.saveSettings();
19806      _this.hide();
19807    });
19808
19809    _this.on(_this.$('.vjs-default-button'), 'click', function () {
19810      _this.setDefaults();
19811      _this.updateDisplay();
19812    });
19813
19814    Obj.each(selectConfigs, function (config) {
19815      _this.on(_this.$(config.selector), 'change', _this.updateDisplay);
19816    });
19817
19818    if (_this.options_.persistTextTrackSettings) {
19819      _this.restoreSettings();
19820    }
19821    return _this;
19822  }
19823
19824  /**
19825   * Create a <select> element with configured options.
19826   *
19827   * @param {string} key
19828   *        Configuration key to use during creation.
19829   *
19830   * @return {Element}
19831   *         The DOM element that gets created.
19832   * @private
19833   */
19834
19835
19836  TextTrackSettings.prototype.createElSelect_ = function createElSelect_(key) {
19837    var _this2 = this;
19838
19839    var config = selectConfigs[key];
19840    var id = config.id.replace('%s', this.id_);
19841
19842    return [(0, _dom.createEl)('label', {
19843      className: 'vjs-label',
19844      textContent: config.label
19845    }, {
19846      'for': id
19847    }), (0, _dom.createEl)('select', { id: id }, undefined, config.options.map(function (o) {
19848      return (0, _dom.createEl)('option', {
19849        textContent: _this2.localize(o[1]),
19850        value: o[0]
19851      });
19852    }))];
19853  };
19854
19855  /**
19856   * Create foreground color element for the component
19857   *
19858   * @return {Element}
19859   *         The element that was created.
19860   *
19861   * @private
19862   */
19863
19864
19865  TextTrackSettings.prototype.createElFgColor_ = function createElFgColor_() {
19866    var legend = (0, _dom.createEl)('legend', {
19867      textContent: this.localize('Text')
19868    });
19869
19870    var select = this.createElSelect_('color');
19871
19872    var opacity = (0, _dom.createEl)('span', {
19873      className: 'vjs-text-opacity vjs-opacity'
19874    }, undefined, this.createElSelect_('textOpacity'));
19875
19876    return (0, _dom.createEl)('fieldset', {
19877      className: 'vjs-fg-color vjs-tracksetting'
19878    }, undefined, [legend].concat(select, opacity));
19879  };
19880
19881  /**
19882   * Create background color element for the component
19883   *
19884   * @return {Element}
19885   *         The element that was created
19886   *
19887   * @private
19888   */
19889
19890
19891  TextTrackSettings.prototype.createElBgColor_ = function createElBgColor_() {
19892    var legend = (0, _dom.createEl)('legend', {
19893      textContent: this.localize('Background')
19894    });
19895
19896    var select = this.createElSelect_('backgroundColor');
19897
19898    var opacity = (0, _dom.createEl)('span', {
19899      className: 'vjs-bg-opacity vjs-opacity'
19900    }, undefined, this.createElSelect_('backgroundOpacity'));
19901
19902    return (0, _dom.createEl)('fieldset', {
19903      className: 'vjs-bg-color vjs-tracksetting'
19904    }, undefined, [legend].concat(select, opacity));
19905  };
19906
19907  /**
19908   * Create window color element for the component
19909   *
19910   * @return {Element}
19911   *         The element that was created
19912   *
19913   * @private
19914   */
19915
19916
19917  TextTrackSettings.prototype.createElWinColor_ = function createElWinColor_() {
19918    var legend = (0, _dom.createEl)('legend', {
19919      textContent: this.localize('Window')
19920    });
19921
19922    var select = this.createElSelect_('windowColor');
19923
19924    var opacity = (0, _dom.createEl)('span', {
19925      className: 'vjs-window-opacity vjs-opacity'
19926    }, undefined, this.createElSelect_('windowOpacity'));
19927
19928    return (0, _dom.createEl)('fieldset', {
19929      className: 'vjs-window-color vjs-tracksetting'
19930    }, undefined, [legend].concat(select, opacity));
19931  };
19932
19933  /**
19934   * Create color elements for the component
19935   *
19936   * @return {Element}
19937   *         The element that was created
19938   *
19939   * @private
19940   */
19941
19942
19943  TextTrackSettings.prototype.createElColors_ = function createElColors_() {
19944    return (0, _dom.createEl)('div', {
19945      className: 'vjs-tracksettings-colors'
19946    }, undefined, [this.createElFgColor_(), this.createElBgColor_(), this.createElWinColor_()]);
19947  };
19948
19949  /**
19950   * Create font elements for the component
19951   *
19952   * @return {Element}
19953   *         The element that was created.
19954   *
19955   * @private
19956   */
19957
19958
19959  TextTrackSettings.prototype.createElFont_ = function createElFont_() {
19960    var fontPercent = (0, _dom.createEl)('div', {
19961      className: 'vjs-font-percent vjs-tracksetting'
19962    }, undefined, this.createElSelect_('fontPercent'));
19963
19964    var edgeStyle = (0, _dom.createEl)('div', {
19965      className: 'vjs-edge-style vjs-tracksetting'
19966    }, undefined, this.createElSelect_('edgeStyle'));
19967
19968    var fontFamily = (0, _dom.createEl)('div', {
19969      className: 'vjs-font-family vjs-tracksetting'
19970    }, undefined, this.createElSelect_('fontFamily'));
19971
19972    return (0, _dom.createEl)('div', {
19973      className: 'vjs-tracksettings-font'
19974    }, undefined, [fontPercent, edgeStyle, fontFamily]);
19975  };
19976
19977  /**
19978   * Create controls for the component
19979   *
19980   * @return {Element}
19981   *         The element that was created.
19982   *
19983   * @private
19984   */
19985
19986
19987  TextTrackSettings.prototype.createElControls_ = function createElControls_() {
19988    var defaultsButton = (0, _dom.createEl)('button', {
19989      className: 'vjs-default-button',
19990      textContent: this.localize('Defaults')
19991    });
19992
19993    var doneButton = (0, _dom.createEl)('button', {
19994      className: 'vjs-done-button',
19995      textContent: 'Done'
19996    });
19997
19998    return (0, _dom.createEl)('div', {
19999      className: 'vjs-tracksettings-controls'
20000    }, undefined, [defaultsButton, doneButton]);
20001  };
20002
20003  /**
20004   * Create the component's DOM element
20005   *
20006   * @return {Element}
20007   *         The element that was created.
20008   */
20009
20010
20011  TextTrackSettings.prototype.createEl = function createEl() {
20012    var settings = (0, _dom.createEl)('div', {
20013      className: 'vjs-tracksettings'
20014    }, undefined, [this.createElColors_(), this.createElFont_(), this.createElControls_()]);
20015
20016    var heading = (0, _dom.createEl)('div', {
20017      className: 'vjs-control-text',
20018      id: 'TTsettingsDialogLabel-' + this.id_,
20019      textContent: 'Caption Settings Dialog'
20020    }, {
20021      'aria-level': '1',
20022      'role': 'heading'
20023    });
20024
20025    var description = (0, _dom.createEl)('div', {
20026      className: 'vjs-control-text',
20027      id: 'TTsettingsDialogDescription-' + this.id_,
20028      textContent: 'Beginning of dialog window. Escape will cancel and close the window.'
20029    });
20030
20031    var doc = (0, _dom.createEl)('div', undefined, {
20032      role: 'document'
20033    }, [heading, description, settings]);
20034
20035    return (0, _dom.createEl)('div', {
20036      className: 'vjs-caption-settings vjs-modal-overlay',
20037      tabIndex: -1
20038    }, {
20039      'role': 'dialog',
20040      'aria-labelledby': heading.id,
20041      'aria-describedby': description.id
20042    }, doc);
20043  };
20044
20045  /**
20046   * Gets an object of text track settings (or null).
20047   *
20048   * @return {Object}
20049   *         An object with config values parsed from the DOM or localStorage.
20050   */
20051
20052
20053  TextTrackSettings.prototype.getValues = function getValues() {
20054    var _this3 = this;
20055
20056    return Obj.reduce(selectConfigs, function (accum, config, key) {
20057      var value = getSelectedOptionValue(_this3.$(config.selector), config.parser);
20058
20059      if (value !== undefined) {
20060        accum[key] = value;
20061      }
20062
20063      return accum;
20064    }, {});
20065  };
20066
20067  /**
20068   * Sets text track settings from an object of values.
20069   *
20070   * @param {Object} values
20071   *        An object with config values parsed from the DOM or localStorage.
20072   */
20073
20074
20075  TextTrackSettings.prototype.setValues = function setValues(values) {
20076    var _this4 = this;
20077
20078    Obj.each(selectConfigs, function (config, key) {
20079      setSelectedOption(_this4.$(config.selector), values[key], config.parser);
20080    });
20081  };
20082
20083  /**
20084   * Sets all <select> elements to their default values.
20085   */
20086
20087
20088  TextTrackSettings.prototype.setDefaults = function setDefaults() {
20089    var _this5 = this;
20090
20091    Obj.each(selectConfigs, function (config) {
20092      var index = config.hasOwnProperty('default') ? config['default'] : 0;
20093
20094      _this5.$(config.selector).selectedIndex = index;
20095    });
20096  };
20097
20098  /**
20099   * Restore texttrack settings from localStorage
20100   */
20101
20102
20103  TextTrackSettings.prototype.restoreSettings = function restoreSettings() {
20104    var values = void 0;
20105
20106    try {
20107      values = JSON.parse(_window2['default'].localStorage.getItem(LOCAL_STORAGE_KEY));
20108    } catch (err) {
20109      _log2['default'].warn(err);
20110    }
20111
20112    if (values) {
20113      this.setValues(values);
20114    }
20115  };
20116
20117  /**
20118   * Save text track settings to localStorage
20119   */
20120
20121
20122  TextTrackSettings.prototype.saveSettings = function saveSettings() {
20123    if (!this.options_.persistTextTrackSettings) {
20124      return;
20125    }
20126
20127    var values = this.getValues();
20128
20129    try {
20130      if (Object.keys(values).length) {
20131        _window2['default'].localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(values));
20132      } else {
20133        _window2['default'].localStorage.removeItem(LOCAL_STORAGE_KEY);
20134      }
20135    } catch (err) {
20136      _log2['default'].warn(err);
20137    }
20138  };
20139
20140  /**
20141   * Update display of text track settings
20142   */
20143
20144
20145  TextTrackSettings.prototype.updateDisplay = function updateDisplay() {
20146    var ttDisplay = this.player_.getChild('textTrackDisplay');
20147
20148    if (ttDisplay) {
20149      ttDisplay.updateDisplay();
20150    }
20151  };
20152
20153  return TextTrackSettings;
20154}(_component2['default']);
20155
20156_component2['default'].registerComponent('TextTrackSettings', TextTrackSettings);
20157
20158exports['default'] = TextTrackSettings;
20159
20160},{"5":5,"81":81,"83":83,"86":86,"88":88,"95":95}],72:[function(_dereq_,module,exports){
20161'use strict';
20162
20163exports.__esModule = true;
20164
20165var _textTrackCueList = _dereq_(67);
20166
20167var _textTrackCueList2 = _interopRequireDefault(_textTrackCueList);
20168
20169var _fn = _dereq_(83);
20170
20171var Fn = _interopRequireWildcard(_fn);
20172
20173var _trackEnums = _dereq_(73);
20174
20175var _log = _dereq_(86);
20176
20177var _log2 = _interopRequireDefault(_log);
20178
20179var _window = _dereq_(95);
20180
20181var _window2 = _interopRequireDefault(_window);
20182
20183var _track = _dereq_(75);
20184
20185var _track2 = _interopRequireDefault(_track);
20186
20187var _url = _dereq_(92);
20188
20189var _xhr = _dereq_(104);
20190
20191var _xhr2 = _interopRequireDefault(_xhr);
20192
20193var _mergeOptions = _dereq_(87);
20194
20195var _mergeOptions2 = _interopRequireDefault(_mergeOptions);
20196
20197var _browser = _dereq_(78);
20198
20199var browser = _interopRequireWildcard(_browser);
20200
20201function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
20202
20203function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
20204
20205function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
20206
20207function _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; }
20208
20209function _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, { c
20209onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
20210                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file text-track.js
20211                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
20212
20213
20214/**
20215 * Takes a webvtt file contents and parses it into cues
20216 *
20217 * @param {string} srcContent
20218 *        webVTT file contents
20219 *
20220 * @param {TextTrack} track
20221 *        TextTrack to add cues to. Cues come from the srcContent.
20222 *
20223 * @private
20224 */
20225var parseCues = function parseCues(srcContent, track) {
20226  var parser = new _window2['default'].WebVTT.Parser(_window2['default'], _window2['default'].vttjs, _window2['default'].WebVTT.StringDecoder());
20227  var errors = [];
20228
20229  parser.oncue = function (cue) {
20230    track.addCue(cue);
20231  };
20232
20233  parser.onparsingerror = function (error) {
20234    errors.push(error);
20235  };
20236
20237  parser.onflush = function () {
20238    track.trigger({
20239      type: 'loadeddata',
20240      target: track
20241    });
20242  };
20243
20244  parser.parse(srcContent);
20245  if (errors.length > 0) {
20246    if (_window2['default'].console && _window2['default'].console.groupCollapsed) {
20247      _window2['default'].console.groupCollapsed('Text Track parsing errors for ' + track.src);
20248    }
20249    errors.forEach(function (error) {
20250      return _log2['default'].error(error);
20251    });
20252    if (_window2['default'].console && _window2['default'].console.groupEnd) {
20253      _window2['default'].console.groupEnd();
20254    }
20255  }
20256
20257  parser.flush();
20258};
20259
20260/**
20261 * Load a `TextTrack` from a specifed url.
20262 *
20263 * @param {string} src
20264 *        Url to load track from.
20265 *
20266 * @param {TextTrack} track
20267 *        Track to add cues to. Comes from the content at the end of `url`.
20268 *
20269 * @private
20270 */
20271var loadTrack = function loadTrack(src, track) {
20272  var opts = {
20273    uri: src
20274  };
20275  var crossOrigin = (0, _url.isCrossOrigin)(src);
20276
20277  if (crossOrigin) {
20278    opts.cors = crossOrigin;
20279  }
20280
20281  (0, _xhr2['default'])(opts, Fn.bind(this, function (err, response, responseBody) {
20282    if (err) {
20283      return _log2['default'].error(err, response);
20284    }
20285
20286    track.loaded_ = true;
20287
20288    // Make sure that vttjs has loaded, otherwise, wait till it finished loading
20289    // NOTE: this is only used for the alt/video.novtt.js build
20290    if (typeof _window2['default'].WebVTT !== 'function') {
20291      if (track.tech_) {
20292        var loadHandler = function loadHandler() {
20293          return parseCues(responseBody, track);
20294        };
20295
20296        track.tech_.on('vttjsloaded', loadHandler);
20297        track.tech_.on('vttjserror', function () {
20298          _log2['default'].error('vttjs failed to load, stopping trying to process ' + track.src);
20299          track.tech_.off('vttjsloaded', loadHandler);
20300        });
20301      }
20302    } else {
20303      parseCues(responseBody, track);
20304    }
20305  }));
20306};
20307
20308/**
20309 * A representation of a single `TextTrack`.
20310 *
20311 * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack}
20312 * @extends Track
20313 */
20314
20315var TextTrack = function (_Track) {
20316  _inherits(TextTrack, _Track);
20317
20318  /**
20319   * Create an instance of this class.
20320   *
20321   * @param {Object} options={}
20322   *        Object of option names and values
20323   *
20324   * @param {Tech} options.tech
20325   *        A reference to the tech that owns this TextTrack.
20326   *
20327   * @param {TextTrack~Kind} [options.kind='subtitles']
20328   *        A valid text track kind.
20329   *
20330   * @param {TextTrack~Mode} [options.mode='disabled']
20331   *        A valid text track mode.
20332   *
20333   * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
20334   *        A unique id for this TextTrack.
20335   *
20336   * @param {string} [options.label='']
20337   *        The menu label for this track.
20338   *
20339   * @param {string} [options.language='']
20340   *        A valid two character language code.
20341   *
20342   * @param {string} [options.srclang='']
20343   *        A valid two character language code. An alternative, but deprioritized
20344   *        vesion of `options.language`
20345   *
20346   * @param {string} [options.src]
20347   *        A url to TextTrack cues.
20348   *
20349   * @param {boolean} [options.default]
20350   *        If this track should default to on or off.
20351   */
20352  function TextTrack() {
20353    var _this, _ret;
20354
20355    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
20356
20357    _classCallCheck(this, TextTrack);
20358
20359    if (!options.tech) {
20360      throw new Error('A tech was not provided.');
20361    }
20362
20363    var settings = (0, _mergeOptions2['default'])(options, {
20364      kind: _trackEnums.TextTrackKind[options.kind] || 'subtitles',
20365      language: options.language || options.srclang || ''
20366    });
20367    var mode = _trackEnums.TextTrackMode[settings.mode] || 'disabled';
20368    var default_ = settings['default'];
20369
20370    if (settings.kind === 'metadata' || settings.kind === 'chapters') {
20371      mode = 'hidden';
20372    }
20373    // on IE8 this will be a document element
20374    // for every other browser this will be a normal object
20375    var tt = (_this = _possibleConstructorReturn(this, _Track.call(this, settings)), _this);
20376
20377    tt.tech_ = settings.tech;
20378
20379    if (browser.IS_IE8) {
20380      for (var prop in TextTrack.prototype) {
20381        if (prop !== 'constructor') {
20382          tt[prop] = TextTrack.prototype[prop];
20383        }
20384      }
20385    }
20386
20387    tt.cues_ = [];
20388    tt.activeCues_ = [];
20389
20390    var cues = new _textTrackCueList2['default'](tt.cues_);
20391    var activeCues = new _textTrackCueList2['default'](tt.activeCues_);
20392    var changed = false;
20393    var timeupdateHandler = Fn.bind(tt, function () {
20394
20395      // Accessing this.activeCues for the side-effects of updating itself
20396      // due to it's nature as a getter function. Do not remove or cues will
20397      // stop updating!
20398      /* eslint-disable no-unused-expressions */
20399      this.activeCues;
20400      /* eslint-enable no-unused-expressions */
20401      if (changed) {
20402        this.trigger('cuechange');
20403        changed = false;
20404      }
20405    });
20406
20407    if (mode !== 'disabled') {
20408      tt.tech_.ready(function () {
20409        tt.tech_.on('timeupdate', timeupdateHandler);
20410      }, true);
20411    }
20412
20413    /**
20414     * @member {boolean} default
20415     *         If this track was set to be on or off by default. Cannot be changed after
20416     *         creation.
20417     *
20418     * @readonly
20419     */
20420    Object.defineProperty(tt, 'default', {
20421      get: function get() {
20422        return default_;
20423      },
20424      set: function set() {}
20425    });
20426
20427    /**
20428     * @member {string} mode
20429     *         Set the mode of this TextTrack to a valid {@link TextTrack~Mode}. Will
20430     *         not be set if setting to an invalid mode.
20431     *
20432     * @fires TextTrack#modechange
20433     */
20434    Object.defineProperty(tt, 'mode', {
20435      get: function get() {
20436        return mode;
20437      },
20438      set: function set(newMode) {
20439        var _this2 = this;
20440
20441        if (!_trackEnums.TextTrackMode[newMode]) {
20442          return;
20443        }
20444        mode = newMode;
20445        if (mode === 'showing') {
20446          this.tech_.ready(function () {
20447            _this2.tech_.on('timeupdate', timeupdateHandler);
20448          }, true);
20449        }
20450        /**
20451         * An event that fires when mode changes on this track. This allows
20452         * the TextTrackList that holds this track to act accordingly.
20453         *
20454         * > Note: This is not part of the spec!
20455         *
20456         * @event TextTrack#modechange
20457         * @type {EventTarget~Event}
20458         */
20459        this.trigger('modechange');
20460      }
20461    });
20462
20463    /**
20464     * @member {TextTrackCueList} cues
20465     *         The text track cue list for this TextTrack.
20466     */
20467    Object.defineProperty(tt, 'cues', {
20468      get: function get() {
20469        if (!this.loaded_) {
20470          return null;
20471        }
20472
20473        return cues;
20474      },
20475      set: function set() {}
20476    });
20477
20478    /**
20479     * @member {TextTrackCueList} activeCues
20480     *         The list text track cues that are currently active for this TextTrack.
20481     */
20482    Object.defineProperty(tt, 'activeCues', {
20483      get: function get() {
20484        if (!this.loaded_) {
20485          return null;
20486        }
20487
20488        // nothing to do
20489        if (this.cues.length === 0) {
20490          return activeCues;
20491        }
20492
20493        var ct = this.tech_.currentTime();
20494        var active = [];
20495
20496        for (var i = 0, l = this.cues.length; i < l; i++) {
20497          var cue = this.cues[i];
20498
20499          if (cue.startTime <= ct && cue.endTime >= ct) {
20500            active.push(cue);
20501          } else if (cue.startTime === cue.endTime && cue.startTime <= ct && cue.startTime + 0.5 >= ct) {
20502            active.push(cue);
20503          }
20504        }
20505
20506        changed = false;
20507
20508        if (active.length !== this.activeCues_.length) {
20509          changed = true;
20510        } else {
20511          for (var _i = 0; _i < active.length; _i++) {
20512            if (this.activeCues_.indexOf(active[_i]) === -1) {
20513              changed = true;
20514            }
20515          }
20516        }
20517
20518        this.activeCues_ = active;
20519        activeCues.setCues_(this.activeCues_);
20520
20521        return activeCues;
20522      },
20523      set: function set() {}
20524    });
20525
20526    if (settings.src) {
20527      tt.src = settings.src;
20528      loadTrack(settings.src, tt);
20529    } else {
20530      tt.loaded_ = true;
20531    }
20532
20533    return _ret = tt, _possibleConstructorReturn(_this, _ret);
20534  }
20535
20536  /**
20537   * Add a cue to the internal list of cues.
20538   *
20539   * @param {TextTrack~Cue} cue
20540   *        The cue to add to our internal list
20541   */
20542
20543
20544  TextTrack.prototype.addCue = function addCue(originalCue) {
20545    var cue = originalCue;
20546
20547    if (_window2['default'].vttjs && !(originalCue instanceof _window2['default'].vttjs.VTTCue)) {
20548      cue = new _window2['default'].vttjs.VTTCue(originalCue.startTime, originalCue.endTime, originalCue.text);
20549
20550      for (var prop in originalCue) {
20551        if (!(prop in cue)) {
20552          cue[prop] = originalCue[prop];
20553        }
20554      }
20555
20556      // make sure that `id` is copied over
20557      cue.id = originalCue.id;
20558      cue.originalCue_ = originalCue;
20559    }
20560
20561    var tracks = this.tech_.textTracks();
20562
20563    if (tracks) {
20564      for (var i = 0; i < tracks.length; i++) {
20565        if (tracks[i] !== this) {
20566          tracks[i].removeCue(cue);
20567        }
20568      }
20569    }
20570
20571    this.cues_.push(cue);
20572    this.cues.setCues_(this.cues_);
20573  };
20574
20575  /**
20576   * Remove a cue from our internal list
20577   *
20578   * @param {TextTrack~Cue} removeCue
20579   *        The cue to remove from our internal list
20580   */
20581
20582
20583  TextTrack.prototype.removeCue = function removeCue(_removeCue) {
20584    var i = this.cues_.length;
20585
20586    while (i--) {
20587      var cue = this.cues_[i];
20588
20589      if (cue === _removeCue || cue.originalCue_ && cue.originalCue_ === _removeCue) {
20590        this.cues_.splice(i, 1);
20591        this.cues.setCues_(this.cues_);
20592        break;
20593      }
20594    }
20595  };
20596
20597  return TextTrack;
20598}(_track2['default']);
20599
20600/**
20601 * cuechange - One or more cues in the track have become active or stopped being active.
20602 */
20603
20604
20605TextTrack.prototype.allowedEvents_ = {
20606  cuechange: 'cuechange'
20607};
20608
20609exports['default'] = TextTrack;
20610
20611},{"104":104,"67":67,"73":73,"75":75,"78":78,"83":83,"86":86,"87":87,"92":92,"95":95}],73:[function(_dereq_,module,exports){
20612'use strict';
20613
20614exports.__esModule = true;
20615/**
20616 * @file track-kinds.js
20617 */
20618
20619/**
20620 * All possible `VideoTrackKind`s
20621 *
20622 * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-videotrack-kind
20623 * @typedef VideoTrack~Kind
20624 * @enum
20625 */
20626var VideoTrackKind = exports.VideoTrackKind = {
20627  alternative: 'alternative',
20628  captions: 'captions',
20629  main: 'main',
20630  sign: 'sign',
20631  subtitles: 'subtitles',
20632  commentary: 'commentary'
20633};
20634
20635/**
20636 * All possible `AudioTrackKind`s
20637 *
20638 * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-audiotrack-kind
20639 * @typedef AudioTrack~Kind
20640 * @enum
20641 */
20642var AudioTrackKind = exports.AudioTrackKind = {
20643  'alternative': 'alternative',
20644  'descriptions': 'descriptions',
20645  'main': 'main',
20646  'main-desc': 'main-desc',
20647  'translation': 'translation',
20648  'commentary': 'commentary'
20649};
20650
20651/**
20652 * All possible `TextTrackKind`s
20653 *
20654 * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-texttrack-kind
20655 * @typedef TextTrack~Kind
20656 * @enum
20657 */
20658var TextTrackKind = exports.TextTrackKind = {
20659  subtitles: 'subtitles',
20660  captions: 'captions',
20661  descriptions: 'descriptions',
20662  chapters: 'chapters',
20663  metadata: 'metadata'
20664};
20665
20666/**
20667 * All possible `TextTrackMode`s
20668 *
20669 * @see https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode
20670 * @typedef TextTrack~Mode
20671 * @enum
20672 */
20673var TextTrackMode = exports.TextTrackMode = {
20674  disabled: 'disabled',
20675  hidden: 'hidden',
20676  showing: 'showing'
20677};
20678
20679},{}],74:[function(_dereq_,module,exports){
20680'use strict';
20681
20682exports.__esModule = true;
20683
20684var _eventTarget = _dereq_(42);
20685
20686var _eventTarget2 = _interopRequireDefault(_eventTarget);
20687
20688var _browser = _dereq_(78);
20689
20690var browser = _interopRequireWildcard(_browser);
20691
20692var _document = _dereq_(94);
20693
20694var _document2 = _interopRequireDefault(_document);
20695
20696function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
20697
20698function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
20699
20700function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
20701
20702function _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; }
20703
20704function _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, { c
20704onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
20705                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file track-list.js
20706                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
20707
20708
20709/**
20710 * Common functionaliy between {@link TextTrackList}, {@link AudioTrackList}, and
20711 * {@link VideoTrackList}
20712 *
20713 * @extends EventTarget
20714 */
20715var TrackList = function (_EventTarget) {
20716  _inherits(TrackList, _EventTarget);
20717
20718  /**
20719   * Create an instance of this class
20720   *
20721   * @param {Track[]} tracks
20722   *        A list of tracks to initialize the list with.
20723   *
20724   * @param {Object} [list]
20725   *        The child object with inheritance done manually for ie8.
20726   *
20727   * @abstract
20728   */
20729  function TrackList() {
20730    var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
20731
20732    var _ret;
20733
20734    var list = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
20735
20736    _classCallCheck(this, TrackList);
20737
20738    var _this = _possibleConstructorReturn(this, _EventTarget.call(this));
20739
20740    if (!list) {
20741      list = _this; // eslint-disable-line
20742      if (browser.IS_IE8) {
20743        list = _document2['default'].createElement('custom');
20744        for (var prop in TrackList.prototype) {
20745          if (prop !== 'constructor') {
20746            list[prop] = TrackList.prototype[prop];
20747          }
20748        }
20749      }
20750    }
20751
20752    list.tracks_ = [];
20753
20754    /**
20755     * @member {number} length
20756     *         The current number of `Track`s in the this Trackist.
20757     */
20758    Object.defineProperty(list, 'length', {
20759      get: function get() {
20760        return this.tracks_.length;
20761      }
20762    });
20763
20764    for (var i = 0; i < tracks.length; i++) {
20765      list.addTrack_(tracks[i]);
20766    }
20767
20768    // must return the object, as for ie8 it will not be this
20769    // but a reference to a document object
20770    return _ret = list, _possibleConstructorReturn(_this, _ret);
20771  }
20772
20773  /**
20774   * Add a {@link Track} to the `TrackList`
20775   *
20776   * @param {Track} track
20777   *        The audio, video, or text track to add to the list.
20778   *
20779   * @fires TrackList#addtrack
20780   * @private
20781   */
20782
20783
20784  TrackList.prototype.addTrack_ = function addTrack_(track) {
20785    var index = this.tracks_.length;
20786
20787    if (!('' + index in this)) {
20788      Object.defineProperty(this, index, {
20789        get: function get() {
20790          return this.tracks_[index];
20791        }
20792      });
20793    }
20794
20795    // Do not add duplicate tracks
20796    if (this.tracks_.indexOf(track) === -1) {
20797      this.tracks_.push(track);
20798      /**
20799       * Triggered when a track is added to a track list.
20800       *
20801       * @event TrackList#addtrack
20802       * @type {EventTarget~Event}
20803       * @property {Track} track
20804       *           A reference to track that was added.
20805       */
20806      this.trigger({
20807        track: track,
20808        type: 'addtrack'
20809      });
20810    }
20811  };
20812
20813  /**
20814   * Remove a {@link Track} from the `TrackList`
20815   *
20816   * @param {Track} track
20817   *        The audio, video, or text track to remove from the list.
20818   *
20819   * @fires TrackList#removetrack
20820   * @private
20821   */
20822
20823
20824  TrackList.prototype.removeTrack_ = function removeTrack_(rtrack) {
20825    var track = void 0;
20826
20827    for (var i = 0, l = this.length; i < l; i++) {
20828      if (this[i] === rtrack) {
20829        track = this[i];
20830        if (track.off) {
20831          track.off();
20832        }
20833
20834        this.tracks_.splice(i, 1);
20835
20836        break;
20837      }
20838    }
20839
20840    if (!track) {
20841      return;
20842    }
20843
20844    /**
20845     * Triggered when a track is removed from track list.
20846     *
20847     * @event TrackList#removetrack
20848     * @type {EventTarget~Event}
20849     * @property {Track} track
20850     *           A reference to track that was removed.
20851     */
20852    this.trigger({
20853      track: track,
20854      type: 'removetrack'
20855    });
20856  };
20857
20858  /**
20859   * Get a Track from the TrackList by a tracks id
20860   *
20861   * @param {String} id - the id of the track to get
20862   * @method getTrackById
20863   * @return {Track}
20864   * @private
20865   */
20866
20867
20868  TrackList.prototype.getTrackById = function getTrackById(id) {
20869    var result = null;
20870
20871    for (var i = 0, l = this.length; i < l; i++) {
20872      var track = this[i];
20873
20874      if (track.id === id) {
20875        result = track;
20876        break;
20877      }
20878    }
20879
20880    return result;
20881  };
20882
20883  return TrackList;
20884}(_eventTarget2['default']);
20885
20886/**
20887 * Triggered when a different track is selected/enabled.
20888 *
20889 * @event TrackList#change
20890 * @type {EventTarget~Event}
20891 */
20892
20893/**
20894 * Events that can be called with on + eventName. See {@link EventHandler}.
20895 *
20896 * @property {Object} TrackList#allowedEvents_
20897 * @private
20898 */
20899
20900
20901TrackList.prototype.allowedEvents_ = {
20902  change: 'change',
20903  addtrack: 'addtrack',
20904  removetrack: 'removetrack'
20905};
20906
20907// emulate attribute EventHandler support to allow for feature detection
20908for (var event in TrackList.prototype.allowedEvents_) {
20909  TrackList.prototype['on' + event] = null;
20910}
20911
20912exports['default'] = TrackList;
20913
20914},{"42":42,"78":78,"94":94}],75:[function(_dereq_,module,exports){
20915'use strict';
20916
20917exports.__esModule = true;
20918
20919var _browser = _dereq_(78);
20920
20921var browser = _interopRequireWildcard(_browser);
20922
20923var _document = _dereq_(94);
20924
20925var _document2 = _interopRequireDefault(_document);
20926
20927var _guid = _dereq_(85);
20928
20929var Guid = _interopRequireWildcard(_guid);
20930
20931var _eventTarget = _dereq_(42);
20932
20933var _eventTarget2 = _interopRequireDefault(_eventTarget);
20934
20935function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
20936
20937function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
20938
20939function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
20940
20941function _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; }
20942
20943function _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, { c
20943onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
20944                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file track.js
20945                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
20946
20947
20948/**
20949 * A Track class that contains all of the common functionality for {@link AudioTrack},
20950 * {@link VideoTrack}, and {@link TextTrack}.
20951 *
20952 * > Note: This class should not be used directly
20953 *
20954 * @see {@link https://html.spec.whatwg.org/multipage/embedded-content.html}
20955 * @extends EventTarget
20956 * @abstract
20957 */
20958var Track = function (_EventTarget) {
20959  _inherits(Track, _EventTarget);
20960
20961  /**
20962   * Create an instance of this class.
20963   *
20964   * @param {Object} [options={}]
20965   *        Object of option names and values
20966   *
20967   * @param {string} [options.kind='']
20968   *        A valid kind for the track type you are creating.
20969   *
20970   * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
20971   *        A unique id for this AudioTrack.
20972   *
20973   * @param {string} [options.label='']
20974   *        The menu label for this track.
20975   *
20976   * @param {string} [options.language='']
20977   *        A valid two character language code.
20978   *
20979   * @abstract
20980   */
20981  function Track() {
20982    var _ret;
20983
20984    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
20985
20986    _classCallCheck(this, Track);
20987
20988    var _this = _possibleConstructorReturn(this, _EventTarget.call(this));
20989
20990    var track = _this; // eslint-disable-line
20991
20992    if (browser.IS_IE8) {
20993      track = _document2['default'].createElement('custom');
20994      for (var prop in Track.prototype) {
20995        if (prop !== 'constructor') {
20996          track[prop] = Track.prototype[prop];
20997        }
20998      }
20999    }
21000
21001    var trackProps = {
21002      id: options.id || 'vjs_track_' + Guid.newGUID(),
21003      kind: options.kind || '',
21004      label: options.label || '',
21005      language: options.language || ''
21006    };
21007
21008    /**
21009     * @member {string} id
21010     *         The id of this track. Cannot be changed after creation.
21011     *
21012     * @readonly
21013     */
21014
21015    /**
21016     * @member {string} kind
21017     *         The kind of track that this is. Cannot be changed after creation.
21018     *
21019     * @readonly
21020     */
21021
21022    /**
21023     * @member {string} label
21024     *         The label of this track. Cannot be changed after creation.
21025     *
21026     * @readonly
21027     */
21028
21029    /**
21030     * @member {string} language
21031     *         The two letter language code for this track. Cannot be changed after
21032     *         creation.
21033     *
21034     * @readonly
21035     */
21036
21037    var _loop = function _loop(key) {
21038      Object.defineProperty(track, key, {
21039        get: function get() {
21040          return trackProps[key];
21041        },
21042        set: function set() {}
21043      });
21044    };
21045
21046    for (var key in trackProps) {
21047      _loop(key);
21048    }
21049
21050    return _ret = track, _possibleConstructorReturn(_this, _ret);
21051  }
21052
21053  return Track;
21054}(_eventTarget2['default']);
21055
21056exports['default'] = Track;
21057
21058},{"42":42,"78":78,"85":85,"94":94}],76:[function(_dereq_,module,exports){
21059'use strict';
21060
21061exports.__esModule = true;
21062
21063var _trackList = _dereq_(74);
21064
21065var _trackList2 = _interopRequireDefault(_trackList);
21066
21067var _browser = _dereq_(78);
21068
21069var browser = _interopRequireWildcard(_browser);
21070
21071var _document = _dereq_(94);
21072
21073var _document2 = _interopRequireDefault(_document);
21074
21075function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
21076
21077function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
21078
21079function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
21080
21081function _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; }
21082
21083function _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, { c
21083onstructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
21084                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file video-track-list.js
21085                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
21086
21087
21088/**
21089 * Un-select all other {@link VideoTrack}s that are selected.
21090 *
21091 * @param {VideoTrackList} list
21092 *        list to work on
21093 *
21094 * @param {VideoTrack} track
21095 *        The track to skip
21096 *
21097 * @private
21098 */
21099var disableOthers = function disableOthers(list, track) {
21100  for (var i = 0; i < list.length; i++) {
21101    if (track.id === list[i].id) {
21102      continue;
21103    }
21104    // another video track is enabled, disable it
21105    list[i].selected = false;
21106  }
21107};
21108
21109/**
21110 * The current list of {@link VideoTrack} for a video.
21111 *
21112 * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist}
21113 * @extends TrackList
21114 */
21115
21116var VideoTrackList = function (_TrackList) {
21117  _inherits(VideoTrackList, _TrackList);
21118
21119  /**
21120   * Create an instance of this class.
21121   *
21122   * @param {VideoTrack[]} [tracks=[]]
21123   *        A list of `VideoTrack` to instantiate the list with.
21124   */
21125  function VideoTrackList() {
21126    var _this, _ret;
21127
21128    var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
21129
21130    _classCallCheck(this, VideoTrackList);
21131
21132    var list = void 0;
21133
21134    // make sure only 1 track is enabled
21135    // sorted from last index to first index
21136    for (var i = tracks.length - 1; i >= 0; i--) {
21137      if (tracks[i].selected) {
21138        disableOthers(tracks, tracks[i]);
21139        break;
21140      }
21141    }
21142
21143    // IE8 forces us to implement inheritance ourselves
21144    // as it does not support Object.defineProperty properly
21145    if (browser.IS_IE8) {
21146      list = _document2['default'].createElement('custom');
21147      for (var prop in _trackList2['default'].prototype) {
21148        if (prop !== 'constructor') {
21149          list[prop] = _trackList2['default'].prototype[prop];
21150        }
21151      }
21152      for (var _prop in VideoTrackList.prototype) {
21153        if (_prop !== 'constructor') {
21154          list[_prop] = VideoTrackList.prototype[_prop];
21155        }
21156      }
21157    }
21158
21159    list = (_this = _possibleConstructorReturn(this, _TrackList.call(this, tracks, list)), _this);
21160    list.changing_ = false;
21161
21162    /**
21163     * @member {number} VideoTrackList#selectedIndex
21164     *         The current index of the selected {@link VideoTrack`}.
21165     */
21166    Object.defineProperty(list, 'selectedIndex', {
21167      get: function get() {
21168        for (var _i = 0; _i < this.length; _i++) {
21169          if (this[_i].selected) {
21170            return _i;
21171          }
21172        }
21173        return -1;
21174      },
21175      set: function set() {}
21176    });
21177
21178    return _ret = list, _possibleConstructorReturn(_this, _ret);
21179  }
21180
21181  /**
21182   * Add a {@link VideoTrack} to the `VideoTrackList`.
21183   *
21184   * @param {VideoTrack} track
21185   *        The VideoTrack to add to the list
21186   *
21187   * @fires TrackList#addtrack
21188   * @private
21189   */
21190
21191
21192  VideoTrackList.prototype.addTrack_ = function addTrack_(track) {
21193    var _this2 = this;
21194
21195    if (track.selected) {
21196      disableOthers(this, track);
21197    }
21198
21199    _TrackList.prototype.addTrack_.call(this, track);
21200    // native tracks don't have this
21201    if (!track.addEventListener) {
21202      return;
21203    }
21204
21205    /**
21206     * @listens VideoTrack#selectedchange
21207     * @fires TrackList#change
21208     */
21209    track.addEventListener('selectedchange', function () {
21210      if (_this2.changing_) {
21211        return;
21212      }
21213      _this2.changing_ = true;
21214      disableOthers(_this2, track);
21215      _this2.changing_ = false;
21216      _this2.trigger('change');
21217    });
21218  };
21219
21220  /**
21221   * Add a {@link VideoTrack} to the `VideoTrackList`.
21222   *
21223   * @param {VideoTrack} track
21224   *        The VideoTrack to add to the list
21225   *
21226   * @fires TrackList#addtrack
21227   */
21228
21229
21230  VideoTrackList.prototype.addTrack = function addTrack(track) {
21231    this.addTrack_(track);
21232  };
21233
21234  /**
21235   * Remove a {@link VideoTrack} to the `VideoTrackList`.
21236   *
21237   * @param {VideoTrack} track
21238   *        The VideoTrack to remove from the list.
21239   *
21240   * @fires TrackList#removetrack
21241   */
21242
21243
21244  VideoTrackList.prototype.removeTrack = function removeTrack(track) {
21245    _TrackList.prototype.removeTrack_.call(this, track);
21246  };
21247
21248  return VideoTrackList;
21249}(_trackList2['default']);
21250
21251exports['default'] = VideoTrackList;
21252
21253},{"74":74,"78":78,"94":94}],77:[function(_dereq_,module,exports){
21254'use strict';
21255
21256exports.__esModule = true;
21257
21258var _trackEnums = _dereq_(73);
21259
21260var _track = _dereq_(75);
21261
21262var _track2 = _interopRequireDefault(_track);
21263
21264var _mergeOptions = _dereq_(87);
21265
21266var _mergeOptions2 = _interopRequireDefault(_mergeOptions);
21267
21268var _browser = _dereq_(78);
21269
21270var browser = _interopRequireWildcard(_browser);
21271
21272function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
21273
21274function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
21275
21276function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
21277
21278function _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; }
21279
21280function _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; }
21281
21282/**
21283 * A representation of a single `VideoTrack`.
21284 *
21285 * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotrack}
21286 * @extends Track
21287 */
21288var VideoTrack = function (_Track) {
21289  _inherits(VideoTrack, _Track);
21290
21291  /**
21292   * Create an instance of this class.
21293   *
21294   * @param {Object} [options={}]
21295   *        Object of option names and values
21296   *
21297   * @param {string} [options.kind='']
21298   *        A valid {@link VideoTrack~Kind}
21299   *
21300   * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
21301   *        A unique id for this AudioTrack.
21302   *
21303   * @param {string} [options.label='']
21304   *        The menu label for this track.
21305   *
21306   * @param {string} [options.language='']
21307   *        A valid two character language code.
21308   *
21309   * @param {boolean} [options.selected]
21310   *        If this track is the one that is currently playing.
21311   */
21312  function VideoTrack() {
21313    var _this, _ret;
21314
21315    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
21316
21317    _classCallCheck(this, VideoTrack);
21318
21319    var settings = (0, _mergeOptions2['default'])(options, {
21320      kind: _trackEnums.VideoTrackKind[options.kind] || ''
21321    });
21322
21323    // on IE8 this will be a document element
21324    // for every other browser this will be a normal object
21325    var track = (_this = _possibleConstructorReturn(this, _Track.call(this, settings)), _this);
21326    var selected = false;
21327
21328    if (browser.IS_IE8) {
21329      for (var prop in VideoTrack.prototype) {
21330        if (prop !== 'constructor') {
21331          track[prop] = VideoTrack.prototype[prop];
21332        }
21333      }
21334    }
21335
21336    /**
21337     * @member {boolean} selected
21338     *         If this `VideoTrack` is selected or not. When setting this will
21339     *         fire {@link VideoTrack#selectedchange} if the state of selected changed.
21340     *
21341     * @fires VideoTrack#selectedchange
21342     */
21343    Object.defineProperty(track, 'selected', {
21344      get: function get() {
21345        return selected;
21346      },
21347      set: function set(newSelected) {
21348        // an invalid or unchanged value
21349        if (typeof newSelected !== 'boolean' || newSelected === selected) {
21350          return;
21351        }
21352        selected = newSelected;
21353
21354        /**
21355         * An event that fires when selected changes on this track. This allows
21356         * the VideoTrackList that holds this track to act accordingly.
21357         *
21358         * > Note: This is not part of the spec! Native tracks will do
21359         *         this internally without an event.
21360         *
21361         * @event VideoTrack#selectedchange
21362         * @type {EventTarget~Event}
21363         */
21364        this.trigger('selectedchange');
21365      }
21366    });
21367
21368    // if the user sets this track to selected then
21369    // set selected to that true value otherwise
21370    // we keep it false
21371    if (settings.selected) {
21372      track.selected = settings.selected;
21373    }
21374
21375    return _ret = track, _possibleConstructorReturn(_this, _ret);
21376  }
21377
21378  return VideoTrack;
21379}(_track2['default']);
21380
21381exports['default'] = VideoTrack;
21382
21383},{"73":73,"75":75,"78":78,"87":87}],78:[function(_dereq_,module,exports){
21384'use strict';
21385
21386exports.__esModule = true;
21387exports.BACKGROUND_SIZE_SUPPORTED = exports.TOUCH_ENABLED = exports.IS_ANY_SAFARI = exports.IS_SAFARI = exports.IE_VERSION = exports.IS_IE8 = exports.CHROME_VERSION = exports.IS_CHROME = exports.IS_EDGE = exports.IS_FIREFOX = exports.IS_NATIVE_ANDROID = exp
21387orts.IS_OLD_ANDROID = exports.ANDROID_VERSION = exports.IS_ANDROID = exports.IOS_VERSION = exports.IS_IOS = exports.IS_IPOD = exports.IS_IPHONE = exports.IS_IPAD = undefined;
21388
21389var _dom = _dereq_(81);
21390
21391var Dom = _interopRequireWildcard(_dom);
21392
21393var _window = _dereq_(95);
21394
21395var _window2 = _interopRequireDefault(_window);
21396
21397function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
21398
21399function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
21400
21401/**
21402 * @file browser.js
21403 * @module browser
21404 */
21405var USER_AGENT = _window2['default'].navigator && _window2['default'].navigator.userAgent || '';
21406var webkitVersionMap = /AppleWebKit\/([\d.]+)/i.exec(USER_AGENT);
21407var appleWebkitVersion = webkitVersionMap ? parseFloat(webkitVersionMap.pop()) : null;
21408
21409/*
21410 * Device is an iPhone
21411 *
21412 * @type {Boolean}
21413 * @constant
21414 * @private
21415 */
21416var IS_IPAD = exports.IS_IPAD = /iPad/i.test(USER_AGENT);
21417
21418// The Facebook app's UIWebView identifies as both an iPhone and iPad, so
21419// to identify iPhones, we need to exclude iPads.
21420// http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/
21421var IS_IPHONE = exports.IS_IPHONE = /iPhone/i.test(USER_AGENT) && !IS_IPAD;
21422var IS_IPOD = exports.IS_IPOD = /iPod/i.test(USER_AGENT);
21423var IS_IOS = exports.IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD;
21424
21425var IOS_VERSION = exports.IOS_VERSION = function () {
21426  var match = USER_AGENT.match(/OS (\d+)_/i);
21427
21428  if (match && match[1]) {
21429    return match[1];
21430  }
21431  return null;
21432}();
21433
21434var IS_ANDROID = exports.IS_ANDROID = /Android/i.test(USER_AGENT);
21435var ANDROID_VERSION = exports.ANDROID_VERSION = function () {
21436  // This matches Android Major.Minor.Patch versions
21437  // ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned
21438  var match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i);
21439
21440  if (!match) {
21441    return null;
21442  }
21443
21444  var major = match[1] && parseFloat(match[1]);
21445  var minor = match[2] && parseFloat(match[2]);
21446
21447  if (major && minor) {
21448    return parseFloat(match[1] + '.' + match[2]);
21449  } else if (major) {
21450    return major;
21451  }
21452  return null;
21453}();
21454
21455// Old Android is defined as Version older than 2.3, and requiring a webkit version of the android browser
21456var IS_OLD_ANDROID = exports.IS_OLD_ANDROID = IS_ANDROID && /webkit/i.test(USER_AGENT) && ANDROID_VERSION < 2.3;
21457var IS_NATIVE_ANDROID = exports.IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537;
21458
21459var IS_FIREFOX = exports.IS_FIREFOX = /Firefox/i.test(USER_AGENT);
21460var IS_EDGE = exports.IS_EDGE = /Edge/i.test(USER_AGENT);
21461var IS_CHROME = exports.IS_CHROME = !IS_EDGE && /Chrome/i.test(USER_AGENT);
21462var CHROME_VERSION = exports.CHROME_VERSION = function () {
21463  var match = USER_AGENT.match(/Chrome\/(\d+)/);
21464
21465  if (match && match[1]) {
21466    return parseFloat(match[1]);
21467  }
21468  return null;
21469}();
21470var IS_IE8 = exports.IS_IE8 = /MSIE\s8\.0/.test(USER_AGENT);
21471var IE_VERSION = exports.IE_VERSION = function () {
21472  var result = /MSIE\s(\d+)\.\d/.exec(USER_AGENT);
21473  var version = result && parseFloat(result[1]);
21474
21475  if (!version && /Trident\/7.0/i.test(USER_AGENT) && /rv:11.0/.test(USER_AGENT)) {
21476    // IE 11 has a different user agent string than other IE versions
21477    version = 11.0;
21478  }
21479
21480  return version;
21481}();
21482
21483var IS_SAFARI = exports.IS_SAFARI = /Safari/i.test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE;
21484var IS_ANY_SAFARI = exports.IS_ANY_SAFARI = IS_SAFARI || IS_IOS;
21485
21486var TOUCH_ENABLED = exports.TOUCH_ENABLED = Dom.isReal() && ('ontouchstart' in _window2['default'] || _window2['default'].DocumentTouch && _window2['default'].document instanceof _window2['default'].DocumentTouch);
21487
21488var BACKGROUND_SIZE_SUPPORTED = exports.BACKGROUND_SIZE_SUPPORTED = Dom.isReal() && 'backgroundSize' in _window2['default'].document.createElement('video').style;
21489
21490},{"81":81,"95":95}],79:[function(_dereq_,module,exports){
21491'use strict';
21492
21493exports.__esModule = true;
21494exports.bufferedPercent = bufferedPercent;
21495
21496var _timeRanges = _dereq_(90);
21497
21498/**
21499 * Compute the percentage of the media that has been buffered.
21500 *
21501 * @param {TimeRange} buffered
21502 *        The current `TimeRange` object representing buffered time ranges
21503 *
21504 * @param {number} duration
21505 *        Total duration of the media
21506 *
21507 * @return {number}
21508 *         Percent buffered of the total duration in decimal form.
21509 */
21510function bufferedPercent(buffered, duration) {
21511  var bufferedDuration = 0;
21512  var start = void 0;
21513  var end = void 0;
21514
21515  if (!duration) {
21516    return 0;
21517  }
21518
21519  if (!buffered || !buffered.length) {
21520    buffered = (0, _timeRanges.createTimeRange)(0, 0);
21521  }
21522
21523  for (var i = 0; i < buffered.length; i++) {
21524    start = buffered.start(i);
21525    end = buffered.end(i);
21526
21527    // buffered end can be bigger than duration by a very small fraction
21528    if (end > duration) {
21529      end = duration;
21530    }
21531
21532    bufferedDuration += end - start;
21533  }
21534
21535  return bufferedDuration / duration;
21536} /**
21537   * @file buffer.js
21538   * @module buffer
21539   */
21540
21541},{"90":90}],80:[function(_dereq_,module,exports){
21542'use strict';
21543
21544exports.__esModule = true;
21545exports['default'] = computedStyle;
21546
21547var _window = _dereq_(95);
21548
21549var _window2 = _interopRequireDefault(_window);
21550
21551function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
21552
21553/**
21554 * A safe getComputedStyle with an IE8 fallback.
21555 *
21556 * This is needed because in Firefox, if the player is loaded in an iframe with
21557 * `display:none`, then `getComputedStyle` returns `null`, so, we do a null-check to
21558 * make sure  that the player doesn't break in these cases.
21559 *
21560 * @param {Element} el
21561 *        The element you want the computed style of
21562 *
21563 * @param {string} prop
21564 *        The property name you want
21565 *
21566 * @see https://bugzilla.mozilla.org/show_bug.cgi?id=548397
21567 */
21568function computedStyle(el, prop) {
21569  if (!el || !prop) {
21570    return '';
21571  }
21572
21573  if (typeof _window2['default'].getComputedStyle === 'function') {
21574    var cs = _window2['default'].getComputedStyle(el);
21575
21576    return cs ? cs[prop] : '';
21577  }
21578
21579  return el.currentStyle[prop] || '';
21580} /**
21581   * @file computed-style.js
21582   * @module computed-style
21583   */
21584
21585},{"95":95}],81:[function(_dereq_,module,exports){
21586'use strict';
21587
21588exports.__esModule = true;
21589exports.$$ = exports.$ = undefined;
21590
21591var _templateObject = _taggedTemplateLiteralLoose(['Setting attributes in the second argument of createEl()\n                has been deprecated. Use the third argument instead.\n                createEl(type, properties, attributes). Attempting to set ', ' to ', '.'], ['Setting attributes in the second argument of createEl()\n                has been deprecated. Use the third argument instead.\n                createEl(type, properties, attributes). Attempting to set ', ' to ', '.']);
21592
21593exports.isReal = isReal;
21594exports.isEl = isEl;
21595exports.getEl = getEl;
21596exports.createEl = createEl;
21597exports.textContent = textContent;
21598exports.insertElFirst = insertElFirst;
21599exports.getElData = getElData;
21600exports.hasElData = hasElData;
21601exports.removeElData = removeElData;
21602exports.hasElClass = hasElClass;
21603exports.addElClass = addElClass;
21604exports.removeElClass = removeElClass;
21605exports.toggleElClass = toggleElClass;
21606exports.setElAttributes = setElAttributes;
21607exports.getElAttributes = getElAttributes;
21608exports.getAttribute = getAttribute;
21609exports.setAttribute = setAttribute;
21610exports.removeAttribute = removeAttribute;
21611exports.blockTextSelection = blockTextSelection;
21612exports.unblockTextSelection = unblockTextSelection;
21613exports.findElPosition = findElPosition;
21614exports.getPointerPosition = getPointerPosition;
21615exports.isTextNode = isTextNode;
21616exports.emptyEl = emptyEl;
21617exports.normalizeContent = normalizeContent;
21618exports.appendContent = appendContent;
21619exports.insertContent = insertContent;
21620
21621var _document = _dereq_(94);
21622
21623var _document2 = _interopRequireDefault(_document);
21624
21625var _window = _dereq_(95);
21626
21627var _window2 = _interopRequireDefault(_window);
21628
21629var _guid = _dereq_(85);
21630
21631var Guid = _interopRequireWildcard(_guid);
21632
21633var _log = _dereq_(86);
21634
21635var _log2 = _interopRequireDefault(_log);
21636
21637var _tsml = _dereq_(98);
21638
21639var _tsml2 = _interopRequireDefault(_tsml);
21640
21641var _obj = _dereq_(88);
21642
21643function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
21644
21645function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
21646
21647function _taggedTemplateLiteralLoose(strings, raw) { strings.raw = raw; return strings; } /**
21648                                                                                           * @file dom.js
21649                                                                                           * @module dom
21650                                                                                           */
21651
21652
21653/**
21654 * Detect if a value is a string with any non-whitespace characters.
21655 *
21656 * @param {string} str
21657 *        The string to check
21658 *
21659 * @return {boolean}
21660 *         - True if the string is non-blank
21661 *         - False otherwise
21662 *
21663 */
21664function isNonBlankString(str) {
21665  return typeof str === 'string' && /\S/.test(str);
21666}
21667
21668/**
21669 * Throws an error if the passed string has whitespace. This is used by
21670 * class methods to be relatively consistent with the classList API.
21671 *
21672 * @param {string} str
21673 *         The string to check for whitespace.
21674 *
21675 * @throws {Error}
21676 *         Throws an error if there is whitespace in the string.
21677 *
21678 */
21679function throwIfWhitespace(str) {
21680  if (/\s/.test(str)) {
21681    throw new Error('class has illegal whitespace characters');
21682  }
21683}
21684
21685/**
21686 * Produce a regular expression for matching a className within an elements className.
21687 *
21688 * @param {string} className
21689 *         The className to generate the RegExp for.
21690 *
21691 * @return {RegExp}
21692 *         The RegExp that will check for a specific `className` in an elements
21693 *         className.
21694 */
21695function classRegExp(className) {
21696  return new RegExp('(^|\\s)' + className + '($|\\s)');
21697}
21698
21699/**
21700 * Whether the current DOM interface appears to be real.
21701 *
21702 * @return {Boolean}
21703 */
21704function isReal() {
21705  return (
21706
21707    // Both document and window will never be undefined thanks to `global`.
21708    _document2['default'] === _window2['default'].document &&
21709
21710    // In IE < 9, DOM methods return "object" as their type, so all we can
21711    // confidently check is that it exists.
21712    typeof _document2['default'].createElement !== 'undefined'
21713  );
21714}
21715
21716/**
21717 * Determines, via duck typing, whether or not a value is a DOM element.
21718 *
21719 * @param {Mixed} value
21720 *        The thing to check
21721 *
21722 * @return {boolean}
21723 *         - True if it is a DOM element
21724 *         - False otherwise
21725 */
21726function isEl(value) {
21727  return (0, _obj.isObject)(value) && value.nodeType === 1;
21728}
21729
21730/**
21731 * Creates functions to query the DOM using a given method.
21732 *
21733 * @param {string} method
21734 *         The method to create the query with.
21735 *
21736 * @return {Function}
21737 *         The query method
21738 */
21739function createQuerier(method) {
21740  return function (selector, context) {
21741    if (!isNonBlankString(selector)) {
21742      return _document2['default'][method](null);
21743    }
21744    if (isNonBlankString(context)) {
21745      context = _document2['default'].querySelector(context);
21746    }
21747
21748    var ctx = isEl(context) ? context : _document2['default'];
21749
21750    return ctx[method] && ctx[method](selector);
21751  };
21752}
21753
21754/**
21755 * Shorthand for document.getElementById()
21756 * Also allows for CSS (jQuery) ID syntax. But nothing other than IDs.
21757 *
21758 * @param {string} id
21759 *         The id of the element to get
21760 *
21761 * @return {Element|null}
21762 *         Element with supplied ID or null if there wasn't one.
21763 */
21764function getEl(id) {
21765  if (id.indexOf('#') === 0) {
21766    id = id.slice(1);
21767  }
21768
21769  return _document2['default'].getElementById(id);
21770}
21771
21772/**
21773 * Creates an element and applies properties.
21774 *
21775 * @param {string} [tagName='div']
21776 *         Name of tag to be created.
21777 *
21778 * @param {Object} [properties={}]
21779 *         Element properties to be applied.
21780 *
21781 * @param {Object} [attributes={}]
21782 *         Element attributes to be applied.
21783 *
21784 * @param {String|Element|TextNode|Array|Function} [content]
21785 *         Contents for the element (see: {@link dom:normalizeContent})
21786 *
21787 * @return {Element}
21788 *         The element that was created.
21789 */
21790function createEl() {
21791  var tagName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div';
21792  var properties = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
21793  var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
21794  var content = arguments[3];
21795
21796  var el = _document2['default'].createElement(tagName);
21797
vendor: 4,190 bytes, lines 21798-21985
21798  Object.getOwnPropertyNames(properties).forEach(function (propName) {
21799    var val = properties[propName];
21800
21801    // See #2176
21802    // We originally were accepting both properties and attributes in the
21803    // same object, but that doesn't work so well.
21804    if (propName.indexOf('aria-') !== -1 || propName === 'role' || propName === 'type') {
21805      _log2['default'].warn((0, _tsml2['default'])(_templateObject, propName, val));
21806      el.setAttribute(propName, val);
21807
21808      // Handle textContent since it's not supported everywhere and we have a
21809      // method for it.
21810    } else if (propName === 'textContent') {
21811      textContent(el, val);
21812    } else {
21813      el[propName] = val;
21814    }
21815  });
21816
21817  Object.getOwnPropertyNames(attributes).forEach(function (attrName) {
21818    el.setAttribute(attrName, attributes[attrName]);
21819  });
21820
21821  if (content) {
21822    appendContent(el, content);
21823  }
21824
21825  return el;
21826}
21827
21828/**
21829 * Injects text into an element, replacing any existing contents entirely.
21830 *
21831 * @param {Element} el
21832 *        The element to add text content into
21833 *
21834 * @param {string} text
21835 *        The text content to add.
21836 *
21837 * @return {Element}
21838 *         The element with added text content.
21839 */
21840function textContent(el, text) {
21841  if (typeof el.textContent === 'undefined') {
21842    el.innerText = text;
21843  } else {
21844    el.textContent = text;
21845  }
21846  return el;
21847}
21848
21849/**
21850 * Insert an element as the first child node of another
21851 *
21852 * @param {Element} child
21853 *        Element to insert
21854 *
21855 * @param {Element} parent
21856 *        Element to insert child into
21857 *
21858 */
21859function insertElFirst(child, parent) {
21860  if (parent.firstChild) {
21861    parent.insertBefore(child, parent.firstChild);
21862  } else {
21863    parent.appendChild(child);
21864  }
21865}
21866
21867/**
21868 * Element Data Store. Allows for binding data to an element without putting it directly on the element.
21869 * Ex. Event listeners are stored here.
21870 * (also from jsninja.com, slightly modified and updated for closure compiler)
21871 *
21872 * @type {Object}
21873 * @private
21874 */
21875var elData = {};
21876
21877/*
21878 * Unique attribute name to store an element's guid in
21879 *
21880 * @type {string}
21881 * @constant
21882 * @private
21883 */
21884var elIdAttr = 'vdata' + new Date().getTime();
21885
21886/**
21887 * Returns the cache object where data for an element is stored
21888 *
21889 * @param {Element} el
21890 *        Element to store data for.
21891 *
21892 * @return {Object}
21893 *         The cache object for that el that was passed in.
21894 */
21895function getElData(el) {
21896  var id = el[elIdAttr];
21897
21898  if (!id) {
21899    id = el[elIdAttr] = Guid.newGUID();
21900  }
21901
21902  if (!elData[id]) {
21903    elData[id] = {};
21904  }
21905
21906  return elData[id];
21907}
21908
21909/**
21910 * Returns whether or not an element has cached data
21911 *
21912 * @param {Element} el
21913 *        Check if this element has cached data.
21914 *
21915 * @return {boolean}
21916 *         - True if the DOM element has cached data.
21917 *         - False otherwise.
21918 */
21919function hasElData(el) {
21920  var id = el[elIdAttr];
21921
21922  if (!id) {
21923    return false;
21924  }
21925
21926  return !!Object.getOwnPropertyNames(elData[id]).length;
21927}
21928
21929/**
21930 * Delete data for the element from the cache and the guid attr from getElementById
21931 *
21932 * @param {Element} el
21933 *        Remove cached data for this element.
21934 */
21935function removeElData(el) {
21936  var id = el[elIdAttr];
21937
21938  if (!id) {
21939    return;
21940  }
21941
21942  // Remove all stored data
21943  delete elData[id];
21944
21945  // Remove the elIdAttr property from the DOM node
21946  try {
21947    delete el[elIdAttr];
21948  } catch (e) {
21949    if (el.removeAttribute) {
21950      el.removeAttribute(elIdAttr);
21951    } else {
21952      // IE doesn't appear to support removeAttribute on the document element
21953      el[elIdAttr] = null;
21954    }
21955  }
21956}
21957
21958/**
21959 * Check if an element has a CSS class
21960 *
21961 * @param {Element} element
21962 *        Element to check
21963 *
21964 * @param {string} classToCheck
21965 *        Class name to check for
21966 *
21967 * @return {boolean}
21968 *         - True if the element had the class
21969 *         - False otherwise.
21970 *
21971 * @throws {Error}
21972 *         Throws an error if `classToCheck` has white space.
21973 */
21974function hasElClass(element, classToCheck) {
21975  throwIfWhitespace(classToCheck);
21976  if (element.classList) {
21977    return element.classList.contains(classToCheck);
21978  }
21979  return classRegExp(classToCheck).test(element.className);
21980}
21981
21982/**
21983 * Add a CSS class name to an element
21984 *
21985 * @param {Element} element
21986 *        Element to add class name to.
21987 *
21988 * @param {string} classToAdd
21989 *        Class name to add.
21990 *
21991 * @return {Element}
21992 *         The dom element with the added class name.
21993 */
21994function addElClass(element, classToAdd) {
21995  if (element.classList) {
21996    element.classList.add(classToAdd);
21997
21998    // Don't need to `throwIfWhitespace` here because `hasElClass` will do it
21999    // in the case of classList not being supported.
22000  } else if (!hasElClass(element, classToAdd)) {
22001    element.className = (element.className + ' ' + classToAdd).trim();
22002  }
22003
22004  return element;
22005}
22006
22007/**
22008 * Remove a CSS class name from an element
22009 *
22010 * @param {Element} element
22011 *        Element to remove a class name from.
22012 *
22013 * @param {string} classToRemove
22014 *        Class name to remove
22015 *
22016 * @return {Element}
22017 *         The dom element with class name removed.
22018 */
22019function removeElClass(element, classToRemove) {
22020  if (element.classList) {
22021    element.classList.remove(classToRemove);
22022  } else {
22023    throwIfWhitespace(classToRemove);
22024    element.className = element.className.split(/\s+/).filter(function (c) {
22025      return c !== classToRemove;
22026    }).join(' ');
22027  }
22028
22029  return element;
22030}
22031
22032/**
22033 * The callback definition for toggleElClass.
22034 *
22035 * @callback Dom~PredicateCallback
22036 * @param {Element} element
22037 *        The DOM element of the Component.
22038 *
22039 * @param {string} classToToggle
22040 *        The `className` that wants to be toggled
22041 *
22042 * @return {boolean|undefined}
22043 *         - If true the `classToToggle` will get added to `element`.
22044 *         - If false the `classToToggle` will get removed from `element`.
22045 *         - If undefined this callback will be ignored
22046 */
22047
22048/**
22049 * Adds or removes a CSS class name on an element depending on an optional
22050 * condition or the presence/absence of the class name.
22051 *
22052 * @param {Element} element
22053 *        The element to toggle a class name on.
22054 *
22055 * @param {string} classToToggle
22056 *        The class that should be toggled
22057 *
22058 * @param {boolean|PredicateCallback} [predicate]
22059 *        See the return value for {@link Dom~PredicateCallback}
22060 *
22061 * @return {Element}
22062 *         The element with a class that has been toggled.
22063 */
22064function toggleElClass(element, classToToggle, predicate) {
22065
22066  // This CANNOT use `classList` internally because IE does not support the
22067  // second parameter to the `classList.toggle()` method! Which is fine because
22068  // `classList` will be used by the add/remove functions.
22069  var has = hasElClass(element, classToToggle);
22070
22071  if (typeof predicate === 'function') {
22072    predicate = predicate(element, classToToggle);
22073  }
22074
22075  if (typeof predicate !== 'boolean') {
22076    predicate = !has;
22077  }
22078
22079  // If the necessary class operation matches the current state of the
22080  // element, no action is required.
22081  if (predicate === has) {
22082    return;
22083  }
22084
22085  if (predicate) {
22086    addElClass(element, classToToggle);
22087  } else {
22088    removeElClass(element, classToToggle);
22089  }
22090
22091  return element;
22092}
22093
22094/**
22095 * Apply attributes to an HTML element.
22096 *
22097 * @param {Element} el
22098 *        Element to add attributes to.
22099 *
22100 * @param {Object} [attributes]
22101 *        Attributes to be applied.
22102 */
22103function setElAttributes(el, attributes) {
22104  Object.getOwnPropertyNames(attributes).forEach(function (attrName) {
22105    var attrValue = attributes[attrName];
22106
22107    if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) {
22108      el.removeAttribute(attrName);
22109    } else {
22110      el.setAttribute(attrName, attrValue === true ? '' : attrValue);
22111    }
22112  });
22113}
22114
22115/**
22116 * Get an element's attribute values, as defined on the HTML tag
22117 * Attributes are not the same as properties. They're defined on the tag
22118 * or with setAttribute (which shouldn't be used with HTML)
22119 * This will return true or false for boolean attributes.
22120 *
22121 * @param {Element} tag
22122 *        Element from which to get tag attributes.
22123 *
22124 * @return {Object}
22125 *         All attributes of the element.
22126 */
22127function getElAttributes(tag) {
22128  var obj = {};
22129
22130  // known boolean attributes
22131  // we can check for matching boolean properties, but older browsers
22132  // won't know about HTML5 boolean attributes that we still read from
22133  var knownBooleans = ',' + 'autoplay,controls,loop,muted,default' + ',';
22134
22135  if (tag && tag.attributes && tag.attributes.length > 0) {
22136    var attrs = tag.attributes;
22137
22138    for (var i = attrs.length - 1; i >= 0; i--) {
22139      var attrName = attrs[i].name;
22140      var attrVal = attrs[i].value;
22141
22142      // check for known booleans
22143      // the matching element property will return a value for typeof
22144      if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(',' + attrName + ',') !== -1) {
22145        // the value of an included boolean attribute is typically an empty
22146        // string ('') which would equal false if we just check for a false value.
22147        // we also don't want support bad code like autoplay='false'
22148        attrVal = attrVal !== null ? true : false;
22149      }
22150
22151      obj[attrName] = attrVal;
22152    }
22153  }
22154
22155  return obj;
22156}
22157
22158/**
22159 * Get the value of an element's attribute
22160 *
22161 * @param {Element} el
22162 *        A DOM element
22163 *
22164 * @param {string} attribute
22165 *        Attribute to get the value of
22166 *
22167 * @return {string}
22168 *         value of the attribute
22169 */
22170function getAttribute(el, attribute) {
22171  return el.getAttribute(attribute);
22172}
22173
22174/**
22175 * Set the value of an element's attribute
22176 *
22177 * @param {Element} el
22178 *        A DOM element
22179 *
22180 * @param {string} attribute
22181 *        Attribute to set
22182 *
22183 * @param {string} value
22184 *        Value to set the attribute to
22185 */
22186function setAttribute(el, attribute, value) {
22187  el.setAttribute(attribute, value);
22188}
22189
22190/**
22191 * Remove an element's attribute
22192 *
22193 * @param {Element} el
22194 *        A DOM element
22195 *
22196 * @param {string} attribute
22197 *        Attribute to remove
22198 */
22199function removeAttribute(el, attribute) {
22200  el.removeAttribute(attribute);
22201}
22202
22203/**
22204 * Attempt to block the ability to select text while dragging controls
22205 */
22206function blockTextSelection() {
22207  _document2['default'].body.focus();
22208  _document2['default'].onselectstart = function () {
22209    return false;
22210  };
22211}
22212
22213/**
22214 * Turn off text selection blocking
22215 */
22216function unblockTextSelection() {
22217  _document2['default'].onselectstart = function () {
22218    return true;
22219  };
22220}
22221
22222/**
22223 * The postion of a DOM element on the page.
22224 *
22225 * @typedef {Object} Dom~Position
22226 *
22227 * @property {number} left
22228 *           Pixels to the left
22229 *
22230 * @property {number} top
22231 *           Pixels on top
22232 */
22233
22234/**
22235 * Offset Left.
22236 * getBoundingClientRect technique from
22237 * John Resig
22238 *
22239 * @see http://ejohn.org/blog/getboundingclientrect-is-awesome/
22240 *
22241 * @param {Element} el
22242 *        Element from which to get offset
22243 *
22244 * @return {Dom~Position}
22245 *         The position of the element that was passed in.
22246 */
22247function findElPosition(el) {
22248  var box = void 0;
22249
22250  if (el.getBoundingClientRect && el.parentNode) {
22251    box = el.getBoundingClientRect();
22252  }
22253
22254  if (!box) {
22255    return {
22256      left: 0,
22257      top: 0
22258    };
22259  }
22260
22261  var docEl = _document2['default'].documentElement;
22262  var body = _document2['default'].body;
22263
22264  var clientLeft = docEl.clientLeft || body.clientLeft || 0;
22265  var scrollLeft = _window2['default'].pageXOffset || body.scrollLeft;
22266  var left = box.left + scrollLeft - clientLeft;
22267
22268  var clientTop = docEl.clientTop || body.clientTop || 0;
22269  var scrollTop = _window2['default'].pageYOffset || body.scrollTop;
22270  var top = box.top + scrollTop - clientTop;
22271
22272  // Android sometimes returns slightly off decimal values, so need to round
22273  return {
22274    left: Math.round(left),
22275    top: Math.round(top)
22276  };
22277}
22278
22279/**
22280 * x and y coordinates for a dom element or mouse pointer
22281 *
22282 * @typedef {Object} Dom~Coordinates
22283 *
22284 * @property {number} x
22285 *           x coordinate in pixels
22286 *
22287 * @property {number} y
22288 *           y coordinate in pixels
22289 */
22290
22291/**
22292 * Get pointer position in element
22293 * Returns an object with x and y coordinates.
22294 * The base on the coordinates are the bottom left of the element.
22295 *
22296 * @param {Element} el
22297 *        Element on which to get the pointer position on
22298 *
22299 * @param {EventTarget~Event} event
22300 *        Event object
22301 *
22302 * @return {Dom~Coordinates}
22303 *         A Coordinates object corresponding to the mouse position.
22304 *
22305 */
22306function getPointerPosition(el, event) {
22307  var position = {};
22308  var box = findElPosition(el);
22309  var boxW = el.offsetWidth;
22310  var boxH = el.offsetHeight;
22311
22312  var boxY = box.top;
22313  var boxX = box.left;
22314  var pageY = event.pageY;
22315  var pageX = event.pageX;
22316
22317  if (event.changedTouches) {
22318    pageX = event.changedTouches[0].pageX;
22319    pageY = event.changedTouches[0].pageY;
22320  }
22321
22322  position.y = Math.max(0, Math.min(1, (boxY - pageY + boxH) / boxH));
22323  position.x = Math.max(0, Math.min(1, (pageX - boxX) / boxW));
22324
22325  return position;
22326}
22327
22328/**
22329 * Determines, via duck typing, whether or not a value is a text node.
22330 *
22331 * @param {Mixed} value
22332 *        Check if this value is a text node.
22333 *
22334 * @return {boolean}
22335 *         - True if it is a text node
22336 *         - False otherwise
22337 */
22338function isTextNode(value) {
22339  return (0, _obj.isObject)(value) && value.nodeType === 3;
22340}
22341
22342/**
22343 * Empties the contents of an element.
22344 *
22345 * @param {Element} el
22346 *        The element to empty children from
22347 *
22348 * @return {Element}
22349 *         The element with no children
22350 */
22351function emptyEl(el) {
22352  while (el.firstChild) {
22353    el.removeChild(el.firstChild);
22354  }
22355  return el;
22356}
22357
22358/**
22359 * Normalizes content for eventual insertion into the DOM.
22360 *
22361 * This allows a wide range of content definition methods, but protects
22362 * from falling into the trap of simply writing to `innerHTML`, which is
22363 * an XSS concern.
22364 *
22365 * The content for an element can be passed in multiple types and
22366 * combinations, whose behavior is as follows:
22367 *
22368 * @param {String|Element|TextNode|Array|Function} content
22369 *        - String: Normalized into a text node.
22370 *        - Element/TextNode: Passed through.
22371 *        - Array: A one-dimensional array of strings, elements, nodes, or functions
22372 *          (which return single strings, elements, or nodes).
22373 *        - Function: If the sole argument, is expected to produce a string, element,
22374 *          node, or array as defined above.
22375 *
22376 * @return {Array}
22377 *         All of the content that was passed in normalized.
22378 */
22379function normalizeContent(content) {
22380
22381  // First, invoke content if it is a function. If it produces an array,
22382  // that needs to happen before normalization.
22383  if (typeof content === 'function') {
22384    content = content();
22385  }
22386
22387  // Next up, normalize to an array, so one or many items can be normalized,
22388  // filtered, and returned.
22389  return (Array.isArray(content) ? content : [content]).map(function (value) {
22390
22391    // First, invoke value if it is a function to produce a new value,
22392    // which will be subsequently normalized to a Node of some kind.
22393    if (typeof value === 'function') {
22394      value = value();
22395    }
22396
22397    if (isEl(value) || isTextNode(value)) {
22398      return value;
22399    }
22400
22401    if (typeof value === 'string' && /\S/.test(value)) {
22402      return _document2['default'].createTextNode(value);
22403    }
22404  }).filter(function (value) {
22405    return value;
22406  });
22407}
22408
22409/**
22410 * Normalizes and appends content to an element.
22411 *
22412 * @param {Element} el
22413 *        Element to append normalized content to.
22414 *
22415 *
22416 * @param {String|Element|TextNode|Array|Function} content
22417 *        See the `content` argument of {@link dom:normalizeContent}
22418 *
22419 * @return {Element}
22420 *         The element with appended normalized content.
22421 */
22422function appendContent(el, content) {
22423  normalizeContent(content).forEach(function (node) {
22424    return el.appendChild(node);
22425  });
22426  return el;
22427}
22428
22429/**
22430 * Normalizes and inserts content into an element; this is identical to
22431 * `appendContent()`, except it empties the element first.
22432 *
22433 * @param {Element} el
22434 *        Element to insert normalized content into.
22435 *
22436 * @param {String|Element|TextNode|Array|Function} content
22437 *        See the `content` argument of {@link dom:normalizeContent}
22438 *
22439 * @return {Element}
22440 *         The element with inserted normalized content.
22441 *
22442 */
22443function insertContent(el, content) {
22444  return appendContent(emptyEl(el), content);
22445}
22446
22447/**
22448 * Finds a single DOM element matching `selector` within the optional
22449 * `context` of another DOM element (defaulting to `document`).
22450 *
22451 * @param {string} selector
22452 *        A valid CSS selector, which will be passed to `querySelector`.
22453 *
22454 * @param {Element|String} [context=document]
22455 *        A DOM element within which to query. Can also be a selector
22456 *        string in which case the first matching element will be used
22457 *        as context. If missing (or no element matches selector), falls
22458 *        back to `document`.
22459 *
22460 * @return {Element|null}
22461 *         The element that was found or null.
22462 */
22463var $ = exports.$ = createQuerier('querySelector');
22464
22465/**
22466 * Finds a all DOM elements matching `selector` within the optional
22467 * `context` of another DOM element (defaulting to `document`).
22468 *
22469 * @param {string} selector
22470 *           A valid CSS selector, which will be passed to `querySelectorAll`.
22471 *
22472 * @param {Element|String} [context=document]
22473 *           A DOM element within which to query. Can also be a selector
22474 *           string in which case the first matching element will be used
22475 *           as context. If missing (or no element matches selector), falls
22476 *           back to `document`.
22477 *
22478 * @return {NodeList}
22479 *         A element list of elements that were found. Will be empty if none were found.
22480 *
22481 */
22482var $$ = exports.$$ = createQuerier('querySelectorAll');
22483
22484},{"85":85,"86":86,"88":88,"94":94,"95":95,"98":98}],82:[function(_dereq_,module,exports){
22485'use strict';
22486
22487exports.__esModule = true;
22488exports.fixEvent = fixEvent;
22489exports.on = on;
22490exports.off = off;
22491exports.trigger = trigger;
22492exports.one = one;
22493
22494var _dom = _dereq_(81);
22495
22496var Dom = _interopRequireWildcard(_dom);
22497
22498var _guid = _dereq_(85);
22499
22500var Guid = _interopRequireWildcard(_guid);
22501
22502var _log = _dereq_(86);
22503
22504var _log2 = _interopRequireDefault(_log);
22505
22506var _window = _dereq_(95);
22507
22508var _window2 = _interopRequireDefault(_window);
22509
22510var _document = _dereq_(94);
22511
22512var _document2 = _interopRequireDefault(_document);
22513
22514function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
22515
22516function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
22517
22518/**
22519 * Clean up the listener cache and dispatchers
22520 *
22521 * @param {Element|Object} elem
22522 *        Element to clean up
22523 *
22524 * @param {string} type
22525 *        Type of event to clean up
22526 */
22527function _cleanUpEvents(elem, type) {
22528  var data = Dom.getElData(elem);
22529
22530  // Remove the events of a particular type if there are none left
22531  if (data.handlers[type].length === 0) {
22532    delete data.handlers[type];
22533    // data.handlers[type] = null;
22534    // Setting to null was causing an error with data.handlers
22535
22536    // Remove the meta-handler from the element
22537    if (elem.removeEventListener) {
22538      elem.removeEventListener(type, data.dispatcher, false);
22539    } else if (elem.detachEvent) {
22540      elem.detachEvent('on' + type, data.dispatcher);
22541    }
22542  }
22543
22544  // Remove the events object if there are no types left
22545  if (Object.getOwnPropertyNames(data.handlers).length <= 0) {
22546    delete data.handlers;
22547    delete data.dispatcher;
22548    delete data.disabled;
22549  }
22550
22551  // Finally remove the element data if there is no data left
22552  if (Object.getOwnPropertyNames(data).length === 0) {
22553    Dom.removeElData(elem);
22554  }
22555}
22556
22557/**
22558 * Loops through an array of event types and calls the requested method for each type.
22559 *
22560 * @param {Function} fn
22561 *        The event method we want to use.
22562 *
22563 * @param {Element|Object} elem
22564 *        Element or object to bind listeners to
22565 *
22566 * @param {string} type
22567 *        Type of event to bind to.
22568 *
22569 * @param {EventTarget~EventListener} callback
22570 *        Event listener.
22571 */
22572/**
22573 * @file events.js. An Event System (John Resig - Secrets of a JS Ninja http://jsninja.com/)
22574 * (Original book version wasn't completely usable, so fixed some things and made Closure Compiler compatible)
22575 * This should work very similarly to jQuery's events, however it's based off the book version which isn't as
22576 * robust as jquery's, so there's probably some differences.
22577 *
22578 * @module events
22579 */
22580
22581function _handleMultipleEvents(fn, elem, types, callback) {
22582  types.forEach(function (type) {
22583    // Call the event method for each one of the types
22584    fn(elem, type, callback);
22585  });
22586}
22587
22588/**
22589 * Fix a native event to have standard property values
22590 *
22591 * @param {Object} event
22592 *        Event object to fix.
22593 *
22594 * @return {Object}
22595 *         Fixed event object.
22596 */
22597function fixEvent(event) {
22598
22599  function returnTrue() {
22600    return true;
22601  }
22602
22603  function returnFalse() {
22604    return false;
22605  }
22606
22607  // Test if fixing up is needed
22608  // Used to check if !event.stopPropagation instead of isPropagationStopped
22609  // But native events return true for stopPropagation, but don't have
22610  // other expected methods like isPropagationStopped. Seems to be a problem
22611  // with the Javascript Ninja code. So we're just overriding all events now.
22612  if (!event || !event.isPropagationStopped) {
22613    var old = event || _window2['default'].event;
22614
22615    event = {};
22616    // Clone the old object so that we can modify the values event = {};
22617    // IE8 Doesn't like when you mess with native event properties
22618    // Firefox returns false for event.hasOwnProperty('type') and other props
22619    //  which makes copying more difficult.
22620    // TODO: Probably best to create a whitelist of event props
22621    for (var key in old) {
22622      // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y
22623      // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation
22624      // and webkitMovementX/Y
22625      if (key !== 'layerX' && key !== 'layerY' && key !== 'keyLocation' && key !== 'webkitMovementX' && key !== 'webkitMovementY') {
22626        // Chrome 32+ warns if you try to copy deprecated returnValue, but
22627        // we still want to if preventDefault isn't supported (IE8).
22628        if (!(key === 'returnValue' && old.preventDefault)) {
22629          event[key] = old[key];
22630        }
22631      }
22632    }
22633
22634    // The event occurred on this element
22635    if (!event.target) {
22636      event.target = event.srcElement || _document2['default'];
22637    }
22638
22639    // Handle which other element the event is related to
22640    if (!event.relatedTarget) {
22641      event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
22642    }
22643
22644    // Stop the default browser action
22645    event.preventDefault = function () {
22646      if (old.preventDefault) {
22647        old.preventDefault();
22648      }
22649      event.returnValue = false;
22650      old.returnValue = false;
22651      event.defaultPrevented = true;
22652    };
22653
22654    event.defaultPrevented = false;
22655
22656    // Stop the event from bubbling
22657    event.stopPropagation = function () {
22658      if (old.stopPropagation) {
22659        old.stopPropagation();
22660      }
22661      event.cancelBubble = true;
22662      old.cancelBubble = true;
22663      event.isPropagationStopped = returnTrue;
22664    };
22665
22666    event.isPropagationStopped = returnFalse;
22667
22668    // Stop the event from bubbling and executing other handlers
22669    event.stopImmediatePropagation = function () {
22670      if (old.stopImmediatePropagation) {
22671        old.stopImmediatePropagation();
22672      }
22673      event.isImmediatePropagationStopped = returnTrue;
22674      event.stopPropagation();
22675    };
22676
22677    event.isImmediatePropagationStopped = returnFalse;
22678
22679    // Handle mouse position
22680    if (event.clientX !== null && event.clientX !== undefined) {
22681      var doc = _document2['default'].documentElement;
22682      var body = _document2['default'].body;
22683
22684      event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
22685      event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
22686    }
22687
22688    // Handle key presses
22689    event.which = event.charCode || event.keyCode;
22690
22691    // Fix button for mouse clicks:
22692    // 0 == left; 1 == middle; 2 == right
22693    if (event.button !== null && event.button !== undefined) {
22694
22695      // The following is disabled because it does not pass videojs-standard
22696      // and... yikes.
22697      /* eslint-disable */
22698      event.button = event.button & 1 ? 0 : event.button & 4 ? 1 : event.button & 2 ? 2 : 0;
22699      /* eslint-enable */
22700    }
22701  }
22702
22703  // Returns fixed-up instance
22704  return event;
22705}
22706
22707/**
22708 * Whether passive event listeners are supported
22709 */
22710var _supportsPassive = false;
22711
22712(function () {
22713  try {
22714    var opts = Object.defineProperty({}, 'passive', {
22715      get: function get() {
22716        _supportsPassive = true;
22717      }
22718    });
22719
22720    _window2['default'].addEventListener('test', null, opts);
22721  } catch (e) {
22722    // disregard
22723  }
22724})();
22725
22726/**
22727 * Touch events Chrome expects to be passive
22728 */
22729var passiveEvents = ['touchstart', 'touchmove'];
22730
22731/**
22732 * Add an event listener to element
22733 * It stores the handler function in a separate cache object
22734 * and adds a generic handler to the element's event,
22735 * along with a unique id (guid) to the element.
22736 *
22737 * @param {Element|Object} elem
22738 *        Element or object to bind listeners to
22739 *
22740 * @param {string|string[]} type
22741 *        Type of event to bind to.
22742 *
22743 * @param {EventTarget~EventListener} fn
22744 *        Event listener.
22745 */
22746function on(elem, type, fn) {
22747  if (Array.isArray(type)) {
22748    return _handleMultipleEvents(on, elem, type, fn);
22749  }
22750
22751  var data = Dom.getElData(elem);
22752
22753  // We need a place to store all our handler data
22754  if (!data.handlers) {
22755    data.handlers = {};
22756  }
22757
22758  if (!data.handlers[type]) {
22759    data.handlers[type] = [];
22760  }
22761
22762  if (!fn.guid) {
22763    fn.guid = Guid.newGUID();
22764  }
22765
22766  data.handlers[type].push(fn);
22767
22768  if (!data.dispatcher) {
22769    data.disabled = false;
vendor: 4,712 bytes, lines 22770-22938
22770
22771    data.dispatcher = function (event, hash) {
22772
22773      if (data.disabled) {
22774        return;
22775      }
22776
22777      event = fixEvent(event);
22778
22779      var handlers = data.handlers[event.type];
22780
22781      if (handlers) {
22782        // Copy handlers so if handlers are added/removed during the process it doesn't throw everything off.
22783        var handlersCopy = handlers.slice(0);
22784
22785        for (var m = 0, n = handlersCopy.length; m < n; m++) {
22786          if (event.isImmediatePropagationStopped()) {
22787            break;
22788          } else {
22789            try {
22790              handlersCopy[m].call(elem, event, hash);
22791            } catch (e) {
22792              _log2['default'].error(e);
22793            }
22794          }
22795        }
22796      }
22797    };
22798  }
22799
22800  if (data.handlers[type].length === 1) {
22801    if (elem.addEventListener) {
22802      var options = false;
22803
22804      if (_supportsPassive && passiveEvents.indexOf(type) > -1) {
22805        options = { passive: true };
22806      }
22807      elem.addEventListener(type, data.dispatcher, options);
22808    } else if (elem.attachEvent) {
22809      elem.attachEvent('on' + type, data.dispatcher);
22810    }
22811  }
22812}
22813
22814/**
22815 * Removes event listeners from an element
22816 *
22817 * @param {Element|Object} elem
22818 *        Object to remove listeners from.
22819 *
22820 * @param {string|string[]} [type]
22821 *        Type of listener to remove. Don't include to remove all events from element.
22822 *
22823 * @param {EventTarget~EventListener} [fn]
22824 *        Specific listener to remove. Don't include to remove listeners for an event
22825 *        type.
22826 */
22827function off(elem, type, fn) {
22828  // Don't want to add a cache object through getElData if not needed
22829  if (!Dom.hasElData(elem)) {
22830    return;
22831  }
22832
22833  var data = Dom.getElData(elem);
22834
22835  // If no events exist, nothing to unbind
22836  if (!data.handlers) {
22837    return;
22838  }
22839
22840  if (Array.isArray(type)) {
22841    return _handleMultipleEvents(off, elem, type, fn);
22842  }
22843
22844  // Utility function
22845  var removeType = function removeType(t) {
22846    data.handlers[t] = [];
22847    _cleanUpEvents(elem, t);
22848  };
22849
22850  // Are we removing all bound events?
22851  if (!type) {
22852    for (var t in data.handlers) {
22853      removeType(t);
22854    }
22855    return;
22856  }
22857
22858  var handlers = data.handlers[type];
22859
22860  // If no handlers exist, nothing to unbind
22861  if (!handlers) {
22862    return;
22863  }
22864
22865  // If no listener was provided, remove all listeners for type
22866  if (!fn) {
22867    removeType(type);
22868    return;
22869  }
22870
22871  // We're only removing a single handler
22872  if (fn.guid) {
22873    for (var n = 0; n < handlers.length; n++) {
22874      if (handlers[n].guid === fn.guid) {
22875        handlers.splice(n--, 1);
22876      }
22877    }
22878  }
22879
22880  _cleanUpEvents(elem, type);
22881}
22882
22883/**
22884 * Trigger an event for an element
22885 *
22886 * @param {Element|Object} elem
22887 *        Element to trigger an event on
22888 *
22889 * @param {EventTarget~Event|string} event
22890 *        A string (the type) or an event object with a type attribute
22891 *
22892 * @param {Object} [hash]
22893 *        data hash to pass along with the event
22894 *
22895 * @return {boolean|undefined}
22896 *         - Returns the opposite of `defaultPrevented` if default was prevented
22897 *         - Otherwise returns undefined
22898 */
22899function trigger(elem, event, hash) {
22900  // Fetches element data and a reference to the parent (for bubbling).
22901  // Don't want to add a data object to cache for every parent,
22902  // so checking hasElData first.
22903  var elemData = Dom.hasElData(elem) ? Dom.getElData(elem) : {};
22904  var parent = elem.parentNode || elem.ownerDocument;
22905  // type = event.type || event,
22906  // handler;
22907
22908  // If an event name was passed as a string, creates an event out of it
22909  if (typeof event === 'string') {
22910    event = { type: event, target: elem };
22911  }
22912  // Normalizes the event properties.
22913  event = fixEvent(event);
22914
22915  // If the passed element has a dispatcher, executes the established handlers.
22916  if (elemData.dispatcher) {
22917    elemData.dispatcher.call(elem, event, hash);
22918  }
22919
22920  // Unless explicitly stopped or the event does not bubble (e.g. media events)
22921  // recursively calls this function to bubble the event up the DOM.
22922  if (parent && !event.isPropagationStopped() && event.bubbles === true) {
22923    trigger.call(null, parent, event, hash);
22924
22925    // If at the top of the DOM, triggers the default action unless disabled.
22926  } else if (!parent && !event.defaultPrevented) {
22927    var targetData = Dom.getElData(event.target);
22928
22929    // Checks if the target has a default action for this event.
22930    if (event.target[event.type]) {
22931      // Temporarily disables event dispatching on the target as we have already executed the handler.
22932      targetData.disabled = true;
22933      // Executes the default action.
22934      if (typeof event.target[event.type] === 'function') {
22935        event.target[event.type]();
22936      }
22937      // Re-enables event dispatching.
22938      targetData.disabled = false;
22939    }
22940  }
22941
22942  // Inform the triggerer if the default was prevented by returning false
22943  return !event.defaultPrevented;
22944}
22945
22946/**
22947 * Trigger a listener only once for an event
22948 *
22949 * @param {Element|Object} elem
22950 *        Element or object to bind to.
22951 *
22952 * @param {string|string[]} type
22953 *        Name/type of event
22954 *
22955 * @param {Event~EventListener} fn
22956 *        Event Listener function
22957 */
22958function one(elem, type, fn) {
22959  if (Array.isArray(type)) {
22960    return _handleMultipleEvents(one, elem, type, fn);
22961  }
22962  var func = function func() {
22963    off(elem, type, func);
22964    fn.apply(this, arguments);
22965  };
22966
22967  // copy the guid to the new function so it can removed using the original function's ID
22968  func.guid = fn.guid = fn.guid || Guid.newGUID();
22969  on(elem, type, func);
22970}
22971
22972},{"81":81,"85":85,"86":86,"94":94,"95":95}],83:[function(_dereq_,module,exports){
22973'use strict';
22974
22975exports.__esModule = true;
22976exports.throttle = exports.bind = undefined;
22977
22978var _guid = _dereq_(85);
22979
22980/**
22981 * Bind (a.k.a proxy or Context). A simple method for changing the context of a function
22982 * It also stores a unique id on the function so it can be easily removed from events.
22983 *
22984 * @param {Mixed} context
22985 *        The object to bind as scope.
22986 *
22987 * @param {Function} fn
22988 *        The function to be bound to a scope.
22989 *
22990 * @param {number} [uid]
22991 *        An optional unique ID for the function to be set
22992 *
22993 * @return {Function}
22994 *         The new function that will be bound into the context given
22995 */
22996var bind = exports.bind = function bind(context, fn, uid) {
22997  // Make sure the function has a unique ID
22998  if (!fn.guid) {
22999    fn.guid = (0, _guid.newGUID)();
23000  }
23001
23002  // Create the new function that changes the context
23003  var bound = function bound() {
23004    return fn.apply(context, arguments);
23005  };
23006
23007  // Allow for the ability to individualize this function
23008  // Needed in the case where multiple objects might share the same prototype
23009  // IF both items add an event listener with the same function, then you try to remove just one
23010  // it will remove both because they both have the same guid.
23011  // when using this, you need to use the bind method when you remove the listener as well.
23012  // currently used in text tracks
23013  bound.guid = uid ? uid + '_' + fn.guid : fn.guid;
23014
23015  return bound;
23016};
23017
23018/**
23019 * Wraps the given function, `fn`, with a new function that only invokes `fn`
23020 * at most once per every `wait` milliseconds.
23021 *
23022 * @param  {Function} fn
23023 *         The function to be throttled.
23024 *
23025 * @param  {Number}   wait
23026 *         The number of milliseconds by which to throttle.
23027 *
23028 * @return {Function}
23029 */
23030/**
23031 * @file fn.js
23032 * @module fn
23033 */
23034var throttle = exports.throttle = function throttle(fn, wait) {
23035  var last = Date.now();
23036
23037  var throttled = function throttled() {
23038    var now = Date.now();
23039
23040    if (now - last >= wait) {
23041      fn.apply(undefined, arguments);
23042      last = now;
23043    }
23044  };
23045
23046  return throttled;
23047};
23048
23049},{"85":85}],84:[function(_dereq_,module,exports){
23050'use strict';
23051
23052exports.__esModule = true;
23053/**
23054 * @file format-time.js
23055 * @module Format-time
23056 */
23057
23058/**
23059 * Format seconds as a time string, H:MM:SS or M:SS. Supplying a guide (in seconds)
23060 * will force a number of leading zeros to cover the length of the guide.
23061 *
23062 * @param {number} seconds
23063 *        Number of seconds to be turned into a string
23064 *
23065 * @param {number} guide
23066 *        Number (in seconds) to model the string after
23067 *
23068 * @return {string}
23069 *         Time formatted as H:MM:SS or M:SS
23070 */
23071function formatTime(seconds) {
23072  var guide = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : seconds;
23073
23074  seconds = seconds < 0 ? 0 : seconds;
23075  var s = Math.floor(seconds % 60);
23076  var m = Math.floor(seconds / 60 % 60);
23077  var h = Math.floor(seconds / 3600);
23078  var gm = Math.floor(guide / 60 % 60);
23079  var gh = Math.floor(guide / 3600);
23080
23081  // handle invalid times
23082  if (isNaN(seconds) || seconds === Infinity) {
23083    // '-' is false for all relational operators (e.g. <, >=) so this setting
23084    // will add the minimum number of fields specified by the guide
23085    h = m = s = '-';
23086  }
23087
23088  // Check if we need to show hours
23089  h = h > 0 || gh > 0 ? h + ':' : '';
23090
23091  // If hours are showing, we may need to add a leading zero.
23092  // Always show at least one digit of minutes.
23093  m = ((h || gm >= 10) && m < 10 ? '0' + m : m) + ':';
23094
23095  // Check if leading zero is need for seconds
23096  s = s < 10 ? '0' + s : s;
23097
23098  return h + m + s;
23099}
23100
23101exports['default'] = formatTime;
23102
23103},{}],85:[function(_dereq_,module,exports){
23104"use strict";
23105
23106exports.__esModule = true;
23107exports.newGUID = newGUID;
23108/**
23109 * @file guid.js
23110 * @module guid
23111 */
23112
23113/**
23114 * Unique ID for an element or function
23115 * @type {Number}
23116 */
23117var _guid = 1;
23118
23119/**
23120 * Get a unique auto-incrementing ID by number that has not been returned before.
23121 *
23122 * @return {number}
23123 *         A new unique ID.
23124 */
23125function newGUID() {
23126  return _guid++;
23127}
23128
23129},{}],86:[function(_dereq_,module,exports){
23130'use strict';
23131
23132exports.__esModule = true;
23133exports.logByType = undefined;
23134
23135var _window = _dereq_(95);
23136
23137var _window2 = _interopRequireDefault(_window);
23138
23139var _browser = _dereq_(78);
23140
23141var _obj = _dereq_(88);
23142
23143function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
23144
23145var log = void 0;
23146
23147/**
23148 * Log messages to the console and history based on the type of message
23149 *
23150 * @param  {string} type
23151 *         The name of the console method to use.
23152 *
23153 * @param  {Array} args
23154 *         The arguments to be passed to the matching console method.
23155 *
23156 * @param  {boolean} [stringify]
23157 *         By default, only old IEs should get console argument stringification,
23158 *         but this is exposed as a parameter to facilitate testing.
23159 */
23160/**
23161 * @file log.js
23162 * @module log
23163 */
23164var logByType = exports.logByType = function logByType(type, args) {
23165  var stringify = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : !!_browser.IE_VERSION && _browser.IE_VERSION < 11;
23166
23167
23168  if (type !== 'log') {
23169
23170    // add the type to the front of the message when it's not "log"
23171    args.unshift(type.toUpperCase() + ':');
23172  }
23173
23174  // add to history
23175  log.history.push(args);
23176
23177  // add console prefix after adding to history
23178  args.unshift('VIDEOJS:');
23179
23180  // If there's no console then don't try to output messages, but they will
23181  // still be stored in `log.history`.
23182  //
23183  // Was setting these once outside of this function, but containing them
23184  // in the function makes it easier to test cases where console doesn't exist
23185  // when the module is executed.
23186  var fn = _window2['default'].console && _window2['default'].console[type];
23187
23188  // Bail out if there's no console.
23189  if (!fn) {
23190    return;
23191  }
23192
23193  // IEs previous to 11 log objects uselessly as "[object Object]"; so, JSONify
23194  // objects and arrays for those less-capable browsers.
23195  if (stringify) {
23196    args = args.map(function (a) {
23197      if ((0, _obj.isObject)(a) || Array.isArray(a)) {
23198        try {
23199          return JSON.stringify(a);
23200        } catch (x) {
23201          return String(a);
23202        }
23203      }
23204
23205      // Cast to string before joining, so we get null and undefined explicitly
23206      // included in output (as we would in a modern console).
23207      return String(a);
23208    }).join(' ');
23209  }
23210
23211  // Old IE versions do not allow .apply() for console methods (they are
23212  // reported as objects rather than functions).
23213  if (!fn.apply) {
23214    fn(args);
23215  } else {
23216    fn[Array.isArray(args) ? 'apply' : 'call'](_window2['default'].console, args);
23217  }
23218};
23219
23220/**
23221 * Log plain debug messages
23222 *
23223 * @param {Mixed[]} args
23224 *        One or more messages or objects that should be logged.
23225 */
23226log = function log() {
23227  for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
23228    args[_key] = arguments[_key];
23229  }
23230
23231  logByType('log', args);
23232};
23233
23234/**
23235 * Keep a history of log messages
23236 *
23237 * @type {Array}
23238 */
23239log.history = [];
23240
23241/**
23242 * Log error messages
23243 *
23244 * @param {Mixed[]} args
23245 *        One or more messages or objects that should be logged as an error
23246 */
23247log.error = function () {
23248  for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
23249    args[_key2] = arguments[_key2];
23250  }
23251
23252  return logByType('error', args);
23253};
23254
23255/**
23256 * Log warning messages
23257 *
23258 * @param {Mixed[]} args
23259 *        One or more messages or objects that should be logged as a warning.
23260 */
23261log.warn = function () {
23262  for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
23263    args[_key3] = arguments[_key3];
23264  }
23265
23266  return logByType('warn', args);
23267};
23268
23269exports['default'] = log;
23270
23271},{"78":78,"88":88,"95":95}],87:[function(_dereq_,module,exports){
23272'use strict';
23273
23274exports.__esModule = true;
23275exports['default'] = mergeOptions;
23276
23277var _obj = _dereq_(88);
23278
23279/**
23280 * Deep-merge one or more options objects, recursively merging **only** plain
23281 * object properties.
23282 *
23283 * @param   {Object[]} sources
23284 *          One or more objects to merge into a new object.
23285 *
23286 * @returns {Object}
23287 *          A new object that is the merged result of all sources.
23288 */
23289function mergeOptions() {
23290  var result = {};
23291
23292  for (var _len = arguments.length, sources = Array(_len), _key = 0; _key < _len; _key++) {
23293    sources[_key] = arguments[_key];
23294  }
23295
23296  sources.forEach(function (source) {
23297    if (!source) {
23298      return;
23299    }
23300
23301    (0, _obj.each)(source, function (value, key) {
23302      if (!(0, _obj.isPlain)(value)) {
23303        result[key] = value;
23304        return;
23305      }
23306
23307      if (!(0, _obj.isPlain)(result[key])) {
23308        result[key] = {};
23309      }
23310
23311      result[key] = mergeOptions(result[key], value);
23312    });
23313  });
23314
23315  return result;
23316} /**
23317   * @file merge-options.js
23318   * @module merge-options
23319   */
23320
23321},{"88":88}],88:[function(_dereq_,module,exports){
23322'use strict';
23323
23324exports.__esModule = true;
23325
23326var _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; };
23327
23328exports.each = each;
23329exports.reduce = reduce;
23330exports.assign = assign;
23331exports.isObject = isObject;
23332exports.isPlain = isPlain;
23333/**
23334 * @file obj.js
23335 * @module obj
23336 */
23337
23338/**
23339 * @callback obj:EachCallback
23340 *
23341 * @param {Mixed} value
23342 *        The current key for the object that is being iterated over.
23343 *
23344 * @param {string} key
23345 *        The current key-value for object that is being iterated over
23346 */
23347
23348/**
23349 * @callback obj:ReduceCallback
23350 *
23351 * @param {Mixed} accum
23352 *        The value that is accumulating over the reduce loop.
23353 *
23354 * @param {Mixed} value
23355 *        The current key for the object that is being iterated over.
23356 *
23357 * @param {string} key
23358 *        The current key-value for object that is being iterated over
23359 *
23360 * @return {Mixed}
23361 *         The new accumulated value.
23362 */
23363var toString = Object.prototype.toString;
23364
23365/**
23366 * Get the keys of an Object
23367 *
23368 * @param {Object}
23369 *        The Object to get the keys from
23370 *
23371 * @return {string[]}
23372 *         An array of the keys from the object. Returns an empty array if the
23373 *         object passed in was invalid or had no keys.
23374 *
23375 * @private
23376 */
23377var keys = function keys(object) {
23378  return isObject(object) ? Object.keys(object) : [];
23379};
23380
23381/**
23382 * Array-like iteration for objects.
23383 *
23384 * @param {Object} object
23385 *        The object to iterate over
23386 *
23387 * @param {obj:EachCallback} fn
23388 *        The callback function which is called for each key in the object.
23389 */
23390function each(object, fn) {
23391  keys(object).forEach(function (key) {
23392    return fn(object[key], key);
23393  });
23394}
23395
23396/**
23397 * Array-like reduce for objects.
23398 *
23399 * @param {Object} object
23400 *        The Object that you want to reduce.
23401 *
23402 * @param {Function} fn
23403 *         A callback function which is called for each key in the object. It
23404 *         receives the accumulated value and the per-iteration value and key
23405 *         as arguments.
23406 *
23407 * @param {Mixed} [initial = 0]
23408 *        Starting value
23409 *
23410 * @return {Mixed}
23411 *         The final accumulated value.
23412 */
23413function reduce(object, fn) {
23414  var initial = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
23415
23416  return keys(object).reduce(function (accum, key) {
23417    return fn(accum, object[key], key);
23418  }, initial);
23419}
23420
23421/**
23422 * Object.assign-style object shallow merge/extend.
23423 *
23424 * @param  {Object} target
23425 * @param  {Object} ...sources
23426 * @return {Object}
23427 */
23428function assign(target) {
23429  for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
23430    sources[_key - 1] = arguments[_key];
23431  }
23432
23433  if (Object.assign) {
23434    return Object.assign.apply(Object, [target].concat(sources));
23435  }
23436
23437  sources.forEach(function (source) {
23438    if (!source) {
23439      return;
23440    }
23441
23442    each(source, function (value, key) {
23443      target[key] = value;
23444    });
23445  });
23446
23447  return target;
23448}
23449
23450/**
23451 * Returns whether a value is an object of any kind - including DOM nodes,
23452 * arrays, regular expressions, etc. Not functions, though.
23453 *
23454 * This avoids the gotcha where using `typeof` on a `null` value
23455 * results in `'object'`.
23456 *
23457 * @param  {Object} value
23458 * @return {Boolean}
23459 */
23460function isObject(value) {
23461  return !!value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object';
23462}
23463
23464/**
23465 * Returns whether an object appears to be a "plain" object - that is, a
23466 * direct instance of `Object`.
23467 *
23468 * @param  {Object} value
23469 * @return {Boolean}
23470 */
23471function isPlain(value) {
23472  return isObject(value) && toString.call(value) === '[object Object]' && value.constructor === Object;
23473}
23474
23475},{}],89:[function(_dereq_,module,exports){
23476'use strict';
23477
23478exports.__esModule = true;
23479exports.setTextContent = exports.createStyleElement = undefined;
23480
23481var _document = _dereq_(94);
23482
23483var _document2 = _interopRequireDefault(_document);
23484
23485function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
23486
23487/**
23488 * Create a DOM syle element given a className for it.
23489 *
23490 * @param {string} className
23491 *        The className to add to the created style element.
23492 *
23493 * @return {Element}
23494 *         The element that was created.
23495 */
23496var createStyleElement = exports.createStyleElement = function createStyleElement(className) {
23497  var style = _document2['default'].createElement('style');
23498
23499  style.className = className;
23500
23501  return style;
23502};
23503
23504/**
23505 * Add text to a DOM element.
23506 *
23507 * @param {Element} el
23508 *        The Element to add text content to.
23509 *
23510 * @param {string} content
23511 *        The text to add to the element.
23512 */
23513/**
23514 * @file stylesheet.js
23515 * @module stylesheet
23516 */
23517var setTextContent = exports.setTextContent = function setTextContent(el, content) {
23518  if (el.styleSheet) {
23519    el.styleSheet.cssText = content;
23520  } else {
23521    el.textContent = content;
23522  }
23523};
23524
23525},{"94":94}],90:[function(_dereq_,module,exports){
23526'use strict';
23527
23528exports.__esModule = true;
23529exports.createTimeRange = undefined;
23530exports.createTimeRanges = createTimeRanges;
23531
23532var _log = _dereq_(86);
23533
23534var _log2 = _interopRequireDefault(_log);
23535
23536function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
23537
23538/**
23539 * Returns the time for the specified index at the start or end
23540 * of a TimeRange object.
23541 *
23542 * @function time-ranges:indexFunction
23543 *
23544 * @param {number} [index=0]
23545 *        The range number to return the time for.
23546 *
23547 * @return {number}
23548 *         The time that offset at the specified index.
23549 *
23550 * @depricated index must be set to a value, in the future this will throw an error.
23551 */
23552
23553/**
23554 * An object that contains ranges of time for various reasons.
23555 *
23556 * @typedef {Object} TimeRange
23557 *
23558 * @property {number} length
23559 *           The number of time ranges represented by this Object
23560 *
23561 * @property {time-ranges:indexFunction} start
23562 *           Returns the time offset at which a specified time range begins.
23563 *
23564 * @property {time-ranges:indexFunction} end
23565 *           Returns the time offset at which a specified time range begins.
23566 *
23567 * @see https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges
23568 */
23569
23570/**
23571 * Check if any of the time ranges are over the maximum index.
23572 *
23573 * @param {string} fnName
23574 *        The function name to use for logging
23575 *
23576 * @param {number} index
23577 *        The index to check
23578 *
23579 * @param {number} maxIndex
23580 *        The maximum possible index
23581 *
23582 * @throws {Error} if the timeRanges provided are over the maxIndex
23583 */
23584function rangeCheck(fnName, index, maxIndex) {
23585  if (index < 0 || index > maxIndex) {
23586    throw new Error('Failed to execute \'' + fnName + '\' on \'TimeRanges\': The index provided (' + index + ') is greater than or equal to the maximum bound (' + maxIndex + ').');
23587  }
23588}
23589
23590/**
23591 * Check if any of the time ranges are over the maximum index.
23592 *
23593 * @param {string} fnName
23594 *        The function name to use for logging
23595 *
23596 * @param {string} valueIndex
23597 *        The proprety that should be used to get the time. should be 'start' or 'end'
23598 *
23599 * @param {Array} ranges
23600 *        An array of time ranges
23601 *
23602 * @param {Array} [rangeIndex=0]
23603 *        The index to start the search at
23604 *
23605 * @return {number}
23606 *         The time that offset at the specified index.
23607 *
23608 *
23609 * @depricated rangeIndex must be set to a value, in the future this will throw an error.
23610 * @throws {Error} if rangeIndex is more than the length of ranges
23611 */
23612/**
23613 * @file time-ranges.js
23614 * @module time-ranges
23615 */
23616function getRange(fnName, valueIndex, ranges, rangeIndex) {
23617  if (rangeIndex === undefined) {
23618    _log2['default'].warn('DEPRECATED: Function \'' + fnName + '\' on \'TimeRanges\' called without an index argument.');
23619    rangeIndex = 0;
23620  }
23621  rangeCheck(fnName, rangeIndex, ranges.length - 1);
23622  return ranges[rangeIndex][valueIndex];
23623}
23624
23625/**
23626 * Create a time range object givent ranges of time.
23627 *
23628 * @param {Array} [ranges]
23629 *        An array of time ranges.
23630 */
23631function createTimeRangesObj(ranges) {
23632  if (ranges === undefined || ranges.length === 0) {
23633    return {
23634      length: 0,
23635      start: function start() {
23636        throw new Error('This TimeRanges object is empty');
23637      },
23638      end: function end() {
23639        throw new Error('This TimeRanges object is empty');
23640      }
23641    };
23642  }
23643  return {
23644    length: ranges.length,
23645    start: getRange.bind(null, 'start', 0, ranges),
23646    end: getRange.bind(null, 'end', 1, ranges)
23647  };
23648}
23649
23650/**
23651 * Should create a fake `TimeRange` object which mimics an HTML5 time range instance.
23652 *
23653 * @param {number|Array} start
23654 *        The start of a single range or an array of ranges
23655 *
23656 * @param {number} end
23657 *        The end of a single range.
23658 *
23659 * @private
23660 */
23661function createTimeRanges(start, end) {
23662  if (Array.isArray(start)) {
23663    return createTimeRangesObj(start);
23664  } else if (start === undefined || end === undefined) {
23665    return createTimeRangesObj();
23666  }
23667  return createTimeRangesObj([[start, end]]);
23668}
23669
23670exports.createTimeRange = createTimeRanges;
23671
23672},{"86":86}],91:[function(_dereq_,module,exports){
23673'use strict';
23674
23675exports.__esModule = true;
23676/**
23677 * @file to-title-case.js
23678 * @module to-title-case
23679 */
23680
23681/**
23682 * Uppercase the first letter of a string.
23683 *
23684 * @param {string} string
23685 *        String to be uppercased
23686 *
23687 * @return {string}
23688 *         The string with an uppercased first letter
23689 */
23690function toTitleCase(string) {
23691  if (typeof string !== 'string') {
23692    return string;
23693  }
23694
23695  return string.charAt(0).toUpperCase() + string.slice(1);
23696}
23697
23698exports['default'] = toTitleCase;
23699
23700},{}],92:[function(_dereq_,module,exports){
23701'use strict';
23702
23703exports.__esModule = true;
23704exports.isCrossOrigin = exports.getFileExtension = exports.getAbsoluteURL = exports.parseUrl = undefined;
23705
23706var _document = _dereq_(94);
23707
23708var _document2 = _interopRequireDefault(_document);
23709
23710var _window = _dereq_(95);
23711
23712var _window2 = _interopRequireDefault(_window);
23713
23714function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
23715
23716/**
23717 * @typedef {Object} url:URLObject
23718 *
23719 * @property {string} protocol
23720 *           The protocol of the url that was parsed.
23721 *
23722 * @property {string} hostname
23723 *           The hostname of the url that was parsed.
23724 *
23725 * @property {string} port
23726 *           The port of the url that was parsed.
23727 *
23728 * @property {string} pathname
23729 *           The pathname of the url that was parsed.
23730 *
23731 * @property {string} search
23732 *           The search query of the url that was parsed.
23733 *
23734 * @property {string} hash
23735 *           The hash of the url that was parsed.
23736 *
23737 * @property {string} host
23738 *           The host of the url that was parsed.
23739 */
23740
23741/**
23742 * Resolve and parse the elements of a URL.
23743 *
23744 * @param  {String} url
23745 *         The url to parse
23746 *
23747 * @return {url:URLObject}
23748 *         An object of url details
23749 */
23750/**
23751 * @file url.js
23752 * @module url
23753 */
23754var parseUrl = exports.parseUrl = function parseUrl(url) {
23755  var props = ['protocol', 'hostname', 'port', 'pathname', 'search', 'hash', 'host'];
23756
23757  // add the url to an anchor and let the browser parse the URL
23758  var a = _document2['default'].createElement('a');
23759
23760  a.href = url;
23761
23762  // IE8 (and 9?) Fix
23763  // ie8 doesn't parse the URL correctly until the anchor is actually
23764  // added to the body, and an innerHTML is needed to trigger the parsing
23765  var addToBody = a.host === '' && a.protocol !== 'file:';
23766  var div = void 0;
23767
23768  if (addToBody) {
23769    div = _document2['default'].createElement('div');
23770    div.innerHTML = '<a href="' + url + '"></a>';
23771    a = div.firstChild;
23772    // prevent the div from affecting layout
23773    div.setAttribute('style', 'display:none; position:absolute;');
23774    _document2['default'].body.appendChild(div);
23775  }
23776
23777  // Copy the specific URL properties to a new object
23778  // This is also needed for IE8 because the anchor loses its
23779  // properties when it's removed from the dom
23780  var details = {};
23781
23782  for (var i = 0; i < props.length; i++) {
23783    details[props[i]] = a[props[i]];
23784  }
23785
23786  // IE9 adds the port to the host property unlike everyone else. If
23787  // a port identifier is added for standard ports, strip it.
23788  if (details.protocol === 'http:') {
23789    details.host = details.host.replace(/:80$/, '');
23790  }
23791
23792  if (details.protocol === 'https:') {
23793    details.host = details.host.replace(/:443$/, '');
23794  }
23795
23796  if (addToBody) {
23797    _document2['default'].body.removeChild(div);
23798  }
23799
23800  return details;
23801};
23802
23803/**
23804 * Get absolute version of relative URL. Used to tell flash correct URL.
23805 *
23806 *
23807 * @param  {string} url
23808 *         URL to make absolute
23809 *
23810 * @return {string}
23811 *         Absolute URL
23812 *
23813 * @see http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
23814 */
23815var getAbsoluteURL = exports.getAbsoluteURL = function getAbsoluteURL(url) {
23816  // Check if absolute URL
23817  if (!url.match(/^https?:\/\//)) {
23818    // Convert to absolute URL. Flash hosted off-site needs an absolute URL.
23819    var div = _document2['default'].createElement('div');
23820
23821    div.innerHTML = '<a href="' + url + '">x</a>';
23822    url = div.firstChild.href;
23823  }
23824
23825  return url;
23826};
23827
23828/**
23829 * Returns the extension of the passed file name. It will return an empty string
23830 * if passed an invalid path.
23831 *
23832 * @param {string} path
23833 *        The fileName path like '/path/to/file.mp4'
23834 *
23835 * @returns {string}
23836 *          The extension in lower case or an empty string if no
23837 *          extension could be found.
23838 */
23839var getFileExtension = exports.getFileExtension = function getFileExtension(path) {
23840  if (typeof path === 'string') {
23841    var splitPathRe = /^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/i;
23842    var pathParts = splitPathRe.exec(path);
23843
23844    if (pathParts) {
23845      return pathParts.pop().toLowerCase();
23846    }
23847  }
23848
23849  return '';
23850};
23851
23852/**
23853 * Returns whether the url passed is a cross domain request or not.
23854 *
23855 * @param {string} url
23856 *        The url to check.
23857 *
23858 * @return {boolean}
23859 *         Whether it is a cross domain request or not.
23860 */
23861var isCrossOrigin = exports.isCrossOrigin = function isCrossOrigin(url) {
23862  var winLoc = _window2['default'].location;
23863  var urlInfo = parseUrl(url);
23864
23865  // IE8 protocol relative urls will return ':' for protocol
23866  var srcProtocol = urlInfo.protocol === ':' ? winLoc.protocol : urlInfo.protocol;
23867
23868  // Check if url is for another domain/origin
23869  // IE8 doesn't know location.origin, so we won't rely on it here
23870  var crossOrigin = srcProtocol + urlInfo.host !== winLoc.protocol + winLoc.host;
23871
23872  return crossOrigin;
23873};
23874
23875},{"94":94,"95":95}],93:[function(_dereq_,module,exports){
23876'use strict';
23877
23878exports.__esModule = true;
23879
23880var _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; }; /**
23881                                                                                                                                                                                                                                                                               * @file video.js
23882                                                                                                                                                                                                                                                                               * @module videojs
23883                                                                                                                                                                                                                                                                               */
23884
23885/* global define */
23886
23887// Include the built-in techs
23888
23889
23890var _window = _dereq_(95);
23891
23892var _window2 = _interopRequireDefault(_window);
23893
23894var _document = _dereq_(94);
23895
23896var _document2 = _interopRequireDefault(_document);
23897
23898var _browser = _dereq_(78);
23899
23900var browser = _interopRequireWildcard(_browser);
23901
23902var _dom = _dereq_(81);
23903
23904var Dom = _interopRequireWildcard(_dom);
23905
23906var _setup = _dereq_(56);
23907
23908var setup = _interopRequireWildcard(_setup);
23909
23910var _stylesheet = _dereq_(89);
23911
23912var stylesheet = _interopRequireWildcard(_stylesheet);
23913
23914var _component = _dereq_(5);
23915
23916var _component2 = _interopRequireDefault(_component);
23917
23918var _eventTarget = _dereq_(42);
23919
23920var _eventTarget2 = _interopRequireDefault(_eventTarget);
23921
23922var _events = _dereq_(82);
23923
23924var Events = _interopRequireWildcard(_events);
23925
23926var _player = _dereq_(51);
23927
23928var _player2 = _interopRequireDefault(_player);
23929
23930var _plugins = _dereq_(52);
23931
23932var _plugins2 = _interopRequireDefault(_plugins);
23933
23934var _mergeOptions2 = _dereq_(87);
23935
23936var _mergeOptions3 = _interopRequireDefault(_mergeOptions2);
23937
23938var _fn = _dereq_(83);
23939
23940var Fn = _interopRequireWildcard(_fn);
23941
23942var _textTrack = _dereq_(72);
23943
23944var _textTrack2 = _interopRequireDefault(_textTrack);
23945
23946var _audioTrack = _dereq_(64);
23947
23948var _audioTrack2 = _interopRequireDefault(_audioTrack);
23949
23950var _videoTrack = _dereq_(77);
23951
23952var _videoTrack2 = _interopRequireDefault(_videoTrack);
23953
23954var _timeRanges = _dereq_(90);
23955
23956var _formatTime = _dereq_(84);
23957
23958var _formatTime2 = _interopRequireDefault(_formatTime);
23959
23960var _log = _dereq_(86);
23961
23962var _log2 = _interopRequireDefault(_log);
23963
23964var _url = _dereq_(92);
23965
23966var Url = _interopRequireWildcard(_url);
23967
23968var _obj = _dereq_(88);
23969
23970var _computedStyle = _dereq_(80);
23971
23972var _computedStyle2 = _interopRequireDefault(_computedStyle);
23973
23974var _extend = _dereq_(43);
23975
23976var _extend2 = _interopRequireDefault(_extend);
23977
23978var _xhr = _dereq_(104);
23979
23980var _xhr2 = _interopRequireDefault(_xhr);
23981
23982var _tech = _dereq_(62);
23983
23984var _tech2 = _interopRequireDefault(_tech);
23985
23986function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
23987
23988function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
23989
23990// HTML5 Element Shim for IE8
23991if (typeof HTMLVideoElement === 'undefined' && Dom.isReal()) {
23992  _document2['default'].createElement('video');
23993  _document2['default'].createElement('audio');
23994  _document2['default'].createElement('track');
23995}
23996
23997/**
23998 * Doubles as the main function for users to create a player instance and also
23999 * the main library object.
24000 * The `videojs` function can be used to initialize or retrieve a player.
24001  *
24002 * @param {string|Element} id
24003 *        Video element or video element ID
24004 *
24005 * @param {Object} [options]
24006 *        Optional options object for config/settings
24007 *
24008 * @param {Component~ReadyCallback} [ready]
24009 *        Optional ready callback
24010 *
24011 * @return {Player}
24012 *         A player instance
24013 *
24014 * @mixes videojs
24015 */
24016function videojs(id, options, ready) {
24017  var tag = void 0;
24018
24019  // Allow for element or ID to be passed in
24020  // String ID
24021  if (typeof id === 'string') {
24022
24023    // Adjust for jQuery ID syntax
24024    if (id.indexOf('#') === 0) {
24025      id = id.slice(1);
24026    }
24027
24028    // If a player instance has already been created for this ID return it.
24029    if (videojs.getPlayers()[id]) {
24030
24031      // If options or ready funtion are passed, warn
24032      if (options) {
24033        _log2['default'].warn('Player "' + id + '" is already initialised. Options will not be applied.');
24034      }
24035
24036      if (ready) {
24037        videojs.getPlayers()[id].ready(ready);
24038      }
24039
24040      return videojs.getPlayers()[id];
24041    }
24042
24043    // Otherwise get element for ID
24044    tag = Dom.getEl(id);
24045
24046    // ID is a media element
24047  } else {
24048    tag = id;
24049  }
24050
24051  // Check for a useable element
24052  // re: nodeName, could be a box div also
24053  if (!tag || !tag.nodeName) {
24054    throw new TypeError('The element or ID supplied is not valid. (videojs)');
24055  }
24056
24057  // Element may have a player attr referring to an already created player instance.
24058  // If so return that otherwise set up a new player below
24059  if (tag.player || _player2['default'].players[tag.playerId]) {
24060    return tag.player || _player2['default'].players[tag.playerId];
24061  }
24062
24063  options = options || {};
24064
24065  videojs.hooks('beforesetup').forEach(function (hookFunction) {
24066    var opts = hookFunction(tag, (0, _mergeOptions3['default'])(options));
24067
24068    if (!(0, _obj.isObject)(opts) || Array.isArray(opts)) {
24069      _log2['default'].error('please return an object in beforesetup hooks');
24070      return;
24071    }
24072
24073    options = (0, _mergeOptions3['default'])(options, opts);
24074  });
24075
24076  var PlayerComponent = _component2['default'].getComponent('Player');
24077  // If not, set up a new player
24078  var player = new PlayerComponent(tag, options, ready);
24079
24080  videojs.hooks('setup').forEach(function (hookFunction) {
24081    return hookFunction(player);
24082  });
24083
24084  return player;
24085}
24086
24087/**
24088 * An Object that contains lifecycle hooks as keys which point to an array
24089 * of functions that are run when a lifecycle is triggered
24090 */
24091videojs.hooks_ = {};
24092
24093/**
24094 * Get a list of hooks for a specific lifecycle
24095 *
24096 * @param {string} type
24097 *        the lifecyle to get hooks from
24098 *
24099 * @param {Function} [fn]
24100 *        Optionally add a hook to the lifecycle that your are getting.
24101 *
24102 * @return {Array}
24103 *         an array of hooks, or an empty array if there are none.
24104 */
24105videojs.hooks = function (type, fn) {
24106  videojs.hooks_[type] = videojs.hooks_[type] || [];
24107  if (fn) {
24108    videojs.hooks_[type] = videojs.hooks_[type].concat(fn);
24109  }
24110  return videojs.hooks_[type];
24111};
24112
24113/**
24114 * Add a function hook to a specific videojs lifecycle.
24115 *
24116 * @param {string} type
24117 *        the lifecycle to hook the function to.
24118 *
24119 * @param {Function|Function[]}
24120 *        The function or array of functions to attach.
24121 */
24122videojs.hook = function (type, fn) {
24123  videojs.hooks(type, fn);
24124};
24125
24126/**
24127 * Remove a hook from a specific videojs lifecycle.
24128 *
24129 * @param {string} type
24130 *        the lifecycle that the function hooked to
24131 *
24132 * @param {Function} fn
24133 *        The hooked function to remove
24134 *
24135 * @return {boolean}
24136 *         The function that was removed or undef
24137 */
24138videojs.removeHook = function (type, fn) {
24139  var index = videojs.hooks(type).indexOf(fn);
24140
24141  if (index <= -1) {
24142    return false;
24143  }
24144
24145  videojs.hooks_[type] = videojs.hooks_[type].slice();
24146  videojs.hooks_[type].splice(index, 1);
24147
24148  return true;
24149};
24150
24151// Add default styles
24152if (_window2['default'].VIDEOJS_NO_DYNAMIC_STYLE !== true && Dom.isReal()) {
24153  var style = Dom.$('.vjs-styles-defaults');
24154
24155  if (!style) {
24156    style = stylesheet.createStyleElement('vjs-styles-defaults');
24157    var head = Dom.$('head');
24158
24159    if (head) {
24160      head.insertBefore(style, head.firstChild);
24161    }
24162    stylesheet.setTextContent(style, '\n      .video-js {\n        width: 300px;\n        height: 150px;\n      }\n\n      .vjs-fluid {\n        padding-top: 56.25%\n      }\n    ');
24163  }
24164}
24165
24166// Run Auto-load players
24167// You have to wait at least once in case this script is loaded after your
24168// video in the DOM (weird behavior only with minified version)
24169setup.autoSetupTimeout(1, videojs);
24170
24171/**
24172 * Current software version. Follows semver.
24173 *
24174 * @type {string}
24175 */
24176videojs.VERSION = '5.20.2';
24177
24178/**
24179 * The global options object. These are the settings that take effect
24180 * if no overrides are specified when the player is created.
24181 *
24182 * @type {Object}
24183 */
24184videojs.options = _player2['default'].prototype.options_;
24185
24186/**
24187 * Get an object with the currently created players, keyed by player ID
24188 *
24189 * @return {Object}
24190 *         The created players
24191 */
24192videojs.getPlayers = function () {
24193  return _player2['default'].players;
24194};
24195
24196/**
24197 * Expose players object.
24198 *
24199 * @memberOf videojs
24200 * @property {Object} players
24201 */
24202videojs.players = _player2['default'].players;
24203
24204/**
24205 * Get a component class object by name
24206 *
24207 * @borrows Component.getComponent as videojs.getComponent
24208 */
24209videojs.getComponent = _component2['default'].getComponent;
24210
24211/**
24212 * Register a component so it can referred to by name. Used when adding to other
24213 * components, either through addChild `component.addChild('myComponent')` or through
24214 * default children options  `{ children: ['myComponent'] }`.
24215 *
24216 * > NOTE: You could also just initialize the component before adding.
24217 * `component.addChild(new MyComponent());`
24218 *
24219 * @param {string} name
24220 *        The class name of the component
24221 *
24222 * @param {Component} comp
24223 *        The component class
24224 *
24225 * @return {Component}
24226 *         The newly registered component
24227 */
24228videojs.registerComponent = function (name, comp) {
24229  if (_tech2['default'].isTech(comp)) {
24230    _log2['default'].warn('The ' + name + ' tech was registered as a component. It should instead be registered using videojs.registerTech(name, tech)');
24231  }
24232
24233  _component2['default'].registerComponent.call(_component2['default'], name, comp);
24234};
24235
24236/**
24237 * Get a Tech class object by name
24238 *
24239 * @borrows Tech.getTech as videojs.getTech
24240 */
24241videojs.getTech = _tech2['default'].getTech;
24242
24243/**
24244 * Register a Tech so it can referred to by name.
24245 * This is used in the tech order for the player.
24246 *
24247 * @borrows Tech.registerTech as videojs.registerTech
24248 */
24249videojs.registerTech = _tech2['default'].registerTech;
24250
24251/**
24252 * A suite of browser and device tests from {@link browser}.
24253 *
24254 * @type {Object}
24255 * @private
24256 */
24257videojs.browser = browser;
24258
24259/**
24260 * Whether or not the browser supports touch events. Included for backward
24261 * compatibility with 4.x, but deprecated. Use `videojs.browser.TOUCH_ENABLED`
24262 * instead going forward.
24263 *
24264 * @deprecated since version 5.0
24265 * @type {boolean}
24266 */
24267videojs.TOUCH_ENABLED = browser.TOUCH_ENABLED;
24268
24269/**
24270 * Subclass an existing class
24271 * Mimics ES6 subclassing with the `extend` keyword
24272 *
24273 * @borrows extend:extendFn as videojs.extend
24274 */
24275videojs.extend = _extend2['default'];
24276
24277/**
24278 * Merge two options objects recursively
24279 * Performs a deep merge like lodash.merge but **only merges plain objects**
24280 * (not arrays, elements, anything else)
24281 * Other values will be copied directly from the second object.
24282 *
24283 * @borrows merge-options:mergeOptions as videojs.mergeOptions
24284 */
24285videojs.mergeOptions = _mergeOptions3['default'];
24286
24287/**
24288 * Change the context (this) of a function
24289 *
24290 * > NOTE: as of v5.0 we require an ES5 shim, so you should use the native
24291 * `function() {}.bind(newContext);` instead of this.
24292 *
24293 * @borrows fn:bind as videojs.bind
24294 */
24295videojs.bind = Fn.bind;
24296
24297/**
24298 * Create a Video.js player plugin.
24299 * Plugins are only initialized when options for the plugin are included
24300 * in the player options, or the plugin function on the player instance is
24301 * called.
24302 *
24303 * @borrows plugin:plugin as videojs.plugin
24304 */
24305videojs.plugin = _plugins2['default'];
24306
24307/**
24308 * Adding languages so that they're available to all players.
24309 * Example: `videojs.addLanguage('es', { 'Hello': 'Hola' });`
24310 *
24311 * @param {string} code
24312 *        The language code or dictionary property
24313 *
24314 * @param {Object} data
24315 *        The data values to be translated
24316 *
24317 * @return {Object}
24318 *         The resulting language dictionary object
24319 */
24320videojs.addLanguage = function (code, data) {
24321  var _mergeOptions;
24322
24323  code = ('' + code).toLowerCase();
24324
24325  videojs.options.languages = (0, _mergeOptions3['default'])(videojs.options.languages, (_mergeOptions = {}, _mergeOptions[code] = data, _mergeOptions));
24326
24327  return videojs.options.languages[code];
24328};
24329
24330/**
24331 * Log messages
24332 *
24333 * @borrows log:log as videojs.log
24334 */
24335videojs.log = _log2['default'];
24336
24337/**
24338 * Creates an emulated TimeRange object.
24339 *
24340 * @borrows time-ranges:createTimeRanges as videojs.createTimeRange
24341 */
24342/**
24343 * @borrows time-ranges:createTimeRanges as videojs.createTimeRanges
24344 */
24345videojs.createTimeRange = videojs.createTimeRanges = _timeRanges.createTimeRanges;
24346
24347/**
24348 * Format seconds as a time string, H:MM:SS or M:SS
24349 * Supplying a guide (in seconds) will force a number of leading zeros
24350 * to cover the length of the guide
24351 *
24352 * @borrows format-time:formatTime as videojs.formatTime
24353 */
24354videojs.formatTime = _formatTime2['default'];
24355
24356/**
24357 * Resolve and parse the elements of a URL
24358 *
24359 * @borrows url:parseUrl as videojs.parseUrl
24360 */
24361videojs.parseUrl = Url.parseUrl;
24362
24363/**
24364 * Returns whether the url passed is a cross domain request or not.
24365 *
24366 * @borrows url:isCrossOrigin as videojs.isCrossOrigin
24367 */
24368videojs.isCrossOrigin = Url.isCrossOrigin;
24369
24370/**
24371 * Event target class.
24372 *
24373 * @borrows EventTarget as videojs.EventTarget
24374 */
24375videojs.EventTarget = _eventTarget2['default'];
24376
24377/**
24378 * Add an event listener to element
24379 * It stores the handler function in a separate cache object
24380 * and adds a generic handler to the element's event,
24381 * along with a unique id (guid) to the element.
24382 *
24383 * @borrows events:on as videojs.on
24384 */
24385videojs.on = Events.on;
24386
24387/**
24388 * Trigger a listener only once for an event
24389 *
24390 * @borrows events:one as videojs.one
24391 */
24392videojs.one = Events.one;
24393
24394/**
24395 * Removes event listeners from an element
24396 *
24397 * @borrows events:off as videojs.off
24398 */
24399videojs.off = Events.off;
24400
24401/**
24402 * Trigger an event for an element
24403 *
24404 * @borrows events:trigger as videojs.trigger
24405 */
24406videojs.trigger = Events.trigger;
24407
24408/**
24409 * A cross-browser XMLHttpRequest wrapper. Here's a simple example:
24410 *
24411 * @param {Object} options
24412 *        settings for the request.
24413 *
24414 * @return {XMLHttpRequest|XDomainRequest}
24415 *         The request object.
24416 *
24417 * @see https://github.com/Raynos/xhr
24418 */
24419videojs.xhr = _xhr2['default'];
24420
24421/**
24422 * TextTrack class
24423 *
24424 * @borrows TextTrack as videojs.TextTrack
24425 */
24426videojs.TextTrack = _textTrack2['default'];
24427
24428/**
24429 * export the AudioTrack class so that source handlers can create
24430 * AudioTracks and then add them to the players AudioTrackList
24431 *
24432 * @borrows AudioTrack as videojs.AudioTrack
24433 */
24434videojs.AudioTrack = _audioTrack2['default'];
24435
24436/**
24437 * export the VideoTrack class so that source handlers can create
24438 * VideoTracks and then add them to the players VideoTrackList
24439 *
24440 * @borrows VideoTrack as videojs.VideoTrack
24441 */
24442videojs.VideoTrack = _videoTrack2['default'];
24443
24444/**
24445 * Determines, via duck typing, whether or not a value is a DOM element.
24446 *
24447 * @borrows dom:isEl as videojs.isEl
24448 */
24449videojs.isEl = Dom.isEl;
24450
24451/**
24452 * Determines, via duck typing, whether or not a value is a text node.
24453 *
24454 * @borrows dom:isTextNode as videojs.isTextNode
24455 */
24456videojs.isTextNode = Dom.isTextNode;
24457
24458/**
24459 * Creates an element and applies properties.
24460 *
24461 * @borrows dom:createEl as videojs.createEl
24462 */
24463videojs.createEl = Dom.createEl;
24464
24465/**
24466 * Check if an element has a CSS class
24467 *
24468 * @borrows dom:hasElClass as videojs.hasClass
24469 */
24470videojs.hasClass = Dom.hasElClass;
24471
24472/**
24473 * Add a CSS class name to an element
24474 *
24475 * @borrows dom:addElClass as videojs.addClass
24476 */
24477videojs.addClass = Dom.addElClass;
24478
24479/**
24480 * Remove a CSS class name from an element
24481 *
24482 * @borrows dom:removeElClass as videojs.removeClass
24483 */
24484videojs.removeClass = Dom.removeElClass;
24485
24486/**
24487 * Adds or removes a CSS class name on an element depending on an optional
24488 * condition or the presence/absence of the class name.
24489 *
24490 * @borrows dom:toggleElClass as videojs.toggleClass
24491 */
24492videojs.toggleClass = Dom.toggleElClass;
24493
24494/**
24495 * Apply attributes to an HTML element.
24496 *
24497 * @borrows dom:setElAttributes as videojs.setAttribute
24498 */
24499videojs.setAttributes = Dom.setElAttributes;
24500
24501/**
24502 * Get an element's attribute values, as defined on the HTML tag
24503 * Attributes are not the same as properties. They're defined on the tag
24504 * or with setAttribute (which shouldn't be used with HTML)
24505 * This will return true or false for boolean attributes.
24506 *
24507 * @borrows dom:getElAttributes as videojs.getAttributes
24508 */
24509videojs.getAttributes = Dom.getElAttributes;
24510
24511/**
24512 * Empties the contents of an element.
24513 *
24514 * @borrows dom:emptyEl as videojs.emptyEl
24515 */
24516videojs.emptyEl = Dom.emptyEl;
24517
24518/**
24519 * Normalizes and appends content to an element.
24520 *
24521 * The content for an element can be passed in multiple types and
24522 * combinations, whose behavior is as follows:
24523 *
24524 * - String
24525 *   Normalized into a text node.
24526 *
24527 * - Element, TextNode
24528 *   Passed through.
24529 *
24530 * - Array
24531 *   A one-dimensional array of strings, elements, nodes, or functions (which
24532 *   return single strings, elements, or nodes).
24533 *
24534 * - Function
24535 *   If the sole argument, is expected to produce a string, element,
24536 *   node, or array.
24537 *
24538 * @borrows dom:appendContents as videojs.appendContet
24539 */
24540videojs.appendContent = Dom.appendContent;
24541
24542/**
24543 * Normalizes and inserts content into an element; this is identical to
24544 * `appendContent()`, except it empties the element first.
24545 *
24546 * The content for an element can be passed in multiple types and
24547 * combinations, whose behavior is as follows:
24548 *
24549 * - String
24550 *   Normalized into a text node.
24551 *
24552 * - Element, TextNode
24553 *   Passed through.
24554 *
24555 * - Array
24556 *   A one-dimensional array of strings, elements, nodes, or functions (which
24557 *   return single strings, elements, or nodes).
24558 *
24559 * - Function
24560 *   If the sole argument, is expected to produce a string, element,
24561 *   node, or array.
24562 *
24563 * @borrows dom:insertContent as videojs.insertContent
24564 */
24565videojs.insertContent = Dom.insertContent;
24566
24567/**
24568 * A safe getComputedStyle with an IE8 fallback.
24569 *
24570 * This is because in Firefox, if the player is loaded in an iframe with `display:none`,
24571 * then `getComputedStyle` returns `null`, so, we do a null-check to make sure
24572 * that the player doesn't break in these cases.
24573 * See https://bugzilla.mozilla.org/show_bug.cgi?id=548397 for more details.
24574 *
24575 * @borrows computed-style:computedStyle as videojs.computedStyle
24576 */
24577videojs.computedStyle = _computedStyle2['default'];
24578
24579/*
24580 * Custom Universal Module Definition (UMD)
24581 *
24582 * Video.js will never be a non-browser lib so we can simplify UMD a bunch and
24583 * still support requirejs and browserify. This also needs to be closure
24584 * compiler compatible, so string keys are used.
24585 */
24586if (typeof define === 'function' && define.amd) {
24587  define('videojs', [], function () {
24588    return videojs;
24589  });
24590
24591  // checking that module is an object too because of umdjs/umd#35
24592} else if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object' && (typeof module === 'undefined' ? 'undefined' : _typeof(module)) === 'object') {
24593  module.exports = videojs;
24594}
24595
24596exports['default'] = videojs;
24597
24598},{"104":104,"42":42,"43":43,"5":5,"51":51,"52":52,"56":56,"62":62,"64":64,"72":72,"77":77,"78":78,"80":80,"81":81,"82":82,"83":83,"84":84,"86":86,"87":87,"88":88,"89":89,"90":90,"92":92,"94":94,"95":95}],94:[function(_dereq_,module,exports){
24599(function (global){
24600var topLevel = typeof global !== 'undefined' ? global :
24601    typeof window !== 'undefined' ? window : {}
24602var minDoc = _dereq_(96);
24603
24604if (typeof document !== 'undefined') {
24605    module.exports = document;
24606} else {
24607    var doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
24608
24609    if (!doccy) {
24610        doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
24611    }
24612
24613    module.exports = doccy;
24614}
24615
24616}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
24617},{"96":96}],95:[function(_dereq_,module,exports){
24618(function (global){
24619if (typeof window !== "undefined") {
24620    module.exports = window;
24621} else if (typeof global !== "undefined") {
24622    module.exports = global;
24623} else if (typeof self !== "undefined"){
24624    module.exports = self;
24625} else {
24626    module.exports = {};
24627}
24628
24629}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
24630},{}],96:[function(_dereq_,module,exports){
24631
24632},{}],97:[function(_dereq_,module,exports){
24633module.exports = SafeParseTuple
24634
24635function SafeParseTuple(obj, reviver) {
24636    var json
24637    var error = null
24638
24639    try {
24640        json = JSON.parse(obj, reviver)
24641    } catch (err) {
24642        error = err
24643    }
24644
24645    return [error, json]
24646}
24647
24648},{}],98:[function(_dereq_,module,exports){
24649function clean (s) {
24650  return s.replace(/\n\r?\s*/g, '')
24651}
24652
24653
24654module.exports = function tsml (sa) {
24655  var s = ''
24656    , i = 0
24657
24658  for (; i < arguments.length; i++)
24659    s += clean(sa[i]) + (arguments[i + 1] || '')
24660
24661  return s
24662}
24663},{}],99:[function(_dereq_,module,exports){
24664/**
24665 * Copyright 2013 vtt.js Contributors
24666 *
24667 * Licensed under the Apache License, Version 2.0 (the "License");
24668 * you may not use this file except in compliance with the License.
24669 * You may obtain a copy of the License at
24670 *
24671 *   http://www.apache.org/licenses/LICENSE-2.0
24672 *
24673 * Unless required by applicable law or agreed to in writing, software
24674 * distributed under the License is distributed on an "AS IS" BASIS,
24675 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24676 * See the License for the specific language governing permissions and
24677 * limitations under the License.
24678 */
24679
24680// Default exports for Node. Export the extended versions of VTTCue and
24681// VTTRegion in Node since we likely want the capability to convert back and
24682// forth between JSON. If we don't then it's not that big of a deal since we're
24683// off browser.
24684
24685var window = _dereq_(103);
24686
24687var vttjs = module.exports = {
24688  WebVTT: _dereq_(100),
24689  VTTCue: _dereq_(101),
24690  VTTRegion: _dereq_(102)
24691};
24692
24693window.vttjs = vttjs;
24694window.WebVTT = vttjs.WebVTT;
24695
24696var cueShim = vttjs.VTTCue;
24697var regionShim = vttjs.VTTRegion;
24698var nativeVTTCue = window.VTTCue;
24699var nativeVTTRegion = window.VTTRegion;
24700
24701vttjs.shim = function() {
24702  window.VTTCue = cueShim;
24703  window.VTTRegion = regionShim;
24704};
24705
24706vttjs.restore = function() {
24707  window.VTTCue = nativeVTTCue;
24708  window.VTTRegion = nativeVTTRegion;
24709};
24710
24711if (!window.VTTCue) {
24712  vttjs.shim();
24713}
24714
24715},{"100":100,"101":101,"102":102,"103":103}],100:[function(_dereq_,module,exports){
24716/**
24717 * Copyright 2013 vtt.js Contributors
24718 *
24719 * Licensed under the Apache License, Version 2.0 (the "License");
vendor: 16,438 bytes, lines 24720-25257
24720 * you may not use this file except in compliance with the License.
24721 * You may obtain a copy of the License at
24722 *
24723 *   http://www.apache.org/licenses/LICENSE-2.0
24724 *
24725 * Unless required by applicable law or agreed to in writing, software
24726 * distributed under the License is distributed on an "AS IS" BASIS,
24727 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24728 * See the License for the specific language governing permissions and
24729 * limitations under the License.
24730 */
24731
24732/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
24733/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
24734var _objCreate = Object.create || (function() {
24735  function F() {}
24736  return function(o) {
24737    if (arguments.length !== 1) {
24738      throw new Error('Object.create shim only accepts one parameter.');
24739    }
24740    F.prototype = o;
24741    return new F();
24742  };
24743})();
24744
24745// Creates a new ParserError object from an errorData object. The errorData
24746// object should have default code and message properties. The default message
24747// property can be overriden by passing in a message parameter.
24748// See ParsingError.Errors below for acceptable errors.
24749function ParsingError(errorData, message) {
24750  this.name = "ParsingError";
24751  this.code = errorData.code;
24752  this.message = message || errorData.message;
24753}
24754ParsingError.prototype = _objCreate(Error.prototype);
24755ParsingError.prototype.constructor = ParsingError;
24756
24757// ParsingError metadata for acceptable ParsingErrors.
24758ParsingError.Errors = {
24759  BadSignature: {
24760    code: 0,
24761    message: "Malformed WebVTT signature."
24762  },
24763  BadTimeStamp: {
24764    code: 1,
24765    message: "Malformed time stamp."
24766  }
24767};
24768
24769// Try to parse input as a time stamp.
24770function parseTimeStamp(input) {
24771
24772  function computeSeconds(h, m, s, f) {
24773    return (h | 0) * 3600 + (m | 0) * 60 + (s | 0) + (f | 0) / 1000;
24774  }
24775
24776  var m = input.match(/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/);
24777  if (!m) {
24778    return null;
24779  }
24780
24781  if (m[3]) {
24782    // Timestamp takes the form of [hours]:[minutes]:[seconds].[milliseconds]
24783    return computeSeconds(m[1], m[2], m[3].replace(":", ""), m[4]);
24784  } else if (m[1] > 59) {
24785    // Timestamp takes the form of [hours]:[minutes].[milliseconds]
24786    // First position is hours as it's over 59.
24787    return computeSeconds(m[1], m[2], 0,  m[4]);
24788  } else {
24789    // Timestamp takes the form of [minutes]:[seconds].[milliseconds]
24790    return computeSeconds(0, m[1], m[2], m[4]);
24791  }
24792}
24793
24794// A settings object holds key/value pairs and will ignore anything but the first
24795// assignment to a specific key.
24796function Settings() {
24797  this.values = _objCreate(null);
24798}
24799
24800Settings.prototype = {
24801  // Only accept the first assignment to any key.
24802  set: function(k, v) {
24803    if (!this.get(k) && v !== "") {
24804      this.values[k] = v;
24805    }
24806  },
24807  // Return the value for a key, or a default value.
24808  // If 'defaultKey' is passed then 'dflt' is assumed to be an object with
24809  // a number of possible default values as properties where 'defaultKey' is
24810  // the key of the property that will be chosen; otherwise it's assumed to be
24811  // a single value.
24812  get: function(k, dflt, defaultKey) {
24813    if (defaultKey) {
24814      return this.has(k) ? this.values[k] : dflt[defaultKey];
24815    }
24816    return this.has(k) ? this.values[k] : dflt;
24817  },
24818  // Check whether we have a value for a key.
24819  has: function(k) {
24820    return k in this.values;
24821  },
24822  // Accept a setting if its one of the given alternatives.
24823  alt: function(k, v, a) {
24824    for (var n = 0; n < a.length; ++n) {
24825      if (v === a[n]) {
24826        this.set(k, v);
24827        break;
24828      }
24829    }
24830  },
24831  // Accept a setting if its a valid (signed) integer.
24832  integer: function(k, v) {
24833    if (/^-?\d+$/.test(v)) { // integer
24834      this.set(k, parseInt(v, 10));
24835    }
24836  },
24837  // Accept a setting if its a valid percentage.
24838  percent: function(k, v) {
24839    var m;
24840    if ((m = v.match(/^([\d]{1,3})(\.[\d]*)?%$/))) {
24841      v = parseFloat(v);
24842      if (v >= 0 && v <= 100) {
24843        this.set(k, v);
24844        return true;
24845      }
24846    }
24847    return false;
24848  }
24849};
24850
24851// Helper function to parse input into groups separated by 'groupDelim', and
24852// interprete each group as a key/value pair separated by 'keyValueDelim'.
24853function parseOptions(input, callback, keyValueDelim, groupDelim) {
24854  var groups = groupDelim ? input.split(groupDelim) : [input];
24855  for (var i in groups) {
24856    if (typeof groups[i] !== "string") {
24857      continue;
24858    }
24859    var kv = groups[i].split(keyValueDelim);
24860    if (kv.length !== 2) {
24861      continue;
24862    }
24863    var k = kv[0];
24864    var v = kv[1];
24865    callback(k, v);
24866  }
24867}
24868
24869function parseCue(input, cue, regionList) {
24870  // Remember the original input if we need to throw an error.
24871  var oInput = input;
24872  // 4.1 WebVTT timestamp
24873  function consumeTimeStamp() {
24874    var ts = parseTimeStamp(input);
24875    if (ts === null) {
24876      throw new ParsingError(ParsingError.Errors.BadTimeStamp,
24877                            "Malformed timestamp: " + oInput);
24878    }
24879    // Remove time stamp from input.
24880    input = input.replace(/^[^\sa-zA-Z-]+/, "");
24881    return ts;
24882  }
24883
24884  // 4.4.2 WebVTT cue settings
24885  function consumeCueSettings(input, cue) {
24886    var settings = new Settings();
24887
24888    parseOptions(input, function (k, v) {
24889      switch (k) {
24890      case "region":
24891        // Find the last region we parsed with the same region id.
24892        for (var i = regionList.length - 1; i >= 0; i--) {
24893          if (regionList[i].id === v) {
24894            settings.set(k, regionList[i].region);
24895            break;
24896          }
24897        }
24898        break;
24899      case "vertical":
24900        settings.alt(k, v, ["rl", "lr"]);
24901        break;
24902      case "line":
24903        var vals = v.split(","),
24904            vals0 = vals[0];
24905        settings.integer(k, vals0);
24906        settings.percent(k, vals0) ? settings.set("snapToLines", false) : null;
24907        settings.alt(k, vals0, ["auto"]);
24908        if (vals.length === 2) {
24909          settings.alt("lineAlign", vals[1], ["start", "middle", "end"]);
24910        }
24911        break;
24912      case "position":
24913        vals = v.split(",");
24914        settings.percent(k, vals[0]);
24915        if (vals.length === 2) {
24916          settings.alt("positionAlign", vals[1], ["start", "middle", "end"]);
24917        }
24918        break;
24919      case "size":
24920        settings.percent(k, v);
24921        break;
24922      case "align":
24923        settings.alt(k, v, ["start", "middle", "end", "left", "right"]);
24924        break;
24925      }
24926    }, /:/, /\s/);
24927
24928    // Apply default values for any missing fields.
24929    cue.region = settings.get("region", null);
24930    cue.vertical = settings.get("vertical", "");
24931    cue.line = settings.get("line", "auto");
24932    cue.lineAlign = settings.get("lineAlign", "start");
24933    cue.snapToLines = settings.get("snapToLines", true);
24934    cue.size = settings.get("size", 100);
24935    cue.align = settings.get("align", "middle");
24936    cue.position = settings.get("position", {
24937      start: 0,
24938      left: 0,
24939      middle: 50,
24940      end: 100,
24941      right: 100
24942    }, cue.align);
24943    cue.positionAlign = settings.get("positionAlign", {
24944      start: "start",
24945      left: "start",
24946      middle: "middle",
24947      end: "end",
24948      right: "end"
24949    }, cue.align);
24950  }
24951
24952  function skipWhitespace() {
24953    input = input.replace(/^\s+/, "");
24954  }
24955
24956  // 4.1 WebVTT cue timings.
24957  skipWhitespace();
24958  cue.startTime = consumeTimeStamp();   // (1) collect cue start time
24959  skipWhitespace();
24960  if (input.substr(0, 3) !== "-->") {     // (3) next characters must match "-->"
24961    throw new ParsingError(ParsingError.Errors.BadTimeStamp,
24962                           "Malformed time stamp (time stamps must be separated by '-->'): " +
24963                           oInput);
24964  }
24965  input = input.substr(3);
24966  skipWhitespace();
24967  cue.endTime = consumeTimeStamp();     // (5) collect cue end time
24968
24969  // 4.1 WebVTT cue settings list.
24970  skipWhitespace();
24971  consumeCueSettings(input, cue);
24972}
24973
24974var ESCAPE = {
24975  "&amp;": "&",
24976  "&lt;": "<",
24977  "&gt;": ">",
24978  "&lrm;": "\u200e",
24979  "&rlm;": "\u200f",
24980  "&nbsp;": "\u00a0"
24981};
24982
24983var TAG_NAME = {
24984  c: "span",
24985  i: "i",
24986  b: "b",
24987  u: "u",
24988  ruby: "ruby",
24989  rt: "rt",
24990  v: "span",
24991  lang: "span"
24992};
24993
24994var TAG_ANNOTATION = {
24995  v: "title",
24996  lang: "lang"
24997};
24998
24999var NEEDS_PARENT = {
25000  rt: "ruby"
25001};
25002
25003// Parse content into a document fragment.
25004function parseContent(window, input) {
25005  function nextToken() {
25006    // Check for end-of-string.
25007    if (!input) {
25008      return null;
25009    }
25010
25011    // Consume 'n' characters from the input.
25012    function consume(result) {
25013      input = input.substr(result.length);
25014      return result;
25015    }
25016
25017    var m = input.match(/^([^<]*)(<[^>]+>?)?/);
25018    // If there is some text before the next tag, return it, otherwise return
25019    // the tag.
25020    return consume(m[1] ? m[1] : m[2]);
25021  }
25022
25023  // Unescape a string 's'.
25024  function unescape1(e) {
25025    return ESCAPE[e];
25026  }
25027  function unescape(s) {
25028    while ((m = s.match(/&(amp|lt|gt|lrm|rlm|nbsp);/))) {
25029      s = s.replace(m[0], unescape1);
25030    }
25031    return s;
25032  }
25033
25034  function shouldAdd(current, element) {
25035    return !NEEDS_PARENT[element.localName] ||
25036           NEEDS_PARENT[element.localName] === current.localName;
25037  }
25038
25039  // Create an element for this tag.
25040  function createElement(type, annotation) {
25041    var tagName = TAG_NAME[type];
25042    if (!tagName) {
25043      return null;
25044    }
25045    var element = window.document.createElement(tagName);
25046    element.localName = tagName;
25047    var name = TAG_ANNOTATION[type];
25048    if (name && annotation) {
25049      element[name] = annotation.trim();
25050    }
25051    return element;
25052  }
25053
25054  var rootDiv = window.document.createElement("div"),
25055      current = rootDiv,
25056      t,
25057      tagStack = [];
25058
25059  while ((t = nextToken()) !== null) {
25060    if (t[0] === '<') {
25061      if (t[1] === "/") {
25062        // If the closing tag matches, move back up to the parent node.
25063        if (tagStack.length &&
25064            tagStack[tagStack.length - 1] === t.substr(2).replace(">", "")) {
25065          tagStack.pop();
25066          current = current.parentNode;
25067        }
25068        // Otherwise just ignore the end tag.
25069        continue;
25070      }
25071      var ts = parseTimeStamp(t.substr(1, t.length - 2));
25072      var node;
25073      if (ts) {
25074        // Timestamps are lead nodes as well.
25075        node = window.document.createProcessingInstruction("timestamp", ts);
25076        current.appendChild(node);
25077        continue;
25078      }
25079      var m = t.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/);
25080      // If we can't parse the tag, skip to the next tag.
25081      if (!m) {
25082        continue;
25083      }
25084      // Try to construct an element, and ignore the tag if we couldn't.
25085      node = createElement(m[1], m[3]);
25086      if (!node) {
25087        continue;
25088      }
25089      // Determine if the tag should be added based on the context of where it
25090      // is placed in the cuetext.
25091      if (!shouldAdd(current, node)) {
25092        continue;
25093      }
25094      // Set the class list (as a list of classes, separated by space).
25095      if (m[2]) {
25096        node.className = m[2].substr(1).replace('.', ' ');
25097      }
25098      // Append the node to the current node, and enter the scope of the new
25099      // node.
25100      tagStack.push(m[1]);
25101      current.appendChild(node);
25102      current = node;
25103      continue;
25104    }
25105
25106    // Text nodes are leaf nodes.
25107    current.appendChild(window.document.createTextNode(unescape(t)));
25108  }
25109
25110  return rootDiv;
25111}
25112
25113// This is a list of all the Unicode characters that have a strong
25114// right-to-left category. What this means is that these characters are
25115// written right-to-left for sure. It was generated by pulling all the strong
25116// right-to-left characters out of the Unicode data table. That table can
25117// found at: http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
25118var strongRTLRanges = [[0x5be, 0x5be], [0x5c0, 0x5c0], [0x5c3, 0x5c3], [0x5c6, 0x5c6],
25119 [0x5d0, 0x5ea], [0x5f0, 0x5f4], [0x608, 0x608], [0x60b, 0x60b], [0x60d, 0x60d],
25120 [0x61b, 0x61b], [0x61e, 0x64a], [0x66d, 0x66f], [0x671, 0x6d5], [0x6e5, 0x6e6],
25121 [0x6ee, 0x6ef], [0x6fa, 0x70d], [0x70f, 0x710], [0x712, 0x72f], [0x74d, 0x7a5],
25122 [0x7b1, 0x7b1], [0x7c0, 0x7ea], [0x7f4, 0x7f5], [0x7fa, 0x7fa], [0x800, 0x815],
25123 [0x81a, 0x81a], [0x824, 0x824], [0x828, 0x828], [0x830, 0x83e], [0x840, 0x858],
25124 [0x85e, 0x85e], [0x8a0, 0x8a0], [0x8a2, 0x8ac], [0x200f, 0x200f],
25125 [0xfb1d, 0xfb1d], [0xfb1f, 0xfb28], [0xfb2a, 0xfb36], [0xfb38, 0xfb3c],
25126 [0xfb3e, 0xfb3e], [0xfb40, 0xfb41], [0xfb43, 0xfb44], [0xfb46, 0xfbc1],
25127 [0xfbd3, 0xfd3d], [0xfd50, 0xfd8f], [0xfd92, 0xfdc7], [0xfdf0, 0xfdfc],
25128 [0xfe70, 0xfe74], [0xfe76, 0xfefc], [0x10800, 0x10805], [0x10808, 0x10808],
25129 [0x1080a, 0x10835], [0x10837, 0x10838], [0x1083c, 0x1083c], [0x1083f, 0x10855],
25130 [0x10857, 0x1085f], [0x10900, 0x1091b], [0x10920, 0x10939], [0x1093f, 0x1093f],
25131 [0x10980, 0x109b7], [0x109be, 0x109bf], [0x10a00, 0x10a00], [0x10a10, 0x10a13],
25132 [0x10a15, 0x10a17], [0x10a19, 0x10a33], [0x10a40, 0x10a47], [0x10a50, 0x10a58],
25133 [0x10a60, 0x10a7f], [0x10b00, 0x10b35], [0x10b40, 0x10b55], [0x10b58, 0x10b72],
25134 [0x10b78, 0x10b7f], [0x10c00, 0x10c48], [0x1ee00, 0x1ee03], [0x1ee05, 0x1ee1f],
25135 [0x1ee21, 0x1ee22], [0x1ee24, 0x1ee24], [0x1ee27, 0x1ee27], [0x1ee29, 0x1ee32],
25136 [0x1ee34, 0x1ee37], [0x1ee39, 0x1ee39], [0x1ee3b, 0x1ee3b], [0x1ee42, 0x1ee42],
25137 [0x1ee47, 0x1ee47], [0x1ee49, 0x1ee49], [0x1ee4b, 0x1ee4b], [0x1ee4d, 0x1ee4f],
25138 [0x1ee51, 0x1ee52], [0x1ee54, 0x1ee54], [0x1ee57, 0x1ee57], [0x1ee59, 0x1ee59],
25139 [0x1ee5b, 0x1ee5b], [0x1ee5d, 0x1ee5d], [0x1ee5f, 0x1ee5f], [0x1ee61, 0x1ee62],
25140 [0x1ee64, 0x1ee64], [0x1ee67, 0x1ee6a], [0x1ee6c, 0x1ee72], [0x1ee74, 0x1ee77],
25141 [0x1ee79, 0x1ee7c], [0x1ee7e, 0x1ee7e], [0x1ee80, 0x1ee89], [0x1ee8b, 0x1ee9b],
25142 [0x1eea1, 0x1eea3], [0x1eea5, 0x1eea9], [0x1eeab, 0x1eebb], [0x10fffd, 0x10fffd]];
25143
25144function isStrongRTLChar(charCode) {
25145  for (var i = 0; i < strongRTLRanges.length; i++) {
25146    var currentRange = strongRTLRanges[i];
25147    if (charCode >= currentRange[0] && charCode <= currentRange[1]) {
25148      return true;
25149    }
25150  }
25151
25152  return false;
25153}
25154
25155function determineBidi(cueDiv) {
25156  var nodeStack = [],
25157      text = "",
25158      charCode;
25159
25160  if (!cueDiv || !cueDiv.childNodes) {
25161    return "ltr";
25162  }
25163
25164  function pushNodes(nodeStack, node) {
25165    for (var i = node.childNodes.length - 1; i >= 0; i--) {
25166      nodeStack.push(node.childNodes[i]);
25167    }
25168  }
25169
25170  function nextTextNode(nodeStack) {
25171    if (!nodeStack || !nodeStack.length) {
25172      return null;
25173    }
25174
25175    var node = nodeStack.pop(),
25176        text = node.textContent || node.innerText;
25177    if (text) {
25178      // TODO: This should match all unicode type B characters (paragraph
25179      // separator characters). See issue #115.
25180      var m = text.match(/^.*(\n|\r)/);
25181      if (m) {
25182        nodeStack.length = 0;
25183        return m[0];
25184      }
25185      return text;
25186    }
25187    if (node.tagName === "ruby") {
25188      return nextTextNode(nodeStack);
25189    }
25190    if (node.childNodes) {
25191      pushNodes(nodeStack, node);
25192      return nextTextNode(nodeStack);
25193    }
25194  }
25195
25196  pushNodes(nodeStack, cueDiv);
25197  while ((text = nextTextNode(nodeStack))) {
25198    for (var i = 0; i < text.length; i++) {
25199      charCode = text.charCodeAt(i);
25200      if (isStrongRTLChar(charCode)) {
25201        return "rtl";
25202      }
25203    }
25204  }
25205  return "ltr";
25206}
25207
25208function computeLinePos(cue) {
25209  if (typeof cue.line === "number" &&
25210      (cue.snapToLines || (cue.line >= 0 && cue.line <= 100))) {
25211    return cue.line;
25212  }
25213  if (!cue.track || !cue.track.textTrackList ||
25214      !cue.track.textTrackList.mediaElement) {
25215    return -1;
25216  }
25217  var track = cue.track,
25218      trackList = track.textTrackList,
25219      count = 0;
25220  for (var i = 0; i < trackList.length && trackList[i] !== track; i++) {
25221    if (trackList[i].mode === "showing") {
25222      count++;
25223    }
25224  }
25225  return ++count * -1;
25226}
25227
25228function StyleBox() {
25229}
25230
25231// Apply styles to a div. If there is no div passed then it defaults to the
25232// div on 'this'.
25233StyleBox.prototype.applyStyles = function(styles, div) {
25234  div = div || this.div;
25235  for (var prop in styles) {
25236    if (styles.hasOwnProperty(prop)) {
25237      div.style[prop] = styles[prop];
25238    }
25239  }
25240};
25241
25242StyleBox.prototype.formatStyle = function(val, unit) {
25243  return val === 0 ? 0 : val + unit;
25244};
25245
25246// Constructs the computed display state of the cue (a div). Places the div
25247// into the overlay which should be a block level element (usually a div).
25248function CueStyleBox(window, cue, styleOptions) {
25249  var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent);
25250  var color = "rgba(255, 255, 255, 1)";
25251  var backgroundColor = "rgba(0, 0, 0, 0.8)";
25252
25253  if (isIE8) {
25254    color = "rgb(255, 255, 255)";
25255    backgroundColor = "rgb(0, 0, 0)";
25256  }
25257
25258  StyleBox.call(this);
25259  this.cue = cue;
25260
25261  // Parse our cue's text into a DOM tree rooted at 'cueDiv'. This div will
25262  // have inline positioning and will function as the cue background box.
25263  this.cueDiv = parseContent(window, cue.text);
25264  var styles = {
25265    color: color,
25266    backgroundColor: backgroundColor,
25267    position: "relative",
25268    left: 0,
25269    right: 0,
25270    top: 0,
25271    bottom: 0,
25272    display: "inline"
25273  };
25274
25275  if (!isIE8) {
25276    styles.writingMode = cue.vertical === "" ? "horizontal-tb"
25277                                             : cue.vertical === "lr" ? "vertical-lr"
25278                                                                     : "vertical-rl";
25279    styles.unicodeBidi = "plaintext";
25280  }
25281  this.applyStyles(styles, this.cueDiv);
25282
25283  // Create an absolutely positioned div that will be used to position the cue
25284  // div. Note, all WebVTT cue-setting alignments are equivalent to the CSS
25285  // mirrors of them except "middle" which is "center" in CSS.
25286  this.div = window.document.createElement("div");
25287  styles = {
25288    textAlign: cue.align === "middle" ? "center" : cue.align,
25289    font: styleOptions.font,
25290    whiteSpace: "pre-line",
25291    position: "absolute"
25292  };
25293
25294  if (!isIE8) {
25295    styles.direction = determineBidi(this.cueDiv);
25296    styles.writingMode = cue.vertical === "" ? "horizontal-tb"
25297                                             : cue.vertical === "lr" ? "vertical-lr"
25298                                                                     : "vertical-rl".
25299    stylesunicodeBidi =  "plaintext";
25300  }
25301
25302  this.applyStyles(styles);
25303
25304  this.div.appendChild(this.cueDiv);
25305
25306  // Calculate the distance from the reference edge of the viewport to the text
25307  // position of the cue box. The reference edge will be resolved later when
25308  // the box orientation styles are applied.
25309  var textPos = 0;
25310  switch (cue.positionAlign) {
25311  case "start":
25312    textPos = cue.position;
25313    break;
25314  case "middle":
25315    textPos = cue.position - (cue.size / 2);
25316    break;
25317  case "end":
25318    textPos = cue.position - cue.size;
25319    break;
25320  }
25321
25322  // Horizontal box orientation; textPos is the distance from the left edge of the
25323  // area to the left edge of the box and cue.size is the distance extending to
25324  // the right from there.
25325  if (cue.vertical === "") {
25326    this.applyStyles({
25327      left:  this.formatStyle(textPos, "%"),
25328      width: this.formatStyle(cue.size, "%")
25329    });
25330  // Vertical box orientation; textPos is the distance from the top edge of the
25331  // area to the top edge of the box and cue.size is the height extending
25332  // downwards from there.
25333  } else {
25334    this.applyStyles({
25335      top: this.formatStyle(textPos, "%"),
25336      height: this.formatStyle(cue.size, "%")
25337    });
25338  }
25339
25340  this.move = function(box) {
25341    this.applyStyles({
25342      top: this.formatStyle(box.top, "px"),
25343      bottom: this.formatStyle(box.bottom, "px"),
25344      left: this.formatStyle(box.left, "px"),
25345      right: this.formatStyle(box.right, "px"),
25346      height: this.formatStyle(box.height, "px"),
25347      width: this.formatStyle(box.width, "px")
25348    });
25349  };
25350}
25351CueStyleBox.prototype = _objCreate(StyleBox.prototype);
25352CueStyleBox.prototype.constructor = CueStyleBox;
25353
25354// Represents the co-ordinates of an Element in a way that we can easily
25355// compute things with such as if it overlaps or intersects with another Element.
25356// Can initialize it with either a StyleBox or another BoxPosition.
25357function BoxPosition(obj) {
25358  var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent);
25359
25360  // Either a BoxPosition was passed in and we need to copy it, or a StyleBox
25361  // was passed in and we need to copy the results of 'getBoundingClientRect'
25362  // as the object returned is readonly. All co-ordinate values are in reference
25363  // to the viewport origin (top left).
25364  var lh, height, width, top;
25365  if (obj.div) {
25366    height = obj.div.offsetHeight;
25367    width = obj.div.offsetWidth;
25368    top = obj.div.offsetTop;
25369
25370    var rects = (rects = obj.div.childNodes) && (rects = rects[0]) &&
25371                rects.getClientRects && rects.getClientRects();
25372    obj = obj.div.getBoundingClientRect();
25373    // In certain cases the outter div will be slightly larger then the sum of
25374    // the inner div's lines. This could be due to bold text, etc, on some platforms.
25375    // In this case we should get the average line height and use that. This will
25376    // result in the desired behaviour.
25377    lh = rects ? Math.max((rects[0] && rects[0].height) || 0, obj.height / rects.length)
25378               : 0;
25379
25380  }
25381  this.left = obj.left;
25382  this.right = obj.right;
25383  this.top = obj.top || top;
25384  this.height = obj.height || height;
25385  this.bottom = obj.bottom || (top + (obj.height || height));
25386  this.width = obj.width || width;
25387  this.lineHeight = lh !== undefined ? lh : obj.lineHeight;
25388
25389  if (isIE8 && !this.lineHeight) {
25390    this.lineHeight = 13;
25391  }
vendor: 20,253 bytes, lines 25391-26045
25391
25392}
25393
25394// Move the box along a particular axis. Optionally pass in an amount to move
25395// the box. If no amount is passed then the default is the line height of the
25396// box.
25397BoxPosition.prototype.move = function(axis, toMove) {
25398  toMove = toMove !== undefined ? toMove : this.lineHeight;
25399  switch (axis) {
25400  case "+x":
25401    this.left += toMove;
25402    this.right += toMove;
25403    break;
25404  case "-x":
25405    this.left -= toMove;
25406    this.right -= toMove;
25407    break;
25408  case "+y":
25409    this.top += toMove;
25410    this.bottom += toMove;
25411    break;
25412  case "-y":
25413    this.top -= toMove;
25414    this.bottom -= toMove;
25415    break;
25416  }
25417};
25418
25419// Check if this box overlaps another box, b2.
25420BoxPosition.prototype.overlaps = function(b2) {
25421  return this.left < b2.right &&
25422         this.right > b2.left &&
25423         this.top < b2.bottom &&
25424         this.bottom > b2.top;
25425};
25426
25427// Check if this box overlaps any other boxes in boxes.
25428BoxPosition.prototype.overlapsAny = function(boxes) {
25429  for (var i = 0; i < boxes.length; i++) {
25430    if (this.overlaps(boxes[i])) {
25431      return true;
25432    }
25433  }
25434  return false;
25435};
25436
25437// Check if this box is within another box.
25438BoxPosition.prototype.within = function(container) {
25439  return this.top >= container.top &&
25440         this.bottom <= container.bottom &&
25441         this.left >= container.left &&
25442         this.right <= container.right;
25443};
25444
25445// Check if this box is entirely within the container or it is overlapping
25446// on the edge opposite of the axis direction passed. For example, if "+x" is
25447// passed and the box is overlapping on the left edge of the container, then
25448// return true.
25449BoxPosition.prototype.overlapsOppositeAxis = function(container, axis) {
25450  switch (axis) {
25451  case "+x":
25452    return this.left < container.left;
25453  case "-x":
25454    return this.right > container.right;
25455  case "+y":
25456    return this.top < container.top;
25457  case "-y":
25458    return this.bottom > container.bottom;
25459  }
25460};
25461
25462// Find the percentage of the area that this box is overlapping with another
25463// box.
25464BoxPosition.prototype.intersectPercentage = function(b2) {
25465  var x = Math.max(0, Math.min(this.right, b2.right) - Math.max(this.left, b2.left)),
25466      y = Math.max(0, Math.min(this.bottom, b2.bottom) - Math.max(this.top, b2.top)),
25467      intersectArea = x * y;
25468  return intersectArea / (this.height * this.width);
25469};
25470
25471// Convert the positions from this box to CSS compatible positions using
25472// the reference container's positions. This has to be done because this
25473// box's positions are in reference to the viewport origin, whereas, CSS
25474// values are in referecne to their respective edges.
25475BoxPosition.prototype.toCSSCompatValues = function(reference) {
25476  return {
25477    top: this.top - reference.top,
25478    bottom: reference.bottom - this.bottom,
25479    left: this.left - reference.left,
25480    right: reference.right - this.right,
25481    height: this.height,
25482    width: this.width
25483  };
25484};
25485
25486// Get an object that represents the box's position without anything extra.
25487// Can pass a StyleBox, HTMLElement, or another BoxPositon.
25488BoxPosition.getSimpleBoxPosition = function(obj) {
25489  var height = obj.div ? obj.div.offsetHeight : obj.tagName ? obj.offsetHeight : 0;
25490  var width = obj.div ? obj.div.offsetWidth : obj.tagName ? obj.offsetWidth : 0;
25491  var top = obj.div ? obj.div.offsetTop : obj.tagName ? obj.offsetTop : 0;
25492
25493  obj = obj.div ? obj.div.getBoundingClientRect() :
25494                obj.tagName ? obj.getBoundingClientRect() : obj;
25495  var ret = {
25496    left: obj.left,
25497    right: obj.right,
25498    top: obj.top || top,
25499    height: obj.height || height,
25500    bottom: obj.bottom || (top + (obj.height || height)),
25501    width: obj.width || width
25502  };
25503  return ret;
25504};
25505
25506// Move a StyleBox to its specified, or next best, position. The containerBox
25507// is the box that contains the StyleBox, such as a div. boxPositions are
25508// a list of other boxes that the styleBox can't overlap with.
25509function moveBoxToLinePosition(window, styleBox, containerBox, boxPositions) {
25510
25511  // Find the best position for a cue box, b, on the video. The axis parameter
25512  // is a list of axis, the order of which, it will move the box along. For example:
25513  // Passing ["+x", "-x"] will move the box first along the x axis in the positive
25514  // direction. If it doesn't find a good position for it there it will then move
25515  // it along the x axis in the negative direction.
25516  function findBestPosition(b, axis) {
25517    var bestPosition,
25518        specifiedPosition = new BoxPosition(b),
25519        percentage = 1; // Highest possible so the first thing we get is better.
25520
25521    for (var i = 0; i < axis.length; i++) {
25522      while (b.overlapsOppositeAxis(containerBox, axis[i]) ||
25523             (b.within(containerBox) && b.overlapsAny(boxPositions))) {
25524        b.move(axis[i]);
25525      }
25526      // We found a spot where we aren't overlapping anything. This is our
25527      // best position.
25528      if (b.within(containerBox)) {
25529        return b;
25530      }
25531      var p = b.intersectPercentage(containerBox);
25532      // If we're outside the container box less then we were on our last try
25533      // then remember this position as the best position.
25534      if (percentage > p) {
25535        bestPosition = new BoxPosition(b);
25536        percentage = p;
25537      }
25538      // Reset the box position to the specified position.
25539      b = new BoxPosition(specifiedPosition);
25540    }
25541    return bestPosition || specifiedPosition;
25542  }
25543
25544  var boxPosition = new BoxPosition(styleBox),
25545      cue = styleBox.cue,
25546      linePos = computeLinePos(cue),
25547      axis = [];
25548
25549  // If we have a line number to align the cue to.
25550  if (cue.snapToLines) {
25551    var size;
25552    switch (cue.vertical) {
25553    case "":
25554      axis = [ "+y", "-y" ];
25555      size = "height";
25556      break;
25557    case "rl":
25558      axis = [ "+x", "-x" ];
25559      size = "width";
25560      break;
25561    case "lr":
25562      axis = [ "-x", "+x" ];
25563      size = "width";
25564      break;
25565    }
25566
25567    var step = boxPosition.lineHeight,
25568        position = step * Math.round(linePos),
25569        maxPosition = containerBox[size] + step,
25570        initialAxis = axis[0];
25571
25572    // If the specified intial position is greater then the max position then
25573    // clamp the box to the amount of steps it would take for the box to
25574    // reach the max position.
25575    if (Math.abs(position) > maxPosition) {
25576      position = position < 0 ? -1 : 1;
25577      position *= Math.ceil(maxPosition / step) * step;
25578    }
25579
25580    // If computed line position returns negative then line numbers are
25581    // relative to the bottom of the video instead of the top. Therefore, we
25582    // need to increase our initial position by the length or width of the
25583    // video, depending on the writing direction, and reverse our axis directions.
25584    if (linePos < 0) {
25585      position += cue.vertical === "" ? containerBox.height : containerBox.width;
25586      axis = axis.reverse();
25587    }
25588
25589    // Move the box to the specified position. This may not be its best
25590    // position.
25591    boxPosition.move(initialAxis, position);
25592
25593  } else {
25594    // If we have a percentage line value for the cue.
25595    var calculatedPercentage = (boxPosition.lineHeight / containerBox.height) * 100;
25596
25597    switch (cue.lineAlign) {
25598    case "middle":
25599      linePos -= (calculatedPercentage / 2);
25600      break;
25601    case "end":
25602      linePos -= calculatedPercentage;
25603      break;
25604    }
25605
25606    // Apply initial line position to the cue box.
25607    switch (cue.vertical) {
25608    case "":
25609      styleBox.applyStyles({
25610        top: styleBox.formatStyle(linePos, "%")
25611      });
25612      break;
25613    case "rl":
25614      styleBox.applyStyles({
25615        left: styleBox.formatStyle(linePos, "%")
25616      });
25617      break;
25618    case "lr":
25619      styleBox.applyStyles({
25620        right: styleBox.formatStyle(linePos, "%")
25621      });
25622      break;
25623    }
25624
25625    axis = [ "+y", "-x", "+x", "-y" ];
25626
25627    // Get the box position again after we've applied the specified positioning
25628    // to it.
25629    boxPosition = new BoxPosition(styleBox);
25630  }
25631
25632  var bestPosition = findBestPosition(boxPosition, axis);
25633  styleBox.move(bestPosition.toCSSCompatValues(containerBox));
25634}
25635
25636function WebVTT() {
25637  // Nothing
25638}
25639
25640// Helper to allow strings to be decoded instead of the default binary utf8 data.
25641WebVTT.StringDecoder = function() {
25642  return {
25643    decode: function(data) {
25644      if (!data) {
25645        return "";
25646      }
25647      if (typeof data !== "string") {
25648        throw new Error("Error - expected string data.");
25649      }
25650      return decodeURIComponent(encodeURIComponent(data));
25651    }
25652  };
25653};
25654
25655WebVTT.convertCueToDOMTree = function(window, cuetext) {
25656  if (!window || !cuetext) {
25657    return null;
25658  }
25659  return parseContent(window, cuetext);
25660};
25661
25662var FONT_SIZE_PERCENT = 0.05;
25663var FONT_STYLE = "sans-serif";
25664var CUE_BACKGROUND_PADDING = "1.5%";
25665
25666// Runs the processing model over the cues and regions passed to it.
25667// @param overlay A block level element (usually a div) that the computed cues
25668//                and regions will be placed into.
25669WebVTT.processCues = function(window, cues, overlay) {
25670  if (!window || !cues || !overlay) {
25671    return null;
25672  }
25673
25674  // Remove all previous children.
25675  while (overlay.firstChild) {
25676    overlay.removeChild(overlay.firstChild);
25677  }
25678
25679  var paddedOverlay = window.document.createElement("div");
25680  paddedOverlay.style.position = "absolute";
25681  paddedOverlay.style.left = "0";
25682  paddedOverlay.style.right = "0";
25683  paddedOverlay.style.top = "0";
25684  paddedOverlay.style.bottom = "0";
25685  paddedOverlay.style.margin = CUE_BACKGROUND_PADDING;
25686  overlay.appendChild(paddedOverlay);
25687
25688  // Determine if we need to compute the display states of the cues. This could
25689  // be the case if a cue's state has been changed since the last computation or
25690  // if it has not been computed yet.
25691  function shouldCompute(cues) {
25692    for (var i = 0; i < cues.length; i++) {
25693      if (cues[i].hasBeenReset || !cues[i].displayState) {
25694        return true;
25695      }
25696    }
25697    return false;
25698  }
25699
25700  // We don't need to recompute the cues' display states. Just reuse them.
25701  if (!shouldCompute(cues)) {
25702    for (var i = 0; i < cues.length; i++) {
25703      paddedOverlay.appendChild(cues[i].displayState);
25704    }
25705    return;
25706  }
25707
25708  var boxPositions = [],
25709      containerBox = BoxPosition.getSimpleBoxPosition(paddedOverlay),
25710      fontSize = Math.round(containerBox.height * FONT_SIZE_PERCENT * 100) / 100;
25711  var styleOptions = {
25712    font: fontSize + "px " + FONT_STYLE
25713  };
25714
25715  (function() {
25716    var styleBox, cue;
25717
25718    for (var i = 0; i < cues.length; i++) {
25719      cue = cues[i];
25720
25721      // Compute the intial position and styles of the cue div.
25722      styleBox = new CueStyleBox(window, cue, styleOptions);
25723      paddedOverlay.appendChild(styleBox.div);
25724
25725      // Move the cue div to it's correct line position.
25726      moveBoxToLinePosition(window, styleBox, containerBox, boxPositions);
25727
25728      // Remember the computed div so that we don't have to recompute it later
25729      // if we don't have too.
25730      cue.displayState = styleBox.div;
25731
25732      boxPositions.push(BoxPosition.getSimpleBoxPosition(styleBox));
25733    }
25734  })();
25735};
25736
25737WebVTT.Parser = function(window, vttjs, decoder) {
25738  if (!decoder) {
25739    decoder = vttjs;
25740    vttjs = {};
25741  }
25742  if (!vttjs) {
25743    vttjs = {};
25744  }
25745
25746  this.window = window;
25747  this.vttjs = vttjs;
25748  this.state = "INITIAL";
25749  this.buffer = "";
25750  this.decoder = decoder || new TextDecoder("utf8");
25751  this.regionList = [];
25752};
25753
25754WebVTT.Parser.prototype = {
25755  // If the error is a ParsingError then report it to the consumer if
25756  // possible. If it's not a ParsingError then throw it like normal.
25757  reportOrThrowError: function(e) {
25758    if (e instanceof ParsingError) {
25759      this.onparsingerror && this.onparsingerror(e);
25760    } else {
25761      throw e;
25762    }
25763  },
25764  parse: function (data) {
25765    var self = this;
25766
25767    // If there is no data then we won't decode it, but will just try to parse
25768    // whatever is in buffer already. This may occur in circumstances, for
25769    // example when flush() is called.
25770    if (data) {
25771      // Try to decode the data that we received.
25772      self.buffer += self.decoder.decode(data, {stream: true});
25773    }
25774
25775    function collectNextLine() {
25776      var buffer = self.buffer;
25777      var pos = 0;
25778      while (pos < buffer.length && buffer[pos] !== '\r' && buffer[pos] !== '\n') {
25779        ++pos;
25780      }
25781      var line = buffer.substr(0, pos);
25782      // Advance the buffer early in case we fail below.
25783      if (buffer[pos] === '\r') {
25784        ++pos;
25785      }
25786      if (buffer[pos] === '\n') {
25787        ++pos;
25788      }
25789      self.buffer = buffer.substr(pos);
25790      return line;
25791    }
25792
25793    // 3.4 WebVTT region and WebVTT region settings syntax
25794    function parseRegion(input) {
25795      var settings = new Settings();
25796
25797      parseOptions(input, function (k, v) {
25798        switch (k) {
25799        case "id":
25800          settings.set(k, v);
25801          break;
25802        case "width":
25803          settings.percent(k, v);
25804          break;
25805        case "lines":
25806          settings.integer(k, v);
25807          break;
25808        case "regionanchor":
25809        case "viewportanchor":
25810          var xy = v.split(',');
25811          if (xy.length !== 2) {
25812            break;
25813          }
25814          // We have to make sure both x and y parse, so use a temporary
25815          // settings object here.
25816          var anchor = new Settings();
25817          anchor.percent("x", xy[0]);
25818          anchor.percent("y", xy[1]);
25819          if (!anchor.has("x") || !anchor.has("y")) {
25820            break;
25821          }
25822          settings.set(k + "X", anchor.get("x"));
25823          settings.set(k + "Y", anchor.get("y"));
25824          break;
25825        case "scroll":
25826          settings.alt(k, v, ["up"]);
25827          break;
25828        }
25829      }, /=/, /\s/);
25830
25831      // Create the region, using default values for any values that were not
25832      // specified.
25833      if (settings.has("id")) {
25834        var region = new (self.vttjs.VTTRegion || self.window.VTTRegion)();
25835        region.width = settings.get("width", 100);
25836        region.lines = settings.get("lines", 3);
25837        region.regionAnchorX = settings.get("regionanchorX", 0);
25838        region.regionAnchorY = settings.get("regionanchorY", 100);
25839        region.viewportAnchorX = settings.get("viewportanchorX", 0);
25840        region.viewportAnchorY = settings.get("viewportanchorY", 100);
25841        region.scroll = settings.get("scroll", "");
25842        // Register the region.
25843        self.onregion && self.onregion(region);
25844        // Remember the VTTRegion for later in case we parse any VTTCues that
25845        // reference it.
25846        self.regionList.push({
25847          id: settings.get("id"),
25848          region: region
25849        });
25850      }
25851    }
25852
25853    // draft-pantos-http-live-streaming-20
25854    // https://tools.ietf.org/html/draft-pantos-http-live-streaming-20#section-3.5
25855    // 3.5 WebVTT
25856    function parseTimestampMap(input) {
25857      var settings = new Settings();
25858
25859      parseOptions(input, function(k, v) {
25860        switch(k) {
25861        case "MPEGT":
25862          settings.integer(k + 'S', v);
25863          break;
25864        case "LOCA":
25865          settings.set(k + 'L', parseTimeStamp(v));
25866          break;
25867        }
25868      }, /[^\d]:/, /,/);
25869
25870      self.ontimestampmap && self.ontimestampmap({
25871        "MPEGTS": settings.get("MPEGTS"),
25872        "LOCAL": settings.get("LOCAL")
25873      });
25874    }
25875
25876    // 3.2 WebVTT metadata header syntax
25877    function parseHeader(input) {
25878      if (input.match(/X-TIMESTAMP-MAP/)) {
25879        // This line contains HLS X-TIMESTAMP-MAP metadata
25880        parseOptions(input, function(k, v) {
25881          switch(k) {
25882          case "X-TIMESTAMP-MAP":
25883            parseTimestampMap(v);
25884            break;
25885          }
25886        }, /=/);
25887      } else {
25888        parseOptions(input, function (k, v) {
25889          switch (k) {
25890          case "Region":
25891            // 3.3 WebVTT region metadata header syntax
25892            parseRegion(v);
25893            break;
25894          }
25895        }, /:/);
25896      }
25897
25898    }
25899
25900    // 5.1 WebVTT file parsing.
25901    try {
25902      var line;
25903      if (self.state === "INITIAL") {
25904        // We can't start parsing until we have the first line.
25905        if (!/\r\n|\n/.test(self.buffer)) {
25906          return this;
25907        }
25908
25909        line = collectNextLine();
25910
25911        var m = line.match(/^WEBVTT([ \t].*)?$/);
25912        if (!m || !m[0]) {
25913          throw new ParsingError(ParsingError.Errors.BadSignature);
25914        }
25915
25916        self.state = "HEADER";
25917      }
25918
25919      var alreadyCollectedLine = false;
25920      while (self.buffer) {
25921        // We can't parse a line until we have the full line.
25922        if (!/\r\n|\n/.test(self.buffer)) {
25923          return this;
25924        }
25925
25926        if (!alreadyCollectedLine) {
25927          line = collectNextLine();
25928        } else {
25929          alreadyCollectedLine = false;
25930        }
25931
25932        switch (self.state) {
25933        case "HEADER":
25934          // 13-18 - Allow a header (metadata) under the WEBVTT line.
25935          if (/:/.test(line)) {
25936            parseHeader(line);
25937          } else if (!line) {
25938            // An empty line terminates the header and starts the body (cues).
25939            self.state = "ID";
25940          }
25941          continue;
25942        case "NOTE":
25943          // Ignore NOTE blocks.
25944          if (!line) {
25945            self.state = "ID";
25946          }
25947          continue;
25948        case "ID":
25949          // Check for the start of NOTE blocks.
25950          if (/^NOTE($|[ \t])/.test(line)) {
25951            self.state = "NOTE";
25952            break;
25953          }
25954          // 19-29 - Allow any number of line terminators, then initialize new cue values.
25955          if (!line) {
25956            continue;
25957          }
25958          self.cue = new (self.vttjs.VTTCue || self.window.VTTCue)(0, 0, "");
25959          self.state = "CUE";
25960          // 30-39 - Check if self line contains an optional identifier or timing data.
25961          if (line.indexOf("-->") === -1) {
25962            self.cue.id = line;
25963            continue;
25964          }
25965          // Process line as start of a cue.
25966          /*falls through*/
25967        case "CUE":
25968          // 40 - Collect cue timings and settings.
25969          try {
25970            parseCue(line, self.cue, self.regionList);
25971          } catch (e) {
25972            self.reportOrThrowError(e);
25973            // In case of an error ignore rest of the cue.
25974            self.cue = null;
25975            self.state = "BADCUE";
25976            continue;
25977          }
25978          self.state = "CUETEXT";
25979          continue;
25980        case "CUETEXT":
25981          var hasSubstring = line.indexOf("-->") !== -1;
25982          // 34 - If we have an empty line then report the cue.
25983          // 35 - If we have the special substring '-->' then report the cue,
25984          // but do not collect the line as we need to process the current
25985          // one as a new cue.
25986          if (!line || hasSubstring && (alreadyCollectedLine = true)) {
25987            // We are done parsing self cue.
25988            self.oncue && self.oncue(self.cue);
25989            self.cue = null;
25990            self.state = "ID";
25991            continue;
25992          }
25993          if (self.cue.text) {
25994            self.cue.text += "\n";
25995          }
25996          self.cue.text += line;
25997          continue;
25998        case "BADCUE": // BADCUE
25999          // 54-62 - Collect and discard the remaining cue.
26000          if (!line) {
26001            self.state = "ID";
26002          }
26003          continue;
26004        }
26005      }
26006    } catch (e) {
26007      self.reportOrThrowError(e);
26008
26009      // If we are currently parsing a cue, report what we have.
26010      if (self.state === "CUETEXT" && self.cue && self.oncue) {
26011        self.oncue(self.cue);
26012      }
26013      self.cue = null;
26014      // Enter BADWEBVTT state if header was not parsed correctly otherwise
26015      // another exception occurred so enter BADCUE state.
26016      self.state = self.state === "INITIAL" ? "BADWEBVTT" : "BADCUE";
26017    }
26018    return this;
26019  },
26020  flush: function () {
26021    var self = this;
26022    try {
26023      // Finish decoding the stream.
26024      self.buffer += self.decoder.decode();
26025      // Synthesize the end of the current cue or region.
26026      if (self.cue || self.state === "HEADER") {
26027        self.buffer += "\n\n";
26028        self.parse();
26029      }
26030      // If we've flushed, parsed, and we're still on the INITIAL state then
26031      // that means we don't have enough of the stream to parse the first
26032      // line.
26033      if (self.state === "INITIAL") {
26034        throw new ParsingError(ParsingError.Errors.BadSignature);
26035      }
26036    } catch(e) {
26037      self.reportOrThrowError(e);
26038    }
26039    self.onflush && self.onflush();
26040    return this;
26041  }
26042};
26043
26044module.exports = WebVTT;
26045
26046},{}],101:[function(_dereq_,module,exports){
26047/**
26048 * Copyright 2013 vtt.js Contributors
26049 *
26050 * Licensed under the Apache License, Version 2.0 (the "License");
26051 * you may not use this file except in compliance with the License.
26052 * You may obtain a copy of the License at
26053 *
26054 *   http://www.apache.org/licenses/LICENSE-2.0
26055 *
26056 * Unless required by applicable law or agreed to in writing, software
26057 * distributed under the License is distributed on an "AS IS" BASIS,
26058 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26059 * See the License for the specific language governing permissions and
26060 * limitations under the License.
26061 */
26062
26063var autoKeyword = "auto";
26064var directionSetting = {
26065  "": true,
26066  "lr": true,
26067  "rl": true
26068};
26069var alignSetting = {
26070  "start": true,
26071  "middle": true,
26072  "end": true,
26073  "left": true,
26074  "right": true
26075};
26076
26077function findDirectionSetting(value) {
26078  if (typeof value !== "string") {
26079    return false;
26080  }
26081  var dir = directionSetting[value.toLowerCase()];
26082  return dir ? value.toLowerCase() : false;
26083}
26084
26085function findAlignSetting(value) {
26086  if (typeof value !== "string") {
26087    return false;
26088  }
26089  var align = alignSetting[value.toLowerCase()];
26090  return align ? value.toLowerCase() : false;
26091}
26092
26093function extend(obj) {
26094  var i = 1;
26095  for (; i < arguments.length; i++) {
26096    var cobj = arguments[i];
26097    for (var p in cobj) {
26098      obj[p] = cobj[p];
26099    }
26100  }
26101
26102  return obj;
26103}
26104
26105function VTTCue(startTime, endTime, text) {
26106  var cue = this;
26107  var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent);
26108  var baseObj = {};
26109
26110  if (isIE8) {
26111    cue = document.createElement('custom');
26112  } else {
26113    baseObj.enumerable = true;
26114  }
26115
26116  /**
26117   * Shim implementation specific properties. These properties are not in
26118   * the spec.
26119   */
26120
26121  // Lets us know when the VTTCue's data has changed in such a way that we need
26122  // to recompute its display state. This lets us compute its display state
26123  // lazily.
26124  cue.hasBeenReset = false;
26125
26126  /**
26127   * VTTCue and TextTrackCue properties
26128   * http://dev.w3.org/html5/webvtt/#vttcue-interface
26129   */
26130
26131  var _id = "";
26132  var _pauseOnExit = false;
26133  var _startTime = startTime;
26134  var _endTime = endTime;
26135  var _text = text;
26136  var _region = null;
26137  var _vertical = "";
26138  var _snapToLines = true;
26139  var _line = "auto";
26140  var _lineAlign = "start";
26141  var _position = 50;
26142  var _positionAlign = "middle";
26143  var _size = 50;
26144  var _align = "middle";
26145
26146  Object.defineProperty(cue,
26147    "id", extend({}, baseObj, {
26148      get: function() {
26149        return _id;
26150      },
26151      set: function(value) {
26152        _id = "" + value;
26153      }
26154    }));
26155
26156  Object.defineProperty(cue,
26157    "pauseOnExit", extend({}, baseObj, {
26158      get: function() {
26159        return _pauseOnExit;
26160      },
26161      set: function(value) {
26162        _pauseOnExit = !!value;
26163      }
26164    }));
26165
26166  Object.defineProperty(cue,
26167    "startTime", extend({}, baseObj, {
26168      get: function() {
26169        return _startTime;
26170      },
26171      set: function(value) {
26172        if (typeof value !== "number") {
26173          throw new TypeError("Start time must be set to a number.");
26174        }
26175        _startTime = value;
26176        this.hasBeenReset = true;
26177      }
26178    }));
26179
26180  Object.defineProperty(cue,
26181    "endTime", extend({}, baseObj, {
26182      get: function() {
26183        return _endTime;
26184      },
26185      set: function(value) {
26186        if (typeof value !== "number") {
26187          throw new TypeError("End time must be set to a number.");
26188        }
26189        _endTime = value;
26190        this.hasBeenReset = true;
26191      }
26192    }));
26193
26194  Object.defineProperty(cue,
26195    "text", extend({}, baseObj, {
26196      get: function() {
26197        return _text;
26198      },
26199      set: function(value) {
26200        _text = "" + value;
26201        this.hasBeenReset = true;
26202      }
26203    }));
26204
26205  Object.defineProperty(cue,
26206    "region", extend({}, baseObj, {
26207      get: function() {
26208        return _region;
26209      },
26210      set: function(value) {
26211        _region = value;
26212        this.hasBeenReset = true;
26213      }
26214    }));
26215
26216  Object.defineProperty(cue,
26217    "vertical", extend({}, baseObj, {
26218      get: function() {
26219        return _vertical;
26220      },
26221      set: function(value) {
26222        var setting = findDirectionSetting(value);
26223        // Have to check for false because the setting an be an empty string.
26224        if (setting === false) {
26225          throw new SyntaxError("An invalid or illegal string was specified.");
26226        }
26227        _vertical = setting;
26228        this.hasBeenReset = true;
26229      }
26230    }));
26231
26232  Object.defineProperty(cue,
26233    "snapToLines", extend({}, baseObj, {
26234      get: function() {
26235        return _snapToLines;
26236      },
26237      set: function(value) {
26238        _snapToLines = !!value;
26239        this.hasBeenReset = true;
26240      }
26241    }));
26242
26243  Object.defineProperty(cue,
26244    "line", extend({}, baseObj, {
26245      get: function() {
26246        return _line;
26247      },
26248      set: function(value) {
26249        if (typeof value !== "number" && value !== autoKeyword) {
26250          throw new SyntaxError("An invalid number or illegal string was specified.");
26251        }
26252        _line = value;
26253        this.hasBeenReset = true;
26254      }
26255    }));
26256
26257  Object.defineProperty(cue,
26258    "lineAlign", extend({}, baseObj, {
26259      get: function() {
26260        return _lineAlign;
26261      },
26262      set: function(value) {
26263        var setting = findAlignSetting(value);
26264        if (!setting) {
26265          throw new SyntaxError("An invalid or illegal string was specified.");
26266        }
26267        _lineAlign = setting;
26268        this.hasBeenReset = true;
26269      }
26270    }));
26271
26272  Object.defineProperty(cue,
26273    "position", extend({}, baseObj, {
26274      get: function() {
26275        return _position;
26276      },
26277      set: function(value) {
26278        if (value < 0 || value > 100) {
26279          throw new Error("Position must be between 0 and 100.");
26280        }
26281        _position = value;
26282        this.hasBeenReset = true;
26283      }
26284    }));
26285
26286  Object.defineProperty(cue,
26287    "positionAlign", extend({}, baseObj, {
26288      get: function() {
26289        return _positionAlign;
26290      },
26291      set: function(value) {
26292        var setting = findAlignSetting(value);
26293        if (!setting) {
26294          throw new SyntaxError("An invalid or illegal string was specified.");
26295        }
26296        _positionAlign = setting;
26297        this.hasBeenReset = true;
26298      }
26299    }));
26300
26301  Object.defineProperty(cue,
26302    "size", extend({}, baseObj, {
26303      get: function() {
26304        return _size;
26305      },
26306      set: function(value) {
26307        if (value < 0 || value > 100) {
26308          throw new Error("Size must be between 0 and 100.");
26309        }
26310        _size = value;
26311        this.hasBeenReset = true;
26312      }
26313    }));
26314
26315  Object.defineProperty(cue,
26316    "align", extend({}, baseObj, {
26317      get: function() {
26318        return _align;
26319      },
26320      set: function(value) {
26321        var setting = findAlignSetting(value);
26322        if (!setting) {
26323          throw new SyntaxError("An invalid or illegal string was specified.");
26324        }
26325        _align = setting;
26326        this.hasBeenReset = true;
26327      }
26328    }));
26329
26330  /**
26331   * Other <track> spec defined properties
26332   */
26333
26334  // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-display-state
26335  cue.displayState = undefined;
26336
26337  if (isIE8) {
26338    return cue;
26339  }
26340}
26341
26342/**
26343 * VTTCue methods
26344 */
26345
26346VTTCue.prototype.getCueAsHTML = function() {
26347  // Assume WebVTT.convertCueToDOMTree is on the global.
26348  return WebVTT.convertCueToDOMTree(window, this.text);
26349};
26350
26351module.exports = VTTCue;
26352
26353},{}],102:[function(_dereq_,module,exports){
26354/**
26355 * Copyright 2013 vtt.js Contributors
26356 *
26357 * Licensed under the Apache License, Version 2.0 (the "License");
26358 * you may not use this file except in compliance with the License.
26359 * You may obtain a copy of the License at
26360 *
26361 *   http://www.apache.org/licenses/LICENSE-2.0
26362 *
26363 * Unless required by applicable law or agreed to in writing, software
26364 * distributed under the License is distributed on an "AS IS" BASIS,
26365 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26366 * See the License for the specific language governing permissions and
26367 * limitations under the License.
26368 */
26369
26370var scrollSetting = {
26371  "": true,
26372  "up": true
26373};
26374
26375function findScrollSetting(value) {
26376  if (typeof value !== "string") {
26377    return false;
26378  }
26379  var scroll = scrollSetting[value.toLowerCase()];
26380  return scroll ? value.toLowerCase() : false;
26381}
26382
26383function isValidPercentValue(value) {
26384  return typeof value === "number" && (value >= 0 && value <= 100);
26385}
26386
26387// VTTRegion shim http://dev.w3.org/html5/webvtt/#vttregion-interface
26388function VTTRegion() {
26389  var _width = 100;
26390  var _lines = 3;
26391  var _regionAnchorX = 0;
26392  var _regionAnchorY = 100;
26393  var _viewportAnchorX = 0;
26394  var _viewportAnchorY = 100;
26395  var _scroll = "";
26396
26397  Object.defineProperties(this, {
26398    "width": {
26399      enumerable: true,
26400      get: function() {
26401        return _width;
26402      },
26403      set: function(value) {
26404        if (!isValidPercentValue(value)) {
26405          throw new Error("Width must be between 0 and 100.");
26406        }
26407        _width = value;
26408      }
26409    },
26410    "lines": {
26411      enumerable: true,
26412      get: function() {
26413        return _lines;
26414      },
26415      set: function(value) {
vendor: 9,167 bytes, lines 26416-26743
26416        if (typeof value !== "number") {
26417          throw new TypeError("Lines must be set to a number.");
26418        }
26419        _lines = value;
26420      }
26421    },
26422    "regionAnchorY": {
26423      enumerable: true,
26424      get: function() {
26425        return _regionAnchorY;
26426      },
26427      set: function(value) {
26428        if (!isValidPercentValue(value)) {
26429          throw new Error("RegionAnchorX must be between 0 and 100.");
26430        }
26431        _regionAnchorY = value;
26432      }
26433    },
26434    "regionAnchorX": {
26435      enumerable: true,
26436      get: function() {
26437        return _regionAnchorX;
26438      },
26439      set: function(value) {
26440        if(!isValidPercentValue(value)) {
26441          throw new Error("RegionAnchorY must be between 0 and 100.");
26442        }
26443        _regionAnchorX = value;
26444      }
26445    },
26446    "viewportAnchorY": {
26447      enumerable: true,
26448      get: function() {
26449        return _viewportAnchorY;
26450      },
26451      set: function(value) {
26452        if (!isValidPercentValue(value)) {
26453          throw new Error("ViewportAnchorY must be between 0 and 100.");
26454        }
26455        _viewportAnchorY = value;
26456      }
26457    },
26458    "viewportAnchorX": {
26459      enumerable: true,
26460      get: function() {
26461        return _viewportAnchorX;
26462      },
26463      set: function(value) {
26464        if (!isValidPercentValue(value)) {
26465          throw new Error("ViewportAnchorX must be between 0 and 100.");
26466        }
26467        _viewportAnchorX = value;
26468      }
26469    },
26470    "scroll": {
26471      enumerable: true,
26472      get: function() {
26473        return _scroll;
26474      },
26475      set: function(value) {
26476        var setting = findScrollSetting(value);
26477        // Have to check for false as an empty string is a legal value.
26478        if (setting === false) {
26479          throw new SyntaxError("An invalid or illegal string was specified.");
26480        }
26481        _scroll = setting;
26482      }
26483    }
26484  });
26485}
26486
26487module.exports = VTTRegion;
26488
26489},{}],103:[function(_dereq_,module,exports){
26490(function (global){
26491var win;
26492
26493if (typeof window !== "undefined") {
26494    win = window;
26495} else if (typeof global !== "undefined") {
26496    win = global;
26497} else if (typeof self !== "undefined"){
26498    win = self;
26499} else {
26500    win = {};
26501}
26502
26503module.exports = win;
26504
26505}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
26506},{}],104:[function(_dereq_,module,exports){
26507"use strict";
26508var window = _dereq_(95)
26509var isFunction = _dereq_(105)
26510var parseHeaders = _dereq_(108)
26511var xtend = _dereq_(109)
26512
26513module.exports = createXHR
26514createXHR.XMLHttpRequest = window.XMLHttpRequest || noop
26515createXHR.XDomainRequest = "withCredentials" in (new createXHR.XMLHttpRequest()) ? createXHR.XMLHttpRequest : window.XDomainRequest
26516
26517forEachArray(["get", "put", "post", "patch", "head", "delete"], function(method) {
26518    createXHR[method === "delete" ? "del" : method] = function(uri, options, callback) {
26519        options = initParams(uri, options, callback)
26520        options.method = method.toUpperCase()
26521        return _createXHR(options)
26522    }
26523})
26524
26525function forEachArray(array, iterator) {
26526    for (var i = 0; i < array.length; i++) {
26527        iterator(array[i])
26528    }
26529}
26530
26531function isEmpty(obj){
26532    for(var i in obj){
26533        if(obj.hasOwnProperty(i)) return false
26534    }
26535    return true
26536}
26537
26538function initParams(uri, options, callback) {
26539    var params = uri
26540
26541    if (isFunction(options)) {
26542        callback = options
26543        if (typeof uri === "string") {
26544            params = {uri:uri}
26545        }
26546    } else {
26547        params = xtend(options, {uri: uri})
26548    }
26549
26550    params.callback = callback
26551    return params
26552}
26553
26554function createXHR(uri, options, callback) {
26555    options = initParams(uri, options, callback)
26556    return _createXHR(options)
26557}
26558
26559function _createXHR(options) {
26560    if(typeof options.callback === "undefined"){
26561        throw new Error("callback argument missing")
26562    }
26563
26564    var called = false
26565    var callback = function cbOnce(err, response, body){
26566        if(!called){
26567            called = true
26568            options.callback(err, response, body)
26569        }
26570    }
26571
26572    function readystatechange() {
26573        if (xhr.readyState === 4) {
26574            loadFunc()
26575        }
26576    }
26577
26578    function getBody() {
26579        // Chrome with requestType=blob throws errors arround when even testing access to responseText
26580        var body = undefined
26581
26582        if (xhr.response) {
26583            body = xhr.response
26584        } else {
26585            body = xhr.responseText || getXml(xhr)
26586        }
26587
26588        if (isJson) {
26589            try {
26590                body = JSON.parse(body)
26591            } catch (e) {}
26592        }
26593
26594        return body
26595    }
26596
26597    var failureResponse = {
26598                body: undefined,
26599                headers: {},
26600                statusCode: 0,
26601                method: method,
26602                url: uri,
26603                rawRequest: xhr
26604            }
26605
26606    function errorFunc(evt) {
26607        clearTimeout(timeoutTimer)
26608        if(!(evt instanceof Error)){
26609            evt = new Error("" + (evt || "Unknown XMLHttpRequest Error") )
26610        }
26611        evt.statusCode = 0
26612        return callback(evt, failureResponse)
26613    }
26614
26615    // will load the data & process the response in a special response object
26616    function loadFunc() {
26617        if (aborted) return
26618        var status
26619        clearTimeout(timeoutTimer)
26620        if(options.useXDR && xhr.status===undefined) {
26621            //IE8 CORS GET successful response doesn't have a status field, but body is fine
26622            status = 200
26623        } else {
26624            status = (xhr.status === 1223 ? 204 : xhr.status)
26625        }
26626        var response = failureResponse
26627        var err = null
26628
26629        if (status !== 0){
26630            response = {
26631                body: getBody(),
26632                statusCode: status,
26633                method: method,
26634                headers: {},
26635                url: uri,
26636                rawRequest: xhr
26637            }
26638            if(xhr.getAllResponseHeaders){ //remember xhr can in fact be XDR for CORS in IE
26639                response.headers = parseHeaders(xhr.getAllResponseHeaders())
26640            }
26641        } else {
26642            err = new Error("Internal XMLHttpRequest Error")
26643        }
26644        return callback(err, response, response.body)
26645    }
26646
26647    var xhr = options.xhr || null
26648
26649    if (!xhr) {
26650        if (options.cors || options.useXDR) {
26651            xhr = new createXHR.XDomainRequest()
26652        }else{
26653            xhr = new createXHR.XMLHttpRequest()
26654        }
26655    }
26656
26657    var key
26658    var aborted
26659    var uri = xhr.url = options.uri || options.url
26660    var method = xhr.method = options.method || "GET"
26661    var body = options.body || options.data || null
26662    var headers = xhr.headers = options.headers || {}
26663    var sync = !!options.sync
26664    var isJson = false
26665    var timeoutTimer
26666
26667    if ("json" in options) {
26668        isJson = true
26669        headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json") //Don't override existing accept header declared by user
26670        if (method !== "GET" && method !== "HEAD") {
26671            headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json") //Don't override existing accept header declared by user
26672            body = JSON.stringify(options.json)
26673        }
26674    }
26675
26676    xhr.onreadystatechange = readystatechange
26677    xhr.onload = loadFunc
26678    xhr.onerror = errorFunc
26679    // IE9 must have onprogress be set to a unique function.
26680    xhr.onprogress = function () {
26681        // IE must die
26682    }
26683    xhr.ontimeout = errorFunc
26684    xhr.open(method, uri, !sync, options.username, options.password)
26685    //has to be after open
26686    if(!sync) {
26687        xhr.withCredentials = !!options.withCredentials
26688    }
26689    // Cannot set timeout with sync request
26690    // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly
26691    // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent
26692    if (!sync && options.timeout > 0 ) {
26693        timeoutTimer = setTimeout(function(){
26694            aborted=true//IE9 may still call readystatechange
26695            xhr.abort("timeout")
26696            var e = new Error("XMLHttpRequest timeout")
26697            e.code = "ETIMEDOUT"
26698            errorFunc(e)
26699        }, options.timeout )
26700    }
26701
26702    if (xhr.setRequestHeader) {
26703        for(key in headers){
26704            if(headers.hasOwnProperty(key)){
26705                xhr.setRequestHeader(key, headers[key])
26706            }
26707        }
26708    } else if (options.headers && !isEmpty(options.headers)) {
26709        throw new Error("Headers cannot be set on an XDomainRequest object")
26710    }
26711
26712    if ("responseType" in options) {
26713        xhr.responseType = options.responseType
26714    }
26715
26716    if ("beforeSend" in options &&
26717        typeof options.beforeSend === "function"
26718    ) {
26719        options.beforeSend(xhr)
26720    }
26721
26722    xhr.send(body)
26723
26724    return xhr
26725
26726
26727}
26728
26729function getXml(xhr) {
26730    if (xhr.responseType === "document") {
26731        return xhr.responseXML
26732    }
26733    var firefoxBugTakenEffect = xhr.status === 204 && xhr.responseXML && xhr.responseXML.documentElement.nodeName === "parsererror"
26734    if (xhr.responseType === "" && !firefoxBugTakenEffect) {
26735        return xhr.responseXML
26736    }
26737
26738    return null
26739}
26740
26741function noop() {}
26742
26743}
26743,{"105":105,"108":108,"109":109,"95":95}],105:[function(_dereq_,module,exports){
26744module.exports = isFunction
26745
26746var toString = Object.prototype.toString
26747
26748function isFunction (fn) {
26749  var string = toString.call(fn)
26750  return string === '[object Function]' ||
26751    (typeof fn === 'function' && string !== '[object RegExp]') ||
26752    (typeof window !== 'undefined' &&
26753     // IE8 and below
26754     (fn === window.setTimeout ||
26755      fn === window.alert ||
26756      fn === window.confirm ||
26757      fn === window.prompt))
26758};
26759
26760},{}],106:[function(_dereq_,module,exports){
26761var isFunction = _dereq_(105)
26762
26763module.exports = forEach
26764
26765var toString = Object.prototype.toString
26766var hasOwnProperty = Object.prototype.hasOwnProperty
26767
26768function forEach(list, iterator, context) {
26769    if (!isFunction(iterator)) {
26770        throw new TypeError('iterator must be a function')
26771    }
26772
26773    if (arguments.length < 3) {
26774        context = this
26775    }
26776    
26777    if (toString.call(list) === '[object Array]')
26778        forEachArray(list, iterator, context)
26779    else if (typeof list === 'string')
26780        forEachString(list, iterator, context)
26781    else
26782        forEachObject(list, iterator, context)
26783}
26784
26785function forEachArray(array, iterator, context) {
26786    for (var i = 0, len = array.length; i < len; i++) {
26787        if (hasOwnProperty.call(array, i)) {
26788            iterator.call(context, array[i], i, array)
26789        }
26790    }
26791}
26792
26793function forEachString(string, iterator, context) {
26794    for (var i = 0, len = string.length; i < len; i++) {
26795        // no such thing as a sparse string.
26796        iterator.call(context, string.charAt(i), i, string)
26797    }
26798}
26799
26800function forEachObject(object, iterator, context) {
26801    for (var k in object) {
26802        if (hasOwnProperty.call(object, k)) {
26803            iterator.call(context, object[k], k, object)
26804        }
26805    }
26806}
26807
26808},{"105":105}],107:[function(_dereq_,module,exports){
26809
26810exports = module.exports = trim;
26811
26812function trim(str){
26813  return str.replace(/^\s*|\s*$/g, '');
26814}
26815
26816exports.left = function(str){
26817  return str.replace(/^\s*/, '');
26818};
26819
26820exports.right = function(str){
26821  return str.replace(/\s*$/, '');
26822};
26823
26824},{}],108:[function(_dereq_,module,exports){
26825var trim = _dereq_(107)
26826  , forEach = _dereq_(106)
26827  , isArray = function(arg) {
26828      return Object.prototype.toString.call(arg) === '[object Array]';
26829    }
26830
26831module.exports = function (headers) {
26832  if (!headers)
26833    return {}
26834
26835  var result = {}
26836
26837  forEach(
26838      trim(headers).split('\n')
26839    , function (row) {
26840        var index = row.indexOf(':')
26841          , key = trim(row.slice(0, index)).toLowerCase()
26842          , value = trim(row.slice(index + 1))
26843
26844        if (typeof(result[key]) === 'undefined') {
26845          result[key] = value
26846        } else if (isArray(result[key])) {
26847          result[key].push(value)
26848        } else {
26849          result[key] = [ result[key], value ]
26850        }
26851      }
26852  )
26853
26854  return result
26855}
26856},{"106":106,"107":107}],109:[function(_dereq_,module,exports){
26857module.exports = extend
26858
26859var hasOwnProperty = Object.prototype.hasOwnProperty;
26860
26861function extend() {
26862    var target = {}
26863
26864    for (var i = 0; i < arguments.length; i++) {
26865        var source = arguments[i]
26866
26867        for (var key in source) {
26868            if (hasOwnProperty.call(source, key)) {
26869                target[key] = source[key]
26870            }
26871        }
26872    }
26873
26874    return target
26875}
26876
26877},{}]},{},[93])(93)
26878});
26879/**
26880 * videojs-contrib-hls
26881 * @version 5.11.0
26882 * @copyright 2017
vendor: 12,171 bytes, lines 26882-27207
26882 Brightcove, Inc
26883 * @license Apache-2.0
26884 */
26885(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.videojsContribHls = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
26886/**
26887 * @file ad-cue-tags.js
26888 */
26889'use strict';
26890
26891Object.defineProperty(exports, '__esModule', {
26892  value: true
26893});
26894
26895var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
26896
26897function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
26898
26899var _globalWindow = require('global/window');
26900
26901var _globalWindow2 = _interopRequireDefault(_globalWindow);
26902
26903/**
26904 * Searches for an ad cue that overlaps with the given mediaTime
26905 */
26906var findAdCue = function findAdCue(track, mediaTime) {
26907  var cues = track.cues;
26908
26909  for (var i = 0; i < cues.length; i++) {
26910    var cue = cues[i];
26911
26912    if (mediaTime >= cue.adStartTime && mediaTime <= cue.adEndTime) {
26913      return cue;
26914    }
26915  }
26916  return null;
26917};
26918
26919var updateAdCues = function updateAdCues(media, track) {
26920  var offset = arguments.length <= 2 || arguments[2] === undefined ? 0 : arguments[2];
26921
26922  if (!media.segments) {
26923    return;
26924  }
26925
26926  var mediaTime = offset;
26927  var cue = undefined;
26928
26929  for (var i = 0; i < media.segments.length; i++) {
26930    var segment = media.segments[i];
26931
26932    if (!cue) {
26933      // Since the cues will span for at least the segment duration, adding a fudge
26934      // factor of half segment duration will prevent duplicate cues from being
26935      // created when timing info is not exact (e.g. cue start time initialized
26936      // at 10.006677, but next call mediaTime is 10.003332 )
26937      cue = findAdCue(track, mediaTime + segment.duration / 2);
26938    }
26939
26940    if (cue) {
26941      if ('cueIn' in segment) {
26942        // Found a CUE-IN so end the cue
26943        cue.endTime = mediaTime;
26944        cue.adEndTime = mediaTime;
26945        mediaTime += segment.duration;
26946        cue = null;
26947        continue;
26948      }
26949
26950      if (mediaTime < cue.endTime) {
26951        // Already processed this mediaTime for this cue
26952        mediaTime += segment.duration;
26953        continue;
26954      }
26955
26956      // otherwise extend cue until a CUE-IN is found
26957      cue.endTime += segment.duration;
26958    } else {
26959      if ('cueOut' in segment) {
26960        cue = new _globalWindow2['default'].VTTCue(mediaTime, mediaTime + segment.duration, segment.cueOut);
26961        cue.adStartTime = mediaTime;
26962        // Assumes tag format to be
26963        // #EXT-X-CUE-OUT:30
26964        cue.adEndTime = mediaTime + parseFloat(segment.cueOut);
26965        track.addCue(cue);
26966      }
26967
26968      if ('cueOutCont' in segment) {
26969        // Entered into the middle of an ad cue
26970        var adOffset = undefined;
26971        var adTotal = undefined;
26972
26973        // Assumes tag formate to be
26974        // #EXT-X-CUE-OUT-CONT:10/30
26975
26976        var _segment$cueOutCont$split$map = segment.cueOutCont.split('/').map(parseFloat);
26977
26978        var _segment$cueOutCont$split$map2 = _slicedToArray(_segment$cueOutCont$split$map, 2);
26979
26980        adOffset = _segment$cueOutCont$split$map2[0];
26981        adTotal = _segment$cueOutCont$split$map2[1];
26982
26983        cue = new _globalWindow2['default'].VTTCue(mediaTime, mediaTime + segment.duration, '');
26984        cue.adStartTime = mediaTime - adOffset;
26985        cue.adEndTime = cue.adStartTime + adTotal;
26986        track.addCue(cue);
26987      }
26988    }
26989    mediaTime += segment.duration;
26990  }
26991};
26992
26993exports['default'] = {
26994  updateAdCues: updateAdCues,
26995  findAdCue: findAdCue
26996};
26997module.exports = exports['default'];
26998},{"global/window":32}],2:[function(require,module,exports){
26999/**
27000 * @file bin-utils.js
27001 */
27002
27003/**
27004 * convert a TimeRange to text
27005 *
27006 * @param {TimeRange} range the timerange to use for conversion
27007 * @param {Number} i the iterator on the range to convert
27008 */
27009'use strict';
27010
27011Object.defineProperty(exports, '__esModule', {
27012  value: true
27013});
27014var textRange = function textRange(range, i) {
27015  return range.start(i) + '-' + range.end(i);
27016};
27017
27018/**
27019 * format a number as hex string
27020 *
27021 * @param {Number} e The number
27022 * @param {Number} i the iterator
27023 */
27024var formatHexString = function formatHexString(e, i) {
27025  var value = e.toString(16);
27026
27027  return '00'.substring(0, 2 - value.length) + value + (i % 2 ? ' ' : '');
27028};
27029var formatAsciiString = function formatAsciiString(e) {
27030  if (e >= 0x20 && e < 0x7e) {
27031    return String.fromCharCode(e);
27032  }
27033  return '.';
27034};
27035
27036/**
27037 * Creates an object for sending to a web worker modifying properties that are TypedArrays
27038 * into a new object with seperated properties for the buffer, byteOffset, and byteLength.
27039 *
27040 * @param {Object} message
27041 *        Object of properties and values to send to the web worker
27042 * @return {Object}
27043 *         Modified message with TypedArray values expanded
27044 * @function createTransferableMessage
27045 */
27046var createTransferableMessage = function createTransferableMessage(message) {
27047  var transferable = {};
27048
27049  Object.keys(message).forEach(function (key) {
27050    var value = message[key];
27051
27052    if (ArrayBuffer.isView(value)) {
27053      transferable[key] = {
27054        bytes: value.buffer,
27055        byteOffset: value.byteOffset,
27056        byteLength: value.byteLength
27057      };
27058    } else {
27059      transferable[key] = value;
27060    }
27061  });
27062
27063  return transferable;
27064};
27065
27066/**
27067 * Returns a unique string identifier for a media initialization
27068 * segment.
27069 */
27070var initSegmentId = function initSegmentId(initSegment) {
27071  var byterange = initSegment.byterange || {
27072    length: Infinity,
27073    offset: 0
27074  };
27075
27076  return [byterange.length, byterange.offset, initSegment.resolvedUri].join(',');
27077};
27078
27079/**
27080 * utils to help dump binary data to the console
27081 */
27082var utils = {
27083  hexDump: function hexDump(data) {
27084    var bytes = Array.prototype.slice.call(data);
27085    var step = 16;
27086    var result = '';
27087    var hex = undefined;
27088    var ascii = undefined;
27089
27090    for (var j = 0; j < bytes.length / step; j++) {
27091      hex = bytes.slice(j * step, j * step + step).map(formatHexString).join('');
27092      ascii = bytes.slice(j * step, j * step + step).map(formatAsciiString).join('');
27093      result += hex + ' ' + ascii + '\n';
27094    }
27095    return result;
27096  },
27097  tagDump: function tagDump(tag) {
27098    return utils.hexDump(tag.bytes);
27099  },
27100  textRanges: function textRanges(ranges) {
27101    var result = '';
27102    var i = undefined;
27103
27104    for (i = 0; i < ranges.length; i++) {
27105      result += textRange(ranges, i) + ' ';
27106    }
27107    return result;
27108  },
27109  createTransferableMessage: createTransferableMessage,
27110  initSegmentId: initSegmentId
27111};
27112
27113exports['default'] = utils;
27114module.exports = exports['default'];
27115},{}],3:[function(require,module,exports){
27116"use strict";
27117
27118Object.defineProperty(exports, "__esModule", {
27119  value: true
27120});
27121exports["default"] = {
27122  GOAL_BUFFER_LENGTH: 30,
27123  MAX_GOAL_BUFFER_LENGTH: 60,
27124  GOAL_BUFFER_LENGTH_RATE: 1,
27125  // A fudge factor to apply to advertised playlist bitrates to account for
27126  // temporary flucations in client bandwidth
27127  BANDWIDTH_VARIANCE: 1.2,
27128  // How much of the buffer must be filled before we consider upswitching
27129  BUFFER_LOW_WATER_LINE: 0,
27130  MAX_BUFFER_LOW_WATER_LINE: 30,
27131  BUFFER_LOW_WATER_LINE_RATE: 1
27132};
27133module.exports = exports["default"];
27134},{}],4:[function(require,module,exports){
27135'use strict';
27136
27137Object.defineProperty(exports, '__esModule', {
27138  value: true
27139});
27140
27141function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
27142
27143var _globalWindow = require('global/window');
27144
27145var _globalWindow2 = _interopRequireDefault(_globalWindow);
27146
27147var _aesDecrypter = require('aes-decrypter');
27148
27149var _binUtils = require('./bin-utils');
27150
27151/**
27152 * Our web worker interface so that things can talk to aes-decrypter
27153 * that will be running in a web worker. the scope is passed to this by
27154 * webworkify.
27155 *
27156 * @param {Object} self
27157 *        the scope for the web worker
27158 */
27159var DecrypterWorker = function DecrypterWorker(self) {
27160  self.onmessage = function (event) {
27161    var data = event.data;
27162    var encrypted = new Uint8Array(data.encrypted.bytes, data.encrypted.byteOffset, data.encrypted.byteLength);
27163    var key = new Uint32Array(data.key.bytes, data.key.byteOffset, data.key.byteLength / 4);
27164    var iv = new Uint32Array(data.iv.bytes, data.iv.byteOffset, data.iv.byteLength / 4);
27165
27166    /* eslint-disable no-new, handle-callback-err */
27167    new _aesDecrypter.Decrypter(encrypted, key, iv, function (err, bytes) {
27168      _globalWindow2['default'].postMessage((0, _binUtils.createTransferableMessage)({
27169        source: data.source,
27170        decrypted: bytes
27171      }), [bytes.buffer]);
27172    });
27173    /* eslint-enable */
27174  };
27175};
27176
27177exports['default'] = function (self) {
27178  return new DecrypterWorker(self);
27179};
27180
27181module.exports = exports['default'];
27182},{"./bin-utils":2,"aes-decrypter":25,"global/window":32}],5:[function(require,module,exports){
27183(function (global){
27184/**
27185 * @file master-playlist-controller.js
27186 */
27187'use strict';
27188
27189Object.defineProperty(exports, '__esModule', {
27190  value: true
27191});
27192
27193var _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; }; })();
27194
27195var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
27196
27197function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
27198
27199function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
27200
27201function _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; }
27202
27203var _playlistLoader = require('./playlist-loader');
27204
27205var _playlistLoader2 = _interopRequireDefault(_playlistLoader);
27206
27207var _
vendor: 4,172 bytes, lines 27207-27333
27207segmentLoader = require('./segment-loader');
27208
27209var _segmentLoader2 = _interopRequireDefault(_segmentLoader);
27210
27211var _vttSegmentLoader = require('./vtt-segment-loader');
27212
27213var _vttSegmentLoader2 = _interopRequireDefault(_vttSegmentLoader);
27214
27215var _ranges = require('./ranges');
27216
27217var _ranges2 = _interopRequireDefault(_ranges);
27218
27219var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
27220
27221var _videoJs2 = _interopRequireDefault(_videoJs);
27222
27223var _adCueTags = require('./ad-cue-tags');
27224
27225var _adCueTags2 = _interopRequireDefault(_adCueTags);
27226
27227var _syncController = require('./sync-controller');
27228
27229var _syncController2 = _interopRequireDefault(_syncController);
27230
27231var _videojsContribMediaSourcesEs5CodecUtils = require('videojs-contrib-media-sources/es5/codec-utils');
27232
27233var _webworkify = require('webworkify');
27234
27235var _webworkify2 = _interopRequireDefault(_webworkify);
27236
27237var _decrypterWorker = require('./decrypter-worker');
27238
27239var _decrypterWorker2 = _interopRequireDefault(_decrypterWorker);
27240
27241var _config = require('./config');
27242
27243var _config2 = _interopRequireDefault(_config);
27244
27245var _utilCodecsJs = require('./util/codecs.js');
27246
27247var _mediaGroups = require('./media-groups');
27248
27249var ABORT_EARLY_BLACKLIST_SECONDS = 60 * 2;
27250
27251var Hls = undefined;
27252
27253// Default codec parameters if none were provided for video and/or audio
27254var defaultCodecs = {
27255  videoCodec: 'avc1',
27256  videoObjectTypeIndicator: '.4d400d',
27257  // AAC-LC
27258  audioProfile: '2'
27259};
27260
27261// SegmentLoader stats that need to have each loader's
27262// values summed to calculate the final value
27263var loaderStats = ['mediaRequests', 'mediaRequestsAborted', 'mediaRequestsTimedout', 'mediaRequestsErrored', 'mediaTransferDuration', 'mediaBytesTransferred'];
27264var sumLoaderStat = function sumLoaderStat(stat) {
27265  return this.audioSegmentLoader_[stat] + this.mainSegmentLoader_[stat];
27266};
27267
27268/**
27269 * Replace codecs in the codec string with the old apple-style `avc1.<dd>.<dd>` to the
27270 * standard `avc1.<hhhhhh>`.
27271 *
27272 * @param codecString {String} the codec string
27273 * @return {String} the codec string with old apple-style codecs replaced
27274 *
27275 * @private
27276 */
27277var mapLegacyAvcCodecs_ = function mapLegacyAvcCodecs_(codecString) {
27278  return codecString.replace(/avc1\.(\d+)\.(\d+)/i, function (match) {
27279    return (0, _videojsContribMediaSourcesEs5CodecUtils.translateLegacyCodecs)([match])[0];
27280  });
27281};
27282
27283exports.mapLegacyAvcCodecs_ = mapLegacyAvcCodecs_;
27284/**
27285 * Build a media mime-type string from a set of parameters
27286 * @param {String} type either 'audio' or 'video'
27287 * @param {String} container either 'mp2t' or 'mp4'
27288 * @param {Array} codecs an array of codec strings to add
27289 * @return {String} a valid media mime-type
27290 */
27291var makeMimeTypeString = function makeMimeTypeString(type, container, codecs) {
27292  // The codecs array is filtered so that falsey values are
27293  // dropped and don't cause Array#join to create spurious
27294  // commas
27295  return type + '/' + container + '; codecs="' + codecs.filter(function (c) {
27296    return !!c;
27297  }).join(', ') + '"';
27298};
27299
27300/**
27301 * Returns the type container based on information in the playlist
27302 * @param {Playlist} media the current media playlist
27303 * @return {String} a valid media container type
27304 */
27305var getContainerType = function getContainerType(media) {
27306  // An initialization segment means the media playlist is an iframe
27307  // playlist or is using the mp4 container. We don't currently
27308  // support iframe playlists, so assume this is signalling mp4
27309  // fragments.
27310  if (media.segments && media.segments.length && media.segments[0].map) {
27311    return 'mp4';
27312  }
27313  return 'mp2t';
27314};
27315
27316/**
27317 * Returns a set of codec strings parsed from the playlist or the default
27318 * codec strings if no codecs were specified in the playlist
27319 * @param {Playlist} media the current media playlist
27320 * @return {Object} an object with the video and audio codecs
27321 */
27322var getCodecs = function getCodecs(media) {
27323  // if the codecs were explicitly specified, use them instead of the
27324  // defaults
27325  var mediaAttributes = media.attributes || {};
27326
27327  if (mediaAttributes.CODECS) {
27328    return (0, _utilCodecsJs.parseCodecs)(mediaAttributes.CODECS);
27329  }
27330  return defaultCodecs;
27331};
27332
27333/**
27334 * Calculates the MIME type strings for a working configuration of
27335 * SourceBuffers to play variant streams in a master playlist. If
27336 * there is no possible working configuration, an empty array will be
27337 * returned.
27338 *
27339 * @param master {Object} the m3u8 object for the master playlist
27340 * @param media {Object} the m3u8 object for the variant playlist
27341 * @return {Array} the MIME type strings. If the array has more than
27342 * one entry, the first element should be applied to the video
27343 * SourceBuffer and the second to the audio SourceBuffer.
27344 *
27345 * @private
27346 */
27347var mimeTypesForPlaylist_ = function mimeTypesForPlaylist_(master, media) {
27348  var containerType = getContainerType(media);
27349  var codecInfo = getCodecs(media);
27350  var mediaAttributes = media.attributes || {};
27351  // Default condition for a traditional HLS (no demuxed audio/video)
27352  var isMuxed = true;
27353  var isMaat = false;
27354
27355  if (!media) {
27356    // Not enough information
27357    return [];
27358  }
27359
27360  if (master.mediaGroups.AUDIO && mediaAttributes.AUDIO) {
27361    var audioGroup = master.mediaGroups.AUDIO[mediaAttributes.AUDIO];
27362
27363    // Handle the case where we are in a multiple-audio track scenario
27364    if (audioGroup) {
27365      isMaat = true;
27366      // Start with the everything demuxed then...
27367      isMuxed = false;
27368      // ...check to see if any audio group tracks are muxed (ie. lacking a uri)
27369      for (var groupId in audioGroup) {
27370        if (!audioGroup[groupId].uri) {
27371          isMuxed = true;
27372          break;
27373        }
27374      }
27375    }
27376  }
27377
27378  // HLS with multiple-audio tracks must always get an audio codec.
27379  // Put another way, there is no way to have a video-only multiple-audio HLS!
27380  if (isMaat && !codecInfo.audioProfile) {
27381    _videoJs2['default'].log.warn('Multiple audio tracks present but no audio codec string is specified. ' + 'Attempting to use the default audio codec (mp4a.40.2)');
27382    codecInfo.audioProfile = defaultCodecs.audioProfile;
27383  }
27384
27385  // Generate the final codec strings from the codec object generated above
27386  var codecStrings = {};
27387
27388  if (codecInfo.videoCodec) {
27389    codecStrings.video = '' + codecInfo.videoCodec + codecInfo.videoObjectTypeIndicator;
27390  }
27391
27392  if (codecInfo.audioProfile) {
27393    codecStrings.audio = 'mp4a.40.' + codecInfo.audioProfile;
27394  }
27395
27396  // Finally, make and return an array with proper mime-types depending on
27397  // the configuration
27398  var justAudio = makeMimeTypeString('audio', containerType, [codecStrings.audio]);
27399  var justVideo = makeMimeTypeString('video', containerType, [codecStrings.video]);
27400  var bothVideoAudio = makeMimeTypeString('video', containerType, [codecStrings.video, codecStrings.audio]);
27401
27402  if (isMaat) {
27403    if (!isMuxed && codecStrings.video) {
27404      return [justVideo, justAudio];
27405    }
27406    // There exists the possiblity that this will return a `video/container`
27407    // mime-type for the first entry in the array even when there is only audio.
27408    // This doesn't appear to be a problem and simplifies the code.
27409    return [bothVideoAudio, justAudio];
27410  }
27411
27412  // If there is ano video codec at all, always just return a single
27413  // audio/<container> mime-type
27414  if (!codecStrings.video) {
27415    return [justAudio];
27416  }
27417
27418  // When not using separate audio media groups, audio and video is
27419  // *always* muxed
27420  return [bothVideoAudio];
27421};
27422
27423exports.mimeTypesForPlaylist_ = mimeTypesForPlaylist_;
27424/**
27425 * the master playlist controller controller all interactons
27426 * between playlists and segmentloaders. At this time this mainly
27427 * involves a master playlist and a series of audio playlists
27428 * if they are available
27429 *
27430 * @class MasterPlaylistController
27431 * @extends videojs.EventTarget
27432 */
27433
27434var MasterPlaylistController = (function (_videojs$EventTarget) {
27435  _inherits(MasterPlaylistController, _videojs$EventTarget);
27436
27437  function MasterPlaylistController(options) {
27438    var _this = this;
27439
27440    _classCallCheck(this, MasterPlaylistController);
27441
27442    _get(Object.getPrototypeOf(MasterPlaylistController.prototype), 'constructor', this).call(this);
27443
27444    var url = options.url;
27445    var withCredentials = options.withCredentials;
27446    var mode = options.mode;
27447    var tech = options.tech;
27448    var bandwidth = options.bandwidth;
27449    var externHls = options.externHls;
27450    var useCueTags = options.useCueTags;
vendor: 28,994 bytes, lines 27451-28312
27451    var blacklistDuration = options.blacklistDuration;
27452    var enableLowInitialPlaylist = options.enableLowInitialPlaylist;
27453
27454    if (!url) {
27455      throw new Error('A non-empty playlist URL is required');
27456    }
27457
27458    Hls = externHls;
27459
27460    this.withCredentials = withCredentials;
27461    this.tech_ = tech;
27462    this.hls_ = tech.hls;
27463    this.mode_ = mode;
27464    this.useCueTags_ = useCueTags;
27465    this.blacklistDuration = blacklistDuration;
27466    this.enableLowInitialPlaylist = enableLowInitialPlaylist;
27467    if (this.useCueTags_) {
27468      this.cueTagsTrack_ = this.tech_.addTextTrack('metadata', 'ad-cues');
27469      this.cueTagsTrack_.inBandMetadataTrackDispatchType = '';
27470    }
27471
27472    this.requestOptions_ = {
27473      withCredentials: this.withCredentials,
27474      timeout: null
27475    };
27476
27477    this.mediaTypes_ = (0, _mediaGroups.createMediaTypes)();
27478
27479    this.mediaSource = new _videoJs2['default'].MediaSource({ mode: mode });
27480
27481    // load the media source into the player
27482    this.mediaSource.addEventListener('sourceopen', this.handleSourceOpen_.bind(this));
27483
27484    this.seekable_ = _videoJs2['default'].createTimeRanges();
27485    this.hasPlayed_ = function () {
27486      return false;
27487    };
27488
27489    this.syncController_ = new _syncController2['default'](options);
27490    this.segmentMetadataTrack_ = tech.addRemoteTextTrack({
27491      kind: 'metadata',
27492      label: 'segment-metadata'
27493    }, false).track;
27494
27495    this.decrypter_ = (0, _webworkify2['default'])(_decrypterWorker2['default']);
27496
27497    var segmentLoaderSettings = {
27498      hls: this.hls_,
27499      mediaSource: this.mediaSource,
27500      currentTime: this.tech_.currentTime.bind(this.tech_),
27501      seekable: function seekable() {
27502        return _this.seekable();
27503      },
27504      seeking: function seeking() {
27505        return _this.tech_.seeking();
27506      },
27507      duration: function duration() {
27508        return _this.mediaSource.duration;
27509      },
27510      hasPlayed: function hasPlayed() {
27511        return _this.hasPlayed_();
27512      },
27513      goalBufferLength: function goalBufferLength() {
27514        return _this.goalBufferLength();
27515      },
27516      bandwidth: bandwidth,
27517      syncController: this.syncController_,
27518      decrypter: this.decrypter_
27519    };
27520
27521    // setup playlist loaders
27522    this.masterPlaylistLoader_ = new _playlistLoader2['default'](url, this.hls_, this.withCredentials);
27523    this.setupMasterPlaylistLoaderListeners_();
27524
27525    // setup segment loaders
27526    // combined audio/video or just video when alternate audio track is selected
27527    this.mainSegmentLoader_ = new _segmentLoader2['default'](_videoJs2['default'].mergeOptions(segmentLoaderSettings, {
27528      segmentMetadataTrack: this.segmentMetadataTrack_,
27529      loaderType: 'main'
27530    }), options);
27531
27532    // alternate audio track
27533    this.audioSegmentLoader_ = new _segmentLoader2['default'](_videoJs2['default'].mergeOptions(segmentLoaderSettings, {
27534      loaderType: 'audio'
27535    }), options);
27536
27537    this.subtitleSegmentLoader_ = new _vttSegmentLoader2['default'](_videoJs2['default'].mergeOptions(segmentLoaderSettings, {
27538      loaderType: 'vtt'
27539    }), options);
27540
27541    this.setupSegmentLoaderListeners_();
27542
27543    // Create SegmentLoader stat-getters
27544    loaderStats.forEach(function (stat) {
27545      _this[stat + '_'] = sumLoaderStat.bind(_this, stat);
27546    });
27547
27548    this.masterPlaylistLoader_.load();
27549  }
27550
27551  /**
27552   * Register event handlers on the master playlist loader. A helper
27553   * function for construction time.
27554   *
27555   * @private
27556   */
27557
27558  _createClass(MasterPlaylistController, [{
27559    key: 'setupMasterPlaylistLoaderListeners_',
27560    value: function setupMasterPlaylistLoaderListeners_() {
27561      var _this2 = this;
27562
27563      this.masterPlaylistLoader_.on('loadedmetadata', function () {
27564        var media = _this2.masterPlaylistLoader_.media();
27565        var requestTimeout = _this2.masterPlaylistLoader_.targetDuration * 1.5 * 1000;
27566
27567        // If we don't have any more available playlists, we don't want to
27568        // timeout the request.
27569        if (_this2.masterPlaylistLoader_.isLowestEnabledRendition_()) {
27570          _this2.requestOptions_.timeout = 0;
27571        } else {
27572          _this2.requestOptions_.timeout = requestTimeout;
27573        }
27574
27575        // if this isn't a live video and preload permits, start
27576        // downloading segments
27577        if (media.endList && _this2.tech_.preload() !== 'none') {
27578          _this2.mainSegmentLoader_.playlist(media, _this2.requestOptions_);
27579          _this2.mainSegmentLoader_.load();
27580        }
27581
27582        (0, _mediaGroups.setupMediaGroups)({
27583          segmentLoaders: {
27584            AUDIO: _this2.audioSegmentLoader_,
27585            SUBTITLES: _this2.subtitleSegmentLoader_,
27586            main: _this2.mainSegmentLoader_
27587          },
27588          tech: _this2.tech_,
27589          requestOptions: _this2.requestOptions_,
27590          masterPlaylistLoader: _this2.masterPlaylistLoader_,
27591          mode: _this2.mode_,
27592          hls: _this2.hls_,
27593          master: _this2.master(),
27594          mediaTypes: _this2.mediaTypes_,
27595          blacklistCurrentPlaylist: _this2.blacklistCurrentPlaylist.bind(_this2)
27596        });
27597
27598        _this2.triggerPresenceUsage_(_this2.master(), media);
27599
27600        try {
27601          _this2.setupSourceBuffers_();
27602        } catch (e) {
27603          _videoJs2['default'].log.warn('Failed to create SourceBuffers', e);
27604          return _this2.mediaSource.endOfStream('decode');
27605        }
27606        _this2.setupFirstPlay();
27607
27608        _this2.trigger('selectedinitialmedia');
27609      });
27610
27611      this.masterPlaylistLoader_.on('loadedplaylist', function () {
27612        var updatedPlaylist = _this2.masterPlaylistLoader_.media();
27613
27614        if (!updatedPlaylist) {
27615          var selectedMedia = undefined;
27616
27617          if (_this2.enableLowInitialPlaylist) {
27618            selectedMedia = _this2.selectInitialPlaylist();
27619          }
27620
27621          if (!selectedMedia) {
27622            selectedMedia = _this2.selectPlaylist();
27623          }
27624
27625          _this2.initialMedia_ = selectedMedia;
27626          _this2.masterPlaylistLoader_.media(_this2.initialMedia_);
27627          return;
27628        }
27629
27630        if (_this2.useCueTags_) {
27631          _this2.updateAdCues_(updatedPlaylist);
27632        }
27633
27634        // TODO: Create a new event on the PlaylistLoader that signals
27635        // that the segments have changed in some way and use that to
27636        // update the SegmentLoader instead of doing it twice here and
27637        // on `mediachange`
27638        _this2.mainSegmentLoader_.playlist(updatedPlaylist, _this2.requestOptions_);
27639        _this2.updateDuration();
27640
27641        // If the player isn't paused, ensure that the segment loader is running,
27642        // as it is possible that it was temporarily stopped while waiting for
27643        // a playlist (e.g., in case the playlist errored and we re-requested it).
27644        if (!_this2.tech_.paused()) {
27645          _this2.mainSegmentLoader_.load();
27646        }
27647
27648        if (!updatedPlaylist.endList) {
27649          (function () {
27650            var addSeekableRange = function addSeekableRange() {
27651              var seekable = _this2.seekable();
27652
27653              if (seekable.length !== 0) {
27654                _this2.mediaSource.addSeekableRange_(seekable.start(0), seekable.end(0));
27655              }
27656            };
27657
27658            if (_this2.duration() !== Infinity) {
27659              (function () {
27660                var onDurationchange = function onDurationchange() {
27661                  if (_this2.duration() === Infinity) {
27662                    addSeekableRange();
27663                  } else {
27664                    _this2.tech_.one('durationchange', onDurationchange);
27665                  }
27666                };
27667
27668                _this2.tech_.one('durationchange', onDurationchange);
27669              })();
27670            } else {
27671              addSeekableRange();
27672            }
27673          })();
27674        }
27675      });
27676
27677      this.masterPlaylistLoader_.on('error', function () {
27678        _this2.blacklistCurrentPlaylist(_this2.masterPlaylistLoader_.error);
27679      });
27680
27681      this.masterPlaylistLoader_.on('mediachanging', function () {
27682        _this2.mainSegmentLoader_.abort();
27683        _this2.mainSegmentLoader_.pause();
27684      });
27685
27686      this.masterPlaylistLoader_.on('mediachange', function () {
27687        var media = _this2.masterPlaylistLoader_.media();
27688        var requestTimeout = _this2.masterPlaylistLoader_.targetDuration * 1.5 * 1000;
27689
27690        // If we don't have any more available playlists, we don't want to
27691        // timeout the request.
27692        if (_this2.masterPlaylistLoader_.isLowestEnabledRendition_()) {
27693          _this2.requestOptions_.timeout = 0;
27694        } else {
27695          _this2.requestOptions_.timeout = requestTimeout;
27696        }
27697
27698        // TODO: Create a new event on the PlaylistLoader that signals
27699        // that the segments have changed in some way and use that to
27700        // update the SegmentLoader instead of doing it twice here and
27701        // on `loadedplaylist`
27702        _this2.mainSegmentLoader_.playlist(media, _this2.requestOptions_);
27703        _this2.mainSegmentLoader_.load();
27704
27705        _this2.tech_.trigger({
27706          type: 'mediachange',
27707          bubbles: true
27708        });
27709      });
27710
27711      this.masterPlaylistLoader_.on('playlistunchanged', function () {
27712        var updatedPlaylist = _this2.masterPlaylistLoader_.media();
27713        var playlistOutdated = _this2.stuckAtPlaylistEnd_(updatedPlaylist);
27714
27715        if (playlistOutdated) {
27716          // Playlist has stopped updating and we're stuck at its end. Try to
27717          // blacklist it and switch to another playlist in the hope that that
27718          // one is updating (and give the player a chance to re-adjust to the
27719          // safe live point).
27720          _this2.blacklistCurrentPlaylist({
27721            message: 'Playlist no longer updating.'
27722          });
27723          // useful for monitoring QoS
27724          _this2.tech_.trigger('playliststuck');
27725        }
27726      });
27727
27728      this.masterPlaylistLoader_.on('renditiondisabled', function () {
27729        _this2.tech_.trigger({ type: 'usage', name: 'hls-rendition-disabled' });
27730      });
27731      this.masterPlaylistLoader_.on('renditionenabled', function () {
27732        _this2.tech_.trigger({ type: 'usage', name: 'hls-rendition-enabled' });
27733      });
27734    }
27735
27736    /**
27737     * A helper function for triggerring presence usage events once per source
27738     *
27739     * @private
27740     */
27741  }, {
27742    key: 'triggerPresenceUsage_',
27743    value: function triggerPresenceUsage_(master, media) {
27744      var mediaGroups = master.mediaGroups || {};
27745      var defaultDemuxed = true;
27746      var audioGroupKeys = Object.keys(mediaGroups.AUDIO);
27747
27748      for (var mediaGroup in mediaGroups.AUDIO) {
27749        for (var label in mediaGroups.AUDIO[mediaGroup]) {
27750          var properties = mediaGroups.AUDIO[mediaGroup][label];
27751
27752          if (!properties.uri) {
27753            defaultDemuxed = false;
27754          }
27755        }
27756      }
27757
27758      if (defaultDemuxed) {
27759        this.tech_.trigger({ type: 'usage', name: 'hls-demuxed' });
27760      }
27761
27762      if (Object.keys(mediaGroups.SUBTITLES).length) {
27763        this.tech_.trigger({ type: 'usage', name: 'hls-webvtt' });
27764      }
27765
27766      if (Hls.Playlist.isAes(media)) {
27767        this.tech_.trigger({ type: 'usage', name: 'hls-aes' });
27768      }
27769
27770      if (Hls.Playlist.isFmp4(media)) {
27771        this.tech_.trigger({ type: 'usage', name: 'hls-fmp4' });
27772      }
27773
27774      if (audioGroupKeys.length && Object.keys(mediaGroups.AUDIO[audioGroupKeys[0]]).length > 1) {
27775        this.tech_.trigger({ type: 'usage', name: 'hls-alternate-audio' });
27776      }
27777
27778      if (this.useCueTags_) {
27779        this.tech_.trigger({ type: 'usage', name: 'hls-playlist-cue-tags' });
27780      }
27781    }
27782
27783    /**
27784     * Register event handlers on the segment loaders. A helper function
27785     * for construction time.
27786     *
27787     * @private
27788     */
27789  }, {
27790    key: 'setupSegmentLoaderListeners_',
27791    value: function setupSegmentLoaderListeners_() {
27792      var _this3 = this;
27793
27794      this.mainSegmentLoader_.on('bandwidthupdate', function () {
27795        var nextPlaylist = _this3.selectPlaylist();
27796        var currentPlaylist = _this3.masterPlaylistLoader_.media();
27797        var buffered = _this3.tech_.buffered();
27798        var forwardBuffer = buffered.length ? buffered.end(buffered.length - 1) - _this3.tech_.currentTime() : 0;
27799
27800        var bufferLowWaterLine = _this3.bufferLowWaterLine();
27801
27802        // If the playlist is live, then we want to not take low water line into account.
27803        // This is because in LIVE, the player plays 3 segments from the end of the
27804        // playlist, and if `BUFFER_LOW_WATER_LINE` is greater than the duration availble
27805        // in those segments, a viewer will never experience a rendition upswitch.
27806        if (!currentPlaylist.endList ||
27807        // For the same reason as LIVE, we ignore the low water line when the VOD
27808        // duration is below the max potential low water line
27809        _this3.duration() < _config2['default'].MAX_BUFFER_LOW_WATER_LINE ||
27810        // we want to switch down to lower resolutions quickly to continue playback, but
27811        nextPlaylist.attributes.BANDWIDTH < currentPlaylist.attributes.BANDWIDTH ||
27812        // ensure we have some buffer before we switch up to prevent us running out of
27813        // buffer while loading a higher rendition.
27814        forwardBuffer >= bufferLowWaterLine) {
27815          _this3.masterPlaylistLoader_.media(nextPlaylist);
27816        }
27817
27818        _this3.tech_.trigger('bandwidthupdate');
27819      });
27820      this.mainSegmentLoader_.on('progress', function () {
27821        _this3.trigger('progress');
27822      });
27823
27824      this.mainSegmentLoader_.on('error', function () {
27825        _this3.blacklistCurrentPlaylist(_this3.mainSegmentLoader_.error());
27826      });
27827
27828      this.mainSegmentLoader_.on('syncinfoupdate', function () {
27829        _this3.onSyncInfoUpdate_();
27830      });
27831
27832      this.mainSegmentLoader_.on('timestampoffset', function () {
27833        _this3.tech_.trigger({ type: 'usage', name: 'hls-timestamp-offset' });
27834      });
27835      this.audioSegmentLoader_.on('syncinfoupdate', function () {
27836        _this3.onSyncInfoUpdate_();
27837      });
27838
27839      this.mainSegmentLoader_.on('ended', function () {
27840        _this3.onEndOfStream();
27841      });
27842
27843      this.mainSegmentLoader_.on('earlyabort', function () {
27844        _this3.blacklistCurrentPlaylist({
27845          message: 'Aborted early because there isn\'t enough bandwidth to complete the ' + 'request without rebuffering.'
27846        }, ABORT_EARLY_BLACKLIST_SECONDS);
27847      });
27848
27849      this.mainSegmentLoader_.on('reseteverything', function () {
27850        _this3.tech_.trigger('hls-reset');
27851      });
27852
27853      this.audioSegmentLoader_.on('ended', function () {
27854        _this3.onEndOfStream();
27855      });
27856    }
27857  }, {
27858    key: 'mediaSecondsLoaded_',
27859    value: function mediaSecondsLoaded_() {
27860      return Math.max(this.audioSegmentLoader_.mediaSecondsLoaded + this.mainSegmentLoader_.mediaSecondsLoaded);
27861    }
27862
27863    /**
27864     * Call load on our SegmentLoaders
27865     */
27866  }, {
27867    key: 'load',
27868    value: function load() {
27869      this.mainSegmentLoader_.load();
27870      if (this.mediaTypes_.AUDIO.activePlaylistLoader) {
27871        this.audioSegmentLoader_.load();
27872      }
27873      if (this.mediaTypes_.SUBTITLES.activePlaylistLoader) {
27874        this.subtitleSegmentLoader_.load();
27875      }
27876    }
27877
27878    /**
27879     * Re-tune playback quality level for the current player
27880     * conditions. This method may perform destructive actions, like
27881     * removing already buffered content, to readjust the currently
27882     * active playlist quickly.
27883     *
27884     * @private
27885     */
27886  }, {
27887    key: 'fastQualityChange_',
27888    value: function fastQualityChange_() {
27889      var media = this.selectPlaylist();
27890
27891      if (media !== this.masterPlaylistLoader_.media()) {
27892        this.masterPlaylistLoader_.media(media);
27893
27894        this.mainSegmentLoader_.resetLoader();
27895        // don't need to reset audio as it is reset when media changes
27896      }
27897    }
27898
27899    /**
27900     * Begin playback.
27901     */
27902  }, {
27903    key: 'play',
27904    value: function play() {
27905      if (this.setupFirstPlay()) {
27906        return;
27907      }
27908
27909      if (this.tech_.ended()) {
27910        this.tech_.setCurrentTime(0);
27911      }
27912
27913      if (this.hasPlayed_()) {
27914        this.load();
27915      }
27916
27917      var seekable = this.tech_.seekable();
27918
27919      // if the viewer has paused and we fell out of the live window,
27920      // seek forward to the live point
27921      if (this.tech_.duration() === Infinity) {
27922        if (this.tech_.currentTime() < seekable.start(0)) {
27923          return this.tech_.setCurrentTime(seekable.end(seekable.length - 1));
27924        }
27925      }
27926    }
27927
27928    /**
27929     * Seek to the latest media position if this is a live video and the
27930     * player and video are loaded and initialized.
27931     */
27932  }, {
27933    key: 'setupFirstPlay',
27934    value: function setupFirstPlay() {
27935      var seekable = undefined;
27936      var media = this.masterPlaylistLoader_.media();
27937
27938      // check that everything is ready to begin buffering in the live
27939      // scenario
27940      // 1) the active media playlist is available
27941      if (media &&
27942      // 2) the player is not paused
27943      !this.tech_.paused() &&
27944      // 3) the player has not started playing
27945      !this.hasPlayed_()) {
27946
27947        // when the video is a live stream
27948        if (!media.endList) {
27949          this.trigger('firstplay');
27950
27951          // seek to the latest media position for live videos
27952          seekable = this.seekable();
27953          if (seekable.length) {
27954            this.tech_.setCurrentTime(seekable.end(0));
27955          }
27956        }
27957        this.hasPlayed_ = function () {
27958          return true;
27959        };
27960        // now that we are ready, load the segment
27961        this.load();
27962        return true;
27963      }
27964      return false;
27965    }
27966
27967    /**
27968     * handle the sourceopen event on the MediaSource
27969     *
27970     * @private
27971     */
27972  }, {
27973    key: 'handleSourceOpen_',
27974    value: function handleSourceOpen_() {
27975      // Only attempt to create the source buffer if none already exist.
27976      // handleSourceOpen is also called when we are "re-opening" a source buffer
27977      // after `endOfStream` has been called (in response to a seek for instance)
27978      try {
27979        this.setupSourceBuffers_();
27980      } catch (e) {
27981        _videoJs2['default'].log.warn('Failed to create Source Buffers', e);
27982        return this.mediaSource.endOfStream('decode');
27983      }
27984
27985      // if autoplay is enabled, begin playback. This is duplicative of
27986      // code in video.js but is required because play() must be invoked
27987      // *after* the media source has opened.
27988      if (this.tech_.autoplay()) {
27989        this.tech_.play();
27990      }
27991
27992      this.trigger('sourceopen');
27993    }
27994
27995    /**
27996     * Calls endOfStream on the media source when all active stream types have called
27997     * endOfStream
27998     *
27999     * @param {string} streamType
28000     *        Stream type of the segment loader that called endOfStream
28001     * @private
28002     */
28003  }, {
28004    key: 'onEndOfStream',
28005    value: function onEndOfStream() {
28006      var isEndOfStream = this.mainSegmentLoader_.ended_;
28007
28008      if (this.mediaTypes_.AUDIO.activePlaylistLoader) {
28009        // if the audio playlist loader exists, then alternate audio is active, so we need
28010        // to wait for both the main and audio segment loaders to call endOfStream
28011        isEndOfStream = isEndOfStream && this.audioSegmentLoader_.ended_;
28012      }
28013
28014      if (isEndOfStream) {
28015        this.mediaSource.endOfStream();
28016      }
28017    }
28018
28019    /**
28020     * Check if a playlist has stopped being updated
28021     * @param {Object} playlist the media playlist object
28022     * @return {boolean} whether the playlist has stopped being updated or not
28023     */
28024  }, {
28025    key: 'stuckAtPlaylistEnd_',
28026    value: function stuckAtPlaylistEnd_(playlist) {
28027      var seekable = this.seekable();
28028
28029      if (!seekable.length) {
28030        // playlist doesn't have enough information to determine whether we are stuck
28031        return false;
28032      }
28033
28034      var expired = this.syncController_.getExpiredTime(playlist, this.mediaSource.duration);
28035
28036      if (expired === null) {
28037        return false;
28038      }
28039
28040      // does not use the safe live end to calculate playlist end, since we
28041      // don't want to say we are stuck while there is still content
28042      var absolutePlaylistEnd = Hls.Playlist.playlistEnd(playlist, expired);
28043      var currentTime = this.tech_.currentTime();
28044      var buffered = this.tech_.buffered();
28045
28046      if (!buffered.length) {
28047        // return true if the playhead reached the absolute end of the playlist
28048        return absolutePlaylistEnd - currentTime <= _ranges2['default'].TIME_FUDGE_FACTOR;
28049      }
28050      var bufferedEnd = buffered.end(buffered.length - 1);
28051
28052      // return true if there is too little buffer left and
28053      // buffer has reached absolute end of playlist
28054      return bufferedEnd - currentTime <= _ranges2['default'].TIME_FUDGE_FACTOR && absolutePlaylistEnd - bufferedEnd <= _ranges2['default'].TIME_FUDGE_FACTOR;
28055    }
28056
28057    /**
28058     * Blacklists a playlist when an error occurs for a set amount of time
28059     * making it unavailable for selection by the rendition selection algorithm
28060     * and then forces a new playlist (rendition) selection.
28061     *
28062     * @param {Object=} error an optional error that may include the playlist
28063     * to blacklist
28064     * @param {Number=} blacklistDuration an optional number of seconds to blacklist the
28065     * playlist
28066     */
28067  }, {
28068    key: 'blacklistCurrentPlaylist',
28069    value: function blacklistCurrentPlaylist(error, blacklistDuration) {
28070      if (error === undefined) error = {};
28071
28072      var currentPlaylist = undefined;
28073      var nextPlaylist = undefined;
28074
28075      // If the `error` was generated by the playlist loader, it will contain
28076      // the playlist we were trying to load (but failed) and that should be
28077      // blacklisted instead of the currently selected playlist which is likely
28078      // out-of-date in this scenario
28079      currentPlaylist = error.playlist || this.masterPlaylistLoader_.media();
28080
28081      // If there is no current playlist, then an error occurred while we were
28082      // trying to load the master OR while we were disposing of the tech
28083      if (!currentPlaylist) {
28084        this.error = error;
28085
28086        try {
28087          return this.mediaSource.endOfStream('network');
28088        } catch (e) {
28089          return this.trigger('error');
28090        }
28091      }
28092
28093      var isFinalRendition = this.masterPlaylistLoader_.isFinalRendition_();
28094
28095      if (isFinalRendition) {
28096        // Never blacklisting this playlist because it's final rendition
28097        _videoJs2['default'].log.warn('Problem encountered with the current ' + 'HLS playlist. Trying again since it is the final playlist.');
28098
28099        this.tech_.trigger('retryplaylist');
28100        return this.masterPlaylistLoader_.load(isFinalRendition);
28101      }
28102      // Blacklist this playlist
28103      currentPlaylist.excludeUntil = Date.now() + (blacklistDuration ? blacklistDuration : this.blacklistDuration) * 1000;
28104      this.tech_.trigger('blacklistplaylist');
28105      this.tech_.trigger({ type: 'usage', name: 'hls-rendition-blacklisted' });
28106
28107      // Select a new playlist
28108      nextPlaylist = this.selectPlaylist();
28109      _videoJs2['default'].log.warn('Problem encountered with the current HLS playlist.' + (error.message ? ' ' + error.message : '') + ' Switching to another playlist.');
28110
28111      return this.masterPlaylistLoader_.media(nextPlaylist);
28112    }
28113
28114    /**
28115     * Pause all segment loaders
28116     */
28117  }, {
28118    key: 'pauseLoading',
28119    value: function pauseLoading() {
28120      this.mainSegmentLoader_.pause();
28121      if (this.mediaTypes_.AUDIO.activePlaylistLoader) {
28122        this.audioSegmentLoader_.pause();
28123      }
28124      if (this.mediaTypes_.SUBTITLES.activePlaylistLoader) {
28125        this.subtitleSegmentLoader_.pause();
28126      }
28127    }
28128
28129    /**
28130     * set the current time on all segment loaders
28131     *
28132     * @param {TimeRange} currentTime the current time to set
28133     * @return {TimeRange} the current time
28134     */
28135  }, {
28136    key: 'setCurrentTime',
28137    value: function setCurrentTime(currentTime) {
28138      var buffered = _ranges2['default'].findRange(this.tech_.buffered(), currentTime);
28139
28140      if (!(this.masterPlaylistLoader_ && this.masterPlaylistLoader_.media())) {
28141        // return immediately if the metadata is not ready yet
28142        return 0;
28143      }
28144
28145      // it's clearly an edge-case but don't thrown an error if asked to
28146      // seek within an empty playlist
28147      if (!this.masterPlaylistLoader_.media().segments) {
28148        return 0;
28149      }
28150
28151      // In flash playback, the segment loaders should be reset on every seek, even
28152      // in buffer seeks
28153      var isFlash = this.mode_ === 'flash' || this.mode_ === 'auto' && !_videoJs2['default'].MediaSource.supportsNativeMediaSources();
28154
28155      // if the seek location is already buffered, continue buffering as
28156      // usual
28157      if (buffered && buffered.length && !isFlash) {
28158        return currentTime;
28159      }
28160
28161      // cancel outstanding requests so we begin buffering at the new
28162      // location
28163      this.mainSegmentLoader_.resetEverything();
28164      this.mainSegmentLoader_.abort();
28165      if (this.mediaTypes_.AUDIO.activePlaylistLoader) {
28166        this.audioSegmentLoader_.resetEverything();
28167        this.audioSegmentLoader_.abort();
28168      }
28169      if (this.mediaTypes_.SUBTITLES.activePlaylistLoader) {
28170        this.subtitleSegmentLoader_.resetEverything();
28171        this.subtitleSegmentLoader_.abort();
28172      }
28173
28174      // start segment loader loading in case they are paused
28175      this.load();
28176    }
28177
28178    /**
28179     * get the current duration
28180     *
28181     * @return {TimeRange} the duration
28182     */
28183  }, {
28184    key: 'duration',
28185    value: function duration() {
28186      if (!this.masterPlaylistLoader_) {
28187        return 0;
28188      }
28189
28190      if (this.mediaSource) {
28191        return this.mediaSource.duration;
28192      }
28193
28194      return Hls.Playlist.duration(this.masterPlaylistLoader_.media());
28195    }
28196
28197    /**
28198     * check the seekable range
28199     *
28200     * @return {TimeRange} the seekable range
28201     */
28202  }, {
28203    key: 'seekable',
28204    value: function seekable() {
28205      return this.seekable_;
28206    }
28207  }, {
28208    key: 'onSyncInfoUpdate_',
28209    value: function onSyncInfoUpdate_() {
28210      var mainSeekable = undefined;
28211      var audioSeekable = undefined;
28212
28213      if (!this.masterPlaylistLoader_) {
28214        return;
28215      }
28216
28217      var media = this.masterPlaylistLoader_.media();
28218
28219      if (!media) {
28220        return;
28221      }
28222
28223      var expired = this.syncController_.getExpiredTime(media, this.mediaSource.duration);
28224
28225      if (expired === null) {
28226        // not enough information to update seekable
28227        return;
28228      }
28229
28230      mainSeekable = Hls.Playlist.seekable(media, expired);
28231
28232      if (mainSeekable.length === 0) {
28233        return;
28234      }
28235
28236      if (this.mediaTypes_.AUDIO.activePlaylistLoader) {
28237        media = this.mediaTypes_.AUDIO.activePlaylistLoader.media();
28238        expired = this.syncController_.getExpiredTime(media, this.mediaSource.duration);
28239
28240        if (expired === null) {
28241          return;
28242        }
28243
28244        audioSeekable = Hls.Playlist.seekable(media, expired);
28245
28246        if (audioSeekable.length === 0) {
28247          return;
28248        }
28249      }
28250
28251      if (!audioSeekable) {
28252        // seekable has been calculated based on buffering video data so it
28253        // can be returned directly
28254        this.seekable_ = mainSeekable;
28255      } else if (audioSeekable.start(0) > mainSeekable.end(0) || mainSeekable.start(0) > audioSeekable.end(0)) {
28256        // seekables are pretty far off, rely on main
28257        this.seekable_ = mainSeekable;
28258      } else {
28259        this.seekable_ = _videoJs2['default'].createTimeRanges([[audioSeekable.start(0) > mainSeekable.start(0) ? audioSeekable.start(0) : mainSeekable.start(0), audioSeekable.end(0) < mainSeekable.end(0) ? audioSeekable.end(0) : mainSeekable.end(0)]]);
28260      }
28261
28262      this.tech_.trigger('seekablechanged');
28263    }
28264
28265    /**
28266     * Update the player duration
28267     */
28268  }, {
28269    key: 'updateDuration',
28270    value: function updateDuration() {
28271      var _this4 = this;
28272
28273      var oldDuration = this.mediaSource.duration;
28274      var newDuration = Hls.Playlist.duration(this.masterPlaylistLoader_.media());
28275      var buffered = this.tech_.buffered();
28276      var setDuration = function setDuration() {
28277        _this4.mediaSource.duration = newDuration;
28278        _this4.tech_.trigger('durationchange');
28279
28280        _this4.mediaSource.removeEventListener('sourceopen', setDuration);
28281      };
28282
28283      if (buffered.length > 0) {
28284        newDuration = Math.max(newDuration, buffered.end(buffered.length - 1));
28285      }
28286
28287      // if the duration has changed, invalidate the cached value
28288      if (oldDuration !== newDuration) {
28289        // update the duration
28290        if (this.mediaSource.readyState !== 'open') {
28291          this.mediaSource.addEventListener('sourceopen', setDuration);
28292        } else {
28293          setDuration();
28294        }
28295      }
28296    }
28297
28298    /**
28299     * dispose of the MasterPlaylistController and everything
28300     * that it controls
28301     */
28302  }, {
28303    key: 'dispose',
28304    value: function dispose() {
28305      var _this5 = this;
28306
28307      this.decrypter_.terminate();
28308      this.masterPlaylistLoader_.dispose();
28309      this.mainSegmentLoader_.dispose();
28310
28311      ['AUDIO', 'SUBTITLES'].forEach(function (type) {
28312        var groups = _this5
vendor: 5,934 bytes, lines 28312-28489
28312.mediaTypes_[type].groups;
28313
28314        for (var id in groups) {
28315          groups[id].forEach(function (group) {
28316            if (group.playlistLoader) {
28317              group.playlistLoader.dispose();
28318            }
28319          });
28320        }
28321      });
28322
28323      this.audioSegmentLoader_.dispose();
28324      this.subtitleSegmentLoader_.dispose();
28325    }
28326
28327    /**
28328     * return the master playlist object if we have one
28329     *
28330     * @return {Object} the master playlist object that we parsed
28331     */
28332  }, {
28333    key: 'master',
28334    value: function master() {
28335      return this.masterPlaylistLoader_.master;
28336    }
28337
28338    /**
28339     * return the currently selected playlist
28340     *
28341     * @return {Object} the currently selected playlist object that we parsed
28342     */
28343  }, {
28344    key: 'media',
28345    value: function media() {
28346      // playlist loader will not return media if it has not been fully loaded
28347      return this.masterPlaylistLoader_.media() || this.initialMedia_;
28348    }
28349
28350    /**
28351     * setup our internal source buffers on our segment Loaders
28352     *
28353     * @private
28354     */
28355  }, {
28356    key: 'setupSourceBuffers_',
28357    value: function setupSourceBuffers_() {
28358      var media = this.masterPlaylistLoader_.media();
28359      var mimeTypes = undefined;
28360
28361      // wait until a media playlist is available and the Media Source is
28362      // attached
28363      if (!media || this.mediaSource.readyState !== 'open') {
28364        return;
28365      }
28366
28367      mimeTypes = mimeTypesForPlaylist_(this.masterPlaylistLoader_.master, media);
28368      if (mimeTypes.length < 1) {
28369        this.error = 'No compatible SourceBuffer configuration for the variant stream:' + media.resolvedUri;
28370        return this.mediaSource.endOfStream('decode');
28371      }
28372      this.mainSegmentLoader_.mimeType(mimeTypes[0]);
28373      if (mimeTypes[1]) {
28374        this.audioSegmentLoader_.mimeType(mimeTypes[1]);
28375      }
28376
28377      // exclude any incompatible variant streams from future playlist
28378      // selection
28379      this.excludeIncompatibleVariants_(media);
28380    }
28381
28382    /**
28383     * Blacklist playlists that are known to be codec or
28384     * stream-incompatible with the SourceBuffer configuration. For
28385     * instance, Media Source Extensions would cause the video element to
28386     * stall waiting for video data if you switched from a variant with
28387     * video and audio to an audio-only one.
28388     *
28389     * @param {Object} media a media playlist compatible with the current
28390     * set of SourceBuffers. Variants in the current master playlist that
28391     * do not appear to have compatible codec or stream configurations
28392     * will be excluded from the default playlist selection algorithm
28393     * indefinitely.
28394     * @private
28395     */
28396  }, {
28397    key: 'excludeIncompatibleVariants_',
28398    value: function excludeIncompatibleVariants_(media) {
28399      var master = this.masterPlaylistLoader_.master;
28400      var codecCount = 2;
28401      var videoCodec = null;
28402      var codecs = undefined;
28403
28404      if (media.attributes.CODECS) {
28405        codecs = (0, _utilCodecsJs.parseCodecs)(media.attributes.CODECS);
28406        videoCodec = codecs.videoCodec;
28407        codecCount = codecs.codecCount;
28408      }
28409      master.playlists.forEach(function (variant) {
28410        var variantCodecs = {
28411          codecCount: 2,
28412          videoCodec: null
28413        };
28414
28415        if (variant.attributes.CODECS) {
28416          var codecString = variant.attributes.CODECS;
28417
28418          variantCodecs = (0, _utilCodecsJs.parseCodecs)(codecString);
28419
28420          if (window.MediaSource && window.MediaSource.isTypeSupported && !window.MediaSource.isTypeSupported('video/mp4; codecs="' + mapLegacyAvcCodecs_(codecString) + '"')) {
28421            variant.excludeUntil = Infinity;
28422          }
28423        }
28424
28425        // if the streams differ in the presence or absence of audio or
28426        // video, they are incompatible
28427        if (variantCodecs.codecCount !== codecCount) {
28428          variant.excludeUntil = Infinity;
28429        }
28430
28431        // if h.264 is specified on the current playlist, some flavor of
28432        // it must be specified on all compatible variants
28433        if (variantCodecs.videoCodec !== videoCodec) {
28434          variant.excludeUntil = Infinity;
28435        }
28436      });
28437    }
28438  }, {
28439    key: 'updateAdCues_',
28440    value: function updateAdCues_(media) {
28441      var offset = 0;
28442      var seekable = this.seekable();
28443
28444      if (seekable.length) {
28445        offset = seekable.start(0);
28446      }
28447
28448      _adCueTags2['default'].updateAdCues(media, this.cueTagsTrack_, offset);
28449    }
28450
28451    /**
28452     * Calculates the desired forward buffer length based on current time
28453     *
28454     * @return {Number} Desired forward buffer length in seconds
28455     */
28456  }, {
28457    key: 'goalBufferLength',
28458    value: function goalBufferLength() {
28459      var currentTime = this.tech_.currentTime();
28460      var initial = _config2['default'].GOAL_BUFFER_LENGTH;
28461      var rate = _config2['default'].GOAL_BUFFER_LENGTH_RATE;
28462      var max = Math.max(initial, _config2['default'].MAX_GOAL_BUFFER_LENGTH);
28463
28464      return Math.min(initial + currentTime * rate, max);
28465    }
28466
28467    /**
28468     * Calculates the desired buffer low water line based on current time
28469     *
28470     * @return {Number} Desired buffer low water line in seconds
28471     */
28472  }, {
28473    key: 'bufferLowWaterLine',
28474    value: function bufferLowWaterLine() {
28475      var currentTime = this.tech_.currentTime();
28476      var initial = _config2['default'].BUFFER_LOW_WATER_LINE;
28477      var rate = _config2['default'].BUFFER_LOW_WATER_LINE_RATE;
28478      var max = Math.max(initial, _config2['default'].MAX_BUFFER_LOW_WATER_LINE);
28479
28480      return Math.min(initial + currentTime * rate, max);
28481    }
28482  }]);
28483
28484  return MasterPlaylistController;
28485})(_videoJs2['default'].EventTarget);
28486
28487exports.MasterPlaylistController = MasterPlaylistController;
28488}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
28489},{"./ad-cue-tags":1,"./config":3,"./decrypter-worker":4,"./media-groups":6,"./playlist-loader":9,"./
vendor: 16,090 bytes, lines 28489-28953
28489ranges":12,"./segment-loader":16,"./sync-controller":18,"./util/codecs.js":19,"./vtt-segment-loader":20,"videojs-contrib-media-sources/es5/codec-utils":65,"webworkify":76}],6:[function(require,module,exports){
28490(function (global){
28491'use strict';
28492
28493Object.defineProperty(exports, '__esModule', {
28494  value: true
28495});
28496
28497function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
28498
28499var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
28500
28501var _videoJs2 = _interopRequireDefault(_videoJs);
28502
28503var _playlistLoader = require('./playlist-loader');
28504
28505var _playlistLoader2 = _interopRequireDefault(_playlistLoader);
28506
28507var noop = function noop() {};
28508
28509/**
28510 * Convert the properties of an HLS track into an audioTrackKind.
28511 *
28512 * @private
28513 */
28514var audioTrackKind_ = function audioTrackKind_(properties) {
28515  var kind = properties['default'] ? 'main' : 'alternative';
28516
28517  if (properties.characteristics && properties.characteristics.indexOf('public.accessibility.describes-video') >= 0) {
28518    kind = 'main-desc';
28519  }
28520
28521  return kind;
28522};
28523
28524/**
28525 * Pause provided segment loader and playlist loader if active
28526 *
28527 * @param {SegmentLoader} segmentLoader
28528 *        SegmentLoader to pause
28529 * @param {Object} mediaType
28530 *        Active media type
28531 * @function stopLoaders
28532 */
28533var stopLoaders = function stopLoaders(segmentLoader, mediaType) {
28534  segmentLoader.abort();
28535  segmentLoader.pause();
28536
28537  if (mediaType && mediaType.activePlaylistLoader) {
28538    mediaType.activePlaylistLoader.pause();
28539    mediaType.activePlaylistLoader = null;
28540  }
28541};
28542
28543exports.stopLoaders = stopLoaders;
28544/**
28545 * Start loading provided segment loader and playlist loader
28546 *
28547 * @param {PlaylistLoader} playlistLoader
28548 *        PlaylistLoader to start loading
28549 * @param {Object} mediaType
28550 *        Active media type
28551 * @function startLoaders
28552 */
28553var startLoaders = function startLoaders(playlistLoader, mediaType) {
28554  // Segment loader will be started after `loadedmetadata` or `loadedplaylist` from the
28555  // playlist loader
28556  mediaType.activePlaylistLoader = playlistLoader;
28557  playlistLoader.load();
28558};
28559
28560exports.startLoaders = startLoaders;
28561/**
28562 * Returns a function to be called when the media group changes. It performs a
28563 * non-destructive (preserve the buffer) resync of the SegmentLoader. This is because a
28564 * change of group is merely a rendition switch of the same content at another encoding,
28565 * rather than a change of content, such as switching audio from English to Spanish.
28566 *
28567 * @param {String} type
28568 *        MediaGroup type
28569 * @param {Object} settings
28570 *        Object containing required information for media groups
28571 * @return {Function}
28572 *         Handler for a non-destructive resync of SegmentLoader when the active media
28573 *         group changes.
28574 * @function onGroupChanged
28575 */
28576var onGroupChanged = function onGroupChanged(type, settings) {
28577  return function () {
28578    var _settings$segmentLoaders = settings.segmentLoaders;
28579    var segmentLoader = _settings$segmentLoaders[type];
28580    var mainSegmentLoader = _settings$segmentLoaders.main;
28581    var mediaType = settings.mediaTypes[type];
28582
28583    var activeTrack = mediaType.activeTrack();
28584    var activeGroup = mediaType.activeGroup(activeTrack);
28585    var previousActiveLoader = mediaType.activePlaylistLoader;
28586
28587    stopLoaders(segmentLoader, mediaType);
28588
28589    if (!activeGroup) {
28590      // there is no group active
28591      return;
28592    }
28593
28594    if (!activeGroup.playlistLoader) {
28595      if (previousActiveLoader) {
28596        // The previous group had a playlist loader but the new active group does not
28597        // this means we are switching from demuxed to muxed audio. In this case we want to
28598        // do a destructive reset of the main segment loader and not restart the audio
28599        // loaders.
28600        mainSegmentLoader.resetEverything();
28601      }
28602      return;
28603    }
28604
28605    // Non-destructive resync
28606    segmentLoader.resyncLoader();
28607
28608    startLoaders(activeGroup.playlistLoader, mediaType);
28609  };
28610};
28611
28612exports.onGroupChanged = onGroupChanged;
28613/**
28614 * Returns a function to be called when the media track changes. It performs a
28615 * destructive reset of the SegmentLoader to ensure we start loading as close to
28616 * currentTime as possible.
28617 *
28618 * @param {String} type
28619 *        MediaGroup type
28620 * @param {Object} settings
28621 *        Object containing required information for media groups
28622 * @return {Function}
28623 *         Handler for a destructive reset of SegmentLoader when the active media
28624 *         track changes.
28625 * @function onTrackChanged
28626 */
28627var onTrackChanged = function onTrackChanged(type, settings) {
28628  return function () {
28629    var _settings$segmentLoaders2 = settings.segmentLoaders;
28630    var segmentLoader = _settings$segmentLoaders2[type];
28631    var mainSegmentLoader = _settings$segmentLoaders2.main;
28632    var mediaType = settings.mediaTypes[type];
28633
28634    var activeTrack = mediaType.activeTrack();
28635    var activeGroup = mediaType.activeGroup(activeTrack);
28636    var previousActiveLoader = mediaType.activePlaylistLoader;
28637
28638    stopLoaders(segmentLoader, mediaType);
28639
28640    if (!activeGroup) {
28641      // there is no group active so we do not want to restart loaders
28642      return;
28643    }
28644
28645    if (!activeGroup.playlistLoader) {
28646      // when switching from demuxed audio/video to muxed audio/video (noted by no playlist
28647      // loader for the audio group), we want to do a destructive reset of the main segment
28648      // loader and not restart the audio loaders
28649      mainSegmentLoader.resetEverything();
28650      return;
28651    }
28652
28653    if (previousActiveLoader === activeGroup.playlistLoader) {
28654      // Nothing has actually changed. This can happen because track change events can fire
28655      // multiple times for a "single" change. One for enabling the new active track, and
28656      // one for disabling the track that was active
28657      startLoaders(activeGroup.playlistLoader, mediaType);
28658      return;
28659    }
28660
28661    if (segmentLoader.track) {
28662      // For WebVTT, set the new text track in the segmentloader
28663      segmentLoader.track(activeTrack);
28664    }
28665
28666    // destructive reset
28667    segmentLoader.resetEverything();
28668
28669    startLoaders(activeGroup.playlistLoader, mediaType);
28670  };
28671};
28672
28673exports.onTrackChanged = onTrackChanged;
28674var onError = {
28675  /**
28676   * Returns a function to be called when a SegmentLoader or PlaylistLoader encounters
28677   * an error.
28678   *
28679   * @param {String} type
28680   *        MediaGroup type
28681   * @param {Object} settings
28682   *        Object containing required information for media groups
28683   * @return {Function}
28684   *         Error handler. Logs warning (or error if the playlist is blacklisted) to
28685   *         console and switches back to default audio track.
28686   * @function onError.AUDIO
28687   */
28688  AUDIO: function AUDIO(type, settings) {
28689    return function () {
28690      var segmentLoader = settings.segmentLoaders[type];
28691      var mediaType = settings.mediaTypes[type];
28692      var blacklistCurrentPlaylist = settings.blacklistCurrentPlaylist;
28693
28694      stopLoaders(segmentLoader, mediaType);
28695
28696      // switch back to default audio track
28697      var activeTrack = mediaType.activeTrack();
28698      var activeGroup = mediaType.activeGroup();
28699      var id = (activeGroup.filter(function (group) {
28700        return group['default'];
28701      })[0] || activeGroup[0]).id;
28702      var defaultTrack = mediaType.tracks[id];
28703
28704      if (activeTrack === defaultTrack) {
28705        // Default track encountered an error. All we can do now is blacklist the current
28706        // rendition and hope another will switch audio groups
28707        blacklistCurrentPlaylist({
28708          message: 'Problem encountered loading the default audio track.'
28709        });
28710        return;
28711      }
28712
28713      _videoJs2['default'].log.warn('Problem encountered loading the alternate audio track.' + 'Switching back to default.');
28714
28715      for (var trackId in mediaType.tracks) {
28716        mediaType.tracks[trackId].enabled = mediaType.tracks[trackId] === defaultTrack;
28717      }
28718
28719      mediaType.onTrackChanged();
28720    };
28721  },
28722  /**
28723   * Returns a function to be called when a SegmentLoader or PlaylistLoader encounters
28724   * an error.
28725   *
28726   * @param {String} type
28727   *        MediaGroup type
28728   * @param {Object} settings
28729   *        Object containing required information for media groups
28730   * @return {Function}
28731   *         Error handler. Logs warning to console and disables the active subtitle track
28732   * @function onError.SUBTITLES
28733   */
28734  SUBTITLES: function SUBTITLES(type, settings) {
28735    return function () {
28736      var segmentLoader = settings.segmentLoaders[type];
28737      var mediaType = settings.mediaTypes[type];
28738
28739      _videoJs2['default'].log.warn('Problem encountered loading the subtitle track.' + 'Disabling subtitle track.');
28740
28741      stopLoaders(segmentLoader, mediaType);
28742
28743      var track = mediaType.activeTrack();
28744
28745      if (track) {
28746        track.mode = 'disabled';
28747      }
28748
28749      mediaType.onTrackChanged();
28750    };
28751  }
28752};
28753
28754exports.onError = onError;
28755var setupListeners = {
28756  /**
28757   * Setup event listeners for audio playlist loader
28758   *
28759   * @param {String} type
28760   *        MediaGroup type
28761   * @param {PlaylistLoader|null} playlistLoader
28762   *        PlaylistLoader to register listeners on
28763   * @param {Object} settings
28764   *        Object containing required information for media groups
28765   * @function setupListeners.AUDIO
28766   */
28767  AUDIO: function AUDIO(type, playlistLoader, settings) {
28768    if (!playlistLoader) {
28769      // no playlist loader means audio will be muxed with the video
28770      return;
28771    }
28772
28773    var tech = settings.tech;
28774    var requestOptions = settings.requestOptions;
28775    var segmentLoader = settings.segmentLoaders[type];
28776
28777    playlistLoader.on('loadedmetadata', function () {
28778      var media = playlistLoader.media();
28779
28780      segmentLoader.playlist(media, requestOptions);
28781
28782      // if the video is already playing, or if this isn't a live video and preload
28783      // permits, start downloading segments
28784      if (!tech.paused() || media.endList && tech.preload() !== 'none') {
28785        segmentLoader.load();
28786      }
28787    });
28788
28789    playlistLoader.on('loadedplaylist', function () {
28790      segmentLoader.playlist(playlistLoader.media(), requestOptions);
28791
28792      // If the player isn't paused, ensure that the segment loader is running
28793      if (!tech.paused()) {
28794        segmentLoader.load();
28795      }
28796    });
28797
28798    playlistLoader.on('error', onError[type](type, settings));
28799  },
28800  /**
28801   * Setup event listeners for subtitle playlist loader
28802   *
28803   * @param {String} type
28804   *        MediaGroup type
28805   * @param {PlaylistLoader|null} playlistLoader
28806   *        PlaylistLoader to register listeners on
28807   * @param {Object} settings
28808   *        Object containing required information for media groups
28809   * @function setupListeners.SUBTITLES
28810   */
28811  SUBTITLES: function SUBTITLES(type, playlistLoader, settings) {
28812    var tech = settings.tech;
28813    var requestOptions = settings.requestOptions;
28814    var segmentLoader = settings.segmentLoaders[type];
28815    var mediaType = settings.mediaTypes[type];
28816
28817    playlistLoader.on('loadedmetadata', function () {
28818      var media = playlistLoader.media();
28819
28820      segmentLoader.playlist(media, requestOptions);
28821      segmentLoader.track(mediaType.activeTrack());
28822
28823      // if the video is already playing, or if this isn't a live video and preload
28824      // permits, start downloading segments
28825      if (!tech.paused() || media.endList && tech.preload() !== 'none') {
28826        segmentLoader.load();
28827      }
28828    });
28829
28830    playlistLoader.on('loadedplaylist', function () {
28831      segmentLoader.playlist(playlistLoader.media(), requestOptions);
28832
28833      // If the player isn't paused, ensure that the segment loader is running
28834      if (!tech.paused()) {
28835        segmentLoader.load();
28836      }
28837    });
28838
28839    playlistLoader.on('error', onError[type](type, settings));
28840  }
28841};
28842
28843exports.setupListeners = setupListeners;
28844var initialize = {
28845  /**
28846   * Setup PlaylistLoaders and AudioTracks for the audio groups
28847   *
28848   * @param {String} type
28849   *        MediaGroup type
28850   * @param {Object} settings
28851   *        Object containing required information for media groups
28852   * @function initialize.AUDIO
28853   */
28854  'AUDIO': function AUDIO(type, settings) {
28855    var mode = settings.mode;
28856    var hls = settings.hls;
28857    var segmentLoader = settings.segmentLoaders[type];
28858    var withCredentials = settings.requestOptions.withCredentials;
28859    var mediaGroups = settings.master.mediaGroups;
28860    var _settings$mediaTypes$type = settings.mediaTypes[type];
28861    var groups = _settings$mediaTypes$type.groups;
28862    var tracks = _settings$mediaTypes$type.tracks;
28863
28864    // force a default if we have none or we are not
28865    // in html5 mode (the only mode to support more than one
28866    // audio track)
28867    if (!mediaGroups[type] || Object.keys(mediaGroups[type]).length === 0 || mode !== 'html5') {
28868      mediaGroups[type] = { main: { 'default': { 'default': true } } };
28869    }
28870
28871    for (var groupId in mediaGroups[type]) {
28872      if (!groups[groupId]) {
28873        groups[groupId] = [];
28874      }
28875
28876      for (var variantLabel in mediaGroups[type][groupId]) {
28877        var properties = mediaGroups[type][groupId][variantLabel];
28878        var playlistLoader = undefined;
28879
28880        if (properties.resolvedUri) {
28881          playlistLoader = new _playlistLoader2['default'](properties.resolvedUri, hls, withCredentials);
28882        } else {
28883          // no resolvedUri means the audio is muxed with the video when using this
28884          // audio track
28885          playlistLoader = null;
28886        }
28887
28888        properties = _videoJs2['default'].mergeOptions({ id: variantLabel, playlistLoader: playlistLoader }, properties);
28889
28890        setupListeners[type](type, properties.playlistLoader, settings);
28891
28892        groups[groupId].push(properties);
28893
28894        if (typeof tracks[variantLabel] === 'undefined') {
28895          var track = new _videoJs2['default'].AudioTrack({
28896            id: variantLabel,
28897            kind: audioTrackKind_(properties),
28898            enabled: false,
28899            language: properties.language,
28900            'default': properties['default'],
28901            label: variantLabel
28902          });
28903
28904          tracks[variantLabel] = track;
28905        }
28906      }
28907    }
28908
28909    // setup single error event handler for the segment loader
28910    segmentLoader.on('error', onError[type](type, settings));
28911  },
28912  /**
28913   * Setup PlaylistLoaders and TextTracks for the subtitle groups
28914   *
28915   * @param {String} type
28916   *        MediaGroup type
28917   * @param {Object} settings
28918   *        Object containing required information for media groups
28919   * @function initialize.SUBTITLES
28920   */
28921  'SUBTITLES': function SUBTITLES(type, settings) {
28922    var tech = settings.tech;
28923    var hls = settings.hls;
28924    var segmentLoader = settings.segmentLoaders[type];
28925    var withCredentials = settings.requestOptions.withCredentials;
28926    var mediaGroups = settings.master.mediaGroups;
28927    var _settings$mediaTypes$type2 = settings.mediaTypes[type];
28928    var groups = _settings$mediaTypes$type2.groups;
28929    var tracks = _settings$mediaTypes$type2.tracks;
28930
28931    for (var groupId in mediaGroups[type]) {
28932      if (!groups[groupId]) {
28933        groups[groupId] = [];
28934      }
28935
28936      for (var variantLabel in mediaGroups[type][groupId]) {
28937        if (mediaGroups[type][groupId][variantLabel].forced) {
28938          // Subtitle playlists with the forced attribute are not selectable in Safari.
28939          // According to Apple's HLS Authoring Specification:
28940          //   If content has forced subtitles and regular subtitles in a given language,
28941          //   the regular subtitles track in that language MUST contain both the forced
28942          //   subtitles and the regular subtitles for that language.
28943          // Because of this requirement and that Safari does not add forced subtitles,
28944          // forced subtitles are skipped here to maintain consistent experience across
28945          // all platforms
28946          continue;
28947        }
28948
28949        var properties = mediaGroups[type][groupId][variantLabel];
28950
28951        properties = _videoJs2['default'].mergeOptions({
28952          id: variantLabel,
28953          playlistLoader: new _playlistLoader2['default'](properties.resolvedUri, hls, withCredential
vendor: 29,351 bytes, lines 28953-29838
28953s)
28954        }, properties);
28955
28956        setupListeners[type](type, properties.playlistLoader, settings);
28957
28958        groups[groupId].push(properties);
28959
28960        if (typeof tracks[variantLabel] === 'undefined') {
28961          var track = tech.addRemoteTextTrack({
28962            id: variantLabel,
28963            kind: 'subtitles',
28964            enabled: false,
28965            language: properties.language,
28966            label: variantLabel
28967          }, false).track;
28968
28969          tracks[variantLabel] = track;
28970        }
28971      }
28972    }
28973
28974    // setup single error event handler for the segment loader
28975    segmentLoader.on('error', onError[type](type, settings));
28976  },
28977  /**
28978   * Setup TextTracks for the closed-caption groups
28979   *
28980   * @param {String} type
28981   *        MediaGroup type
28982   * @param {Object} settings
28983   *        Object containing required information for media groups
28984   * @function initialize['CLOSED-CAPTIONS']
28985   */
28986  'CLOSED-CAPTIONS': function CLOSEDCAPTIONS(type, settings) {
28987    var tech = settings.tech;
28988    var mediaGroups = settings.master.mediaGroups;
28989    var _settings$mediaTypes$type3 = settings.mediaTypes[type];
28990    var groups = _settings$mediaTypes$type3.groups;
28991    var tracks = _settings$mediaTypes$type3.tracks;
28992
28993    for (var groupId in mediaGroups[type]) {
28994      if (!groups[groupId]) {
28995        groups[groupId] = [];
28996      }
28997
28998      for (var variantLabel in mediaGroups[type][groupId]) {
28999        var properties = mediaGroups[type][groupId][variantLabel];
29000
29001        // We only support CEA608 captions for now, so ignore anything that
29002        // doesn't use a CCx INSTREAM-ID
29003        if (!properties.instreamId.match(/CC\d/)) {
29004          continue;
29005        }
29006
29007        // No PlaylistLoader is required for Closed-Captions because the captions are
29008        // embedded within the video stream
29009        groups[groupId].push(_videoJs2['default'].mergeOptions({ id: variantLabel }, properties));
29010
29011        if (typeof tracks[variantLabel] === 'undefined') {
29012          var track = tech.addRemoteTextTrack({
29013            id: properties.instreamId,
29014            kind: 'captions',
29015            enabled: false,
29016            language: properties.language,
29017            label: variantLabel
29018          }, false).track;
29019
29020          tracks[variantLabel] = track;
29021        }
29022      }
29023    }
29024  }
29025};
29026
29027exports.initialize = initialize;
29028/**
29029 * Returns a function used to get the active group of the provided type
29030 *
29031 * @param {String} type
29032 *        MediaGroup type
29033 * @param {Object} settings
29034 *        Object containing required information for media groups
29035 * @return {Function}
29036 *         Function that returns the active media group for the provided type. Takes an
29037 *         optional parameter {TextTrack} track. If no track is provided, a list of all
29038 *         variants in the group, otherwise the variant corresponding to the provided
29039 *         track is returned.
29040 * @function activeGroup
29041 */
29042var activeGroup = function activeGroup(type, settings) {
29043  return function (track) {
29044    var masterPlaylistLoader = settings.masterPlaylistLoader;
29045    var groups = settings.mediaTypes[type].groups;
29046
29047    var media = masterPlaylistLoader.media();
29048
29049    if (!media) {
29050      return null;
29051    }
29052
29053    var variants = null;
29054
29055    if (media.attributes[type]) {
29056      variants = groups[media.attributes[type]];
29057    }
29058
29059    variants = variants || groups.main;
29060
29061    if (typeof track === 'undefined') {
29062      return variants;
29063    }
29064
29065    if (track === null) {
29066      // An active track was specified so a corresponding group is expected. track === null
29067      // means no track is currently active so there is no corresponding group
29068      return null;
29069    }
29070
29071    return variants.filter(function (props) {
29072      return props.id === track.id;
29073    })[0] || null;
29074  };
29075};
29076
29077exports.activeGroup = activeGroup;
29078var activeTrack = {
29079  /**
29080   * Returns a function used to get the active track of type provided
29081   *
29082   * @param {String} type
29083   *        MediaGroup type
29084   * @param {Object} settings
29085   *        Object containing required information for media groups
29086   * @return {Function}
29087   *         Function that returns the active media track for the provided type. Returns
29088   *         null if no track is active
29089   * @function activeTrack.AUDIO
29090   */
29091  AUDIO: function AUDIO(type, settings) {
29092    return function () {
29093      var tracks = settings.mediaTypes[type].tracks;
29094
29095      for (var id in tracks) {
29096        if (tracks[id].enabled) {
29097          return tracks[id];
29098        }
29099      }
29100
29101      return null;
29102    };
29103  },
29104  /**
29105   * Returns a function used to get the active track of type provided
29106   *
29107   * @param {String} type
29108   *        MediaGroup type
29109   * @param {Object} settings
29110   *        Object containing required information for media groups
29111   * @return {Function}
29112   *         Function that returns the active media track for the provided type. Returns
29113   *         null if no track is active
29114   * @function activeTrack.SUBTITLES
29115   */
29116  SUBTITLES: function SUBTITLES(type, settings) {
29117    return function () {
29118      var tracks = settings.mediaTypes[type].tracks;
29119
29120      for (var id in tracks) {
29121        if (tracks[id].mode === 'showing') {
29122          return tracks[id];
29123        }
29124      }
29125
29126      return null;
29127    };
29128  }
29129};
29130
29131exports.activeTrack = activeTrack;
29132/**
29133 * Setup PlaylistLoaders and Tracks for media groups (Audio, Subtitles,
29134 * Closed-Captions) specified in the master manifest.
29135 *
29136 * @param {Object} settings
29137 *        Object containing required information for setting up the media groups
29138 * @param {SegmentLoader} settings.segmentLoaders.AUDIO
29139 *        Audio segment loader
29140 * @param {SegmentLoader} settings.segmentLoaders.SUBTITLES
29141 *        Subtitle segment loader
29142 * @param {SegmentLoader} settings.segmentLoaders.main
29143 *        Main segment loader
29144 * @param {Tech} settings.tech
29145 *        The tech of the player
29146 * @param {Object} settings.requestOptions
29147 *        XHR request options used by the segment loaders
29148 * @param {PlaylistLoader} settings.masterPlaylistLoader
29149 *        PlaylistLoader for the master source
29150 * @param {String} mode
29151 *        Mode of the hls source handler. Can be 'auto', 'html5', or 'flash'
29152 * @param {HlsHandler} settings.hls
29153 *        HLS SourceHandler
29154 * @param {Object} settings.master
29155 *        The parsed master manifest
29156 * @param {Object} settings.mediaTypes
29157 *        Object to store the loaders, tracks, and utility methods for each media type
29158 * @param {Function} settings.blacklistCurrentPlaylist
29159 *        Blacklists the current rendition and forces a rendition switch.
29160 * @function setupMediaGroups
29161 */
29162var setupMediaGroups = function setupMediaGroups(settings) {
29163  ['AUDIO', 'SUBTITLES', 'CLOSED-CAPTIONS'].forEach(function (type) {
29164    initialize[type](type, settings);
29165  });
29166
29167  var mediaTypes = settings.mediaTypes;
29168  var masterPlaylistLoader = settings.masterPlaylistLoader;
29169  var tech = settings.tech;
29170  var hls = settings.hls;
29171
29172  // setup active group and track getters and change event handlers
29173  ['AUDIO', 'SUBTITLES'].forEach(function (type) {
29174    mediaTypes[type].activeGroup = activeGroup(type, settings);
29175    mediaTypes[type].activeTrack = activeTrack[type](type, settings);
29176    mediaTypes[type].onGroupChanged = onGroupChanged(type, settings);
29177    mediaTypes[type].onTrackChanged = onTrackChanged(type, settings);
29178  });
29179
29180  // DO NOT enable the default subtitle or caption track.
29181  // DO enable the default audio track
29182  var audioGroup = mediaTypes.AUDIO.activeGroup();
29183  var groupId = (audioGroup.filter(function (group) {
29184    return group['default'];
29185  })[0] || audioGroup[0]).id;
29186
29187  mediaTypes.AUDIO.tracks[groupId].enabled = true;
29188  mediaTypes.AUDIO.onTrackChanged();
29189
29190  masterPlaylistLoader.on('mediachange', function () {
29191    ['AUDIO', 'SUBTITLES'].forEach(function (type) {
29192      return mediaTypes[type].onGroupChanged();
29193    });
29194  });
29195
29196  // custom audio track change event handler for usage event
29197  var onAudioTrackChanged = function onAudioTrackChanged() {
29198    mediaTypes.AUDIO.onTrackChanged();
29199    tech.trigger({ type: 'usage', name: 'hls-audio-change' });
29200  };
29201
29202  tech.audioTracks().addEventListener('change', onAudioTrackChanged);
29203  tech.remoteTextTracks().addEventListener('change', mediaTypes.SUBTITLES.onTrackChanged);
29204
29205  hls.on('dispose', function () {
29206    tech.audioTracks().removeEventListener('change', onAudioTrackChanged);
29207    tech.remoteTextTracks().removeEventListener('change', mediaTypes.SUBTITLES.onTrackChanged);
29208  });
29209
29210  // clear existing audio tracks and add the ones we just created
29211  tech.clearTracks('audio');
29212
29213  for (var id in mediaTypes.AUDIO.tracks) {
29214    tech.audioTracks().addTrack(mediaTypes.AUDIO.tracks[id]);
29215  }
29216};
29217
29218exports.setupMediaGroups = setupMediaGroups;
29219/**
29220 * Creates skeleton object used to store the loaders, tracks, and utility methods for each
29221 * media type
29222 *
29223 * @return {Object}
29224 *         Object to store the loaders, tracks, and utility methods for each media type
29225 * @function createMediaTypes
29226 */
29227var createMediaTypes = function createMediaTypes() {
29228  var mediaTypes = {};
29229
29230  ['AUDIO', 'SUBTITLES', 'CLOSED-CAPTIONS'].forEach(function (type) {
29231    mediaTypes[type] = {
29232      groups: {},
29233      tracks: {},
29234      activePlaylistLoader: null,
29235      activeGroup: noop,
29236      activeTrack: noop,
29237      onGroupChanged: noop,
29238      onTrackChanged: noop
29239    };
29240  });
29241
29242  return mediaTypes;
29243};
29244exports.createMediaTypes = createMediaTypes;
29245}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
29246},{"./playlist-loader":9}],7:[function(require,module,exports){
29247(function (global){
29248'use strict';
29249
29250Object.defineProperty(exports, '__esModule', {
29251  value: true
29252});
29253
29254function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
29255
29256var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
29257
29258var _videoJs2 = _interopRequireDefault(_videoJs);
29259
29260var _binUtils = require('./bin-utils');
29261
29262var REQUEST_ERRORS = {
29263  FAILURE: 2,
29264  TIMEOUT: -101,
29265  ABORTED: -102
29266};
29267
29268exports.REQUEST_ERRORS = REQUEST_ERRORS;
29269/**
29270 * Turns segment byterange into a string suitable for use in
29271 * HTTP Range requests
29272 *
29273 * @param {Object} byterange - an object with two values defining the start and end
29274 *                             of a byte-range
29275 */
29276var byterangeStr = function byterangeStr(byterange) {
29277  var byterangeStart = undefined;
29278  var byterangeEnd = undefined;
29279
29280  // `byterangeEnd` is one less than `offset + length` because the HTTP range
29281  // header uses inclusive ranges
29282  byterangeEnd = byterange.offset + byterange.length - 1;
29283  byterangeStart = byterange.offset;
29284  return 'bytes=' + byterangeStart + '-' + byterangeEnd;
29285};
29286
29287/**
29288 * Defines headers for use in the xhr request for a particular segment.
29289 *
29290 * @param {Object} segment - a simplified copy of the segmentInfo object
29291 *                           from SegmentLoader
29292 */
29293var segmentXhrHeaders = function segmentXhrHeaders(segment) {
29294  var headers = {};
29295
29296  if (segment.byterange) {
29297    headers.Range = byterangeStr(segment.byterange);
29298  }
29299  return headers;
29300};
29301
29302/**
29303 * Abort all requests
29304 *
29305 * @param {Object} activeXhrs - an object that tracks all XHR requests
29306 */
29307var abortAll = function abortAll(activeXhrs) {
29308  activeXhrs.forEach(function (xhr) {
29309    xhr.abort();
29310  });
29311};
29312
29313/**
29314 * Gather important bandwidth stats once a request has completed
29315 *
29316 * @param {Object} request - the XHR request from which to gather stats
29317 */
29318var getRequestStats = function getRequestStats(request) {
29319  return {
29320    bandwidth: request.bandwidth,
29321    bytesReceived: request.bytesReceived || 0,
29322    roundTripTime: request.roundTripTime || 0
29323  };
29324};
29325
29326/**
29327 * If possible gather bandwidth stats as a request is in
29328 * progress
29329 *
29330 * @param {Event} progressEvent - an event object from an XHR's progress event
29331 */
29332var getProgressStats = function getProgressStats(progressEvent) {
29333  var request = progressEvent.target;
29334  var roundTripTime = Date.now() - request.requestTime;
29335  var stats = {
29336    bandwidth: Infinity,
29337    bytesReceived: 0,
29338    roundTripTime: roundTripTime || 0
29339  };
29340
29341  stats.bytesReceived = progressEvent.loaded;
29342  // This can result in Infinity if stats.roundTripTime is 0 but that is ok
29343  // because we should only use bandwidth stats on progress to determine when
29344  // abort a request early due to insufficient bandwidth
29345  stats.bandwidth = Math.floor(stats.bytesReceived / stats.roundTripTime * 8 * 1000);
29346
29347  return stats;
29348};
29349
29350/**
29351 * Handle all error conditions in one place and return an object
29352 * with all the information
29353 *
29354 * @param {Error|null} error - if non-null signals an error occured with the XHR
29355 * @param {Object} request -  the XHR request that possibly generated the error
29356 */
29357var handleErrors = function handleErrors(error, request) {
29358  if (request.timedout) {
29359    return {
29360      status: request.status,
29361      message: 'HLS request timed-out at URL: ' + request.uri,
29362      code: REQUEST_ERRORS.TIMEOUT,
29363      xhr: request
29364    };
29365  }
29366
29367  if (request.aborted) {
29368    return {
29369      status: request.status,
29370      message: 'HLS request aborted at URL: ' + request.uri,
29371      code: REQUEST_ERRORS.ABORTED,
29372      xhr: request
29373    };
29374  }
29375
29376  if (error) {
29377    return {
29378      status: request.status,
29379      message: 'HLS request errored at URL: ' + request.uri,
29380      code: REQUEST_ERRORS.FAILURE,
29381      xhr: request
29382    };
29383  }
29384
29385  return null;
29386};
29387
29388/**
29389 * Handle responses for key data and convert the key data to the correct format
29390 * for the decryption step later
29391 *
29392 * @param {Object} segment - a simplified copy of the segmentInfo object
29393 *                           from SegmentLoader
29394 * @param {Function} finishProcessingFn - a callback to execute to continue processing
29395 *                                        this request
29396 */
29397var handleKeyResponse = function handleKeyResponse(segment, finishProcessingFn) {
29398  return function (error, request) {
29399    var response = request.response;
29400    var errorObj = handleErrors(error, request);
29401
29402    if (errorObj) {
29403      return finishProcessingFn(errorObj, segment);
29404    }
29405
29406    if (response.byteLength !== 16) {
29407      return finishProcessingFn({
29408        status: request.status,
29409        message: 'Invalid HLS key at URL: ' + request.uri,
29410        code: REQUEST_ERRORS.FAILURE,
29411        xhr: request
29412      }, segment);
29413    }
29414
29415    var view = new DataView(response);
29416
29417    segment.key.bytes = new Uint32Array([view.getUint32(0), view.getUint32(4), view.getUint32(8), view.getUint32(12)]);
29418    return finishProcessingFn(null, segment);
29419  };
29420};
29421
29422/**
29423 * Handle init-segment responses
29424 *
29425 * @param {Object} segment - a simplified copy of the segmentInfo object
29426 *                           from SegmentLoader
29427 * @param {Function} finishProcessingFn - a callback to execute to continue processing
29428 *                                        this request
29429 */
29430var handleInitSegmentResponse = function handleInitSegmentResponse(segment, finishProcessingFn) {
29431  return function (error, request) {
29432    var response = request.response;
29433    var errorObj = handleErrors(error, request);
29434
29435    if (errorObj) {
29436      return finishProcessingFn(errorObj, segment);
29437    }
29438
29439    // stop processing if received empty content
29440    if (response.byteLength === 0) {
29441      return finishProcessingFn({
29442        status: request.status,
29443        message: 'Empty HLS segment content at URL: ' + request.uri,
29444        code: REQUEST_ERRORS.FAILURE,
29445        xhr: request
29446      }, segment);
29447    }
29448
29449    segment.map.bytes = new Uint8Array(request.response);
29450    return finishProcessingFn(null, segment);
29451  };
29452};
29453
29454/**
29455 * Response handler for segment-requests being sure to set the correct
29456 * property depending on whether the segment is encryped or not
29457 * Also records and keeps track of stats that are used for ABR purposes
29458 *
29459 * @param {Object} segment - a simplified copy of the segmentInfo object
29460 *                           from SegmentLoader
29461 * @param {Function} finishProcessingFn - a callback to execute to continue processing
29462 *                                        this request
29463 */
29464var handleSegmentResponse = function handleSegmentResponse(segment, finishProcessingFn) {
29465  return function (error, request) {
29466    var response = request.response;
29467    var errorObj = handleErrors(error, request);
29468
29469    if (errorObj) {
29470      return finishProcessingFn(errorObj, segment);
29471    }
29472
29473    // stop processing if received empty content
29474    if (response.byteLength === 0) {
29475      return finishProcessingFn({
29476        status: request.status,
29477        message: 'Empty HLS segment content at URL: ' + request.uri,
29478        code: REQUEST_ERRORS.FAILURE,
29479        xhr: request
29480      }, segment);
29481    }
29482
29483    segment.stats = getRequestStats(request);
29484
29485    if (segment.key) {
29486      segment.encryptedBytes = new Uint8Array(request.response);
29487    } else {
29488      segment.bytes = new Uint8Array(request.response);
29489    }
29490
29491    return finishProcessingFn(null, segment);
29492  };
29493};
29494
29495/**
29496 * Decrypt the segment via the decryption web worker
29497 *
29498 * @param {WebWorker} decrypter - a WebWorker interface to AES-128 decryption routines
29499 * @param {Object} segment - a simplified copy of the segmentInfo object
29500 *                           from SegmentLoader
29501 * @param {Function} doneFn - a callback that is executed after decryption has completed
29502 */
29503var decryptSegment = function decryptSegment(decrypter, segment, doneFn) {
29504  var decryptionHandler = function decryptionHandler(event) {
29505    if (event.data.source === segment.requestId) {
29506      decrypter.removeEventListener('message', decryptionHandler);
29507      var decrypted = event.data.decrypted;
29508
29509      segment.bytes = new Uint8Array(decrypted.bytes, decrypted.byteOffset, decrypted.byteLength);
29510      return doneFn(null, segment);
29511    }
29512  };
29513
29514  decrypter.addEventListener('message', decryptionHandler);
29515
29516  // this is an encrypted segment
29517  // incrementally decrypt the segment
29518  decrypter.postMessage((0, _binUtils.createTransferableMessage)({
29519    source: segment.requestId,
29520    encrypted: segment.encryptedBytes,
29521    key: segment.key.bytes,
29522    iv: segment.key.iv
29523  }), [segment.encryptedBytes.buffer, segment.key.bytes.buffer]);
29524};
29525
29526/**
29527 * The purpose of this function is to get the most pertinent error from the
29528 * array of errors.
29529 * For instance if a timeout and two aborts occur, then the aborts were
29530 * likely triggered by the timeout so return that error object.
29531 */
29532var getMostImportantError = function getMostImportantError(errors) {
29533  return errors.reduce(function (prev, err) {
29534    return err.code > prev.code ? err : prev;
29535  });
29536};
29537
29538/**
29539 * This function waits for all XHRs to finish (with either success or failure)
29540 * before continueing processing via it's callback. The function gathers errors
29541 * from each request into a single errors array so that the error status for
29542 * each request can be examined later.
29543 *
29544 * @param {Object} activeXhrs - an object that tracks all XHR requests
29545 * @param {WebWorker} decrypter - a WebWorker interface to AES-128 decryption routines
29546 * @param {Function} doneFn - a callback that is executed after all resources have been
29547 *                            downloaded and any decryption completed
29548 */
29549var waitForCompletion = function waitForCompletion(activeXhrs, decrypter, doneFn) {
29550  var errors = [];
29551  var count = 0;
29552
29553  return function (error, segment) {
29554    if (error) {
29555      // If there are errors, we have to abort any outstanding requests
29556      abortAll(activeXhrs);
29557      errors.push(error);
29558    }
29559    count += 1;
29560
29561    if (count === activeXhrs.length) {
29562      // Keep track of when *all* of the requests have completed
29563      segment.endOfAllRequests = Date.now();
29564
29565      if (errors.length > 0) {
29566        var worstError = getMostImportantError(errors);
29567
29568        return doneFn(worstError, segment);
29569      }
29570      if (segment.encryptedBytes) {
29571        return decryptSegment(decrypter, segment, doneFn);
29572      }
29573      // Otherwise, everything is ready just continue
29574      return doneFn(null, segment);
29575    }
29576  };
29577};
29578
29579/**
29580 * Simple progress event callback handler that gathers some stats before
29581 * executing a provided callback with the `segment` object
29582 *
29583 * @param {Object} segment - a simplified copy of the segmentInfo object
29584 *                           from SegmentLoader
29585 * @param {Function} progressFn - a callback that is executed each time a progress event
29586 *                                is received
29587 * @param {Event} event - the progress event object from XMLHttpRequest
29588 */
29589var handleProgress = function handleProgress(segment, progressFn) {
29590  return function (event) {
29591    segment.stats = _videoJs2['default'].mergeOptions(segment.stats, getProgressStats(event));
29592
29593    // record the time that we receive the first byte of data
29594    if (!segment.stats.firstBytesReceivedAt && segment.stats.bytesReceived) {
29595      segment.stats.firstBytesReceivedAt = Date.now();
29596    }
29597
29598    return progressFn(event, segment);
29599  };
29600};
29601
29602/**
29603 * Load all resources and does any processing necessary for a media-segment
29604 *
29605 * Features:
29606 *   decrypts the media-segment if it has a key uri and an iv
29607 *   aborts *all* requests if *any* one request fails
29608 *
29609 * The segment object, at minimum, has the following format:
29610 * {
29611 *   resolvedUri: String,
29612 *   [byterange]: {
29613 *     offset: Number,
29614 *     length: Number
29615 *   },
29616 *   [key]: {
29617 *     resolvedUri: String
29618 *     [byterange]: {
29619 *       offset: Number,
29620 *       length: Number
29621 *     },
29622 *     iv: {
29623 *       bytes: Uint32Array
29624 *     }
29625 *   },
29626 *   [map]: {
29627 *     resolvedUri: String,
29628 *     [byterange]: {
29629 *       offset: Number,
29630 *       length: Number
29631 *     },
29632 *     [bytes]: Uint8Array
29633 *   }
29634 * }
29635 * ...where [name] denotes optional properties
29636 *
29637 * @param {Function} xhr - an instance of the xhr wrapper in xhr.js
29638 * @param {Object} xhrOptions - the base options to provide to all xhr requests
29639 * @param {WebWorker} decryptionWorker - a WebWorker interface to AES-128
29640 *                                       decryption routines
29641 * @param {Object} segment - a simplified copy of the segmentInfo object
29642 *                           from SegmentLoader
29643 * @param {Function} progressFn - a callback that receives progress events from the main
29644 *                                segment's xhr request
29645 * @param {Function} doneFn - a callback that is executed only once all requests have
29646 *                            succeeded or failed
29647 * @returns {Function} a function that, when invoked, immediately aborts all
29648 *                     outstanding requests
29649 */
29650var mediaSegmentRequest = function mediaSegmentRequest(xhr, xhrOptions, decryptionWorker, segment, progressFn, doneFn) {
29651  var activeXhrs = [];
29652  var finishProcessingFn = waitForCompletion(activeXhrs, decryptionWorker, doneFn);
29653
29654  // optionally, request the decryption key
29655  if (segment.key) {
29656    var keyRequestOptions = _videoJs2['default'].mergeOptions(xhrOptions, {
29657      uri: segment.key.resolvedUri,
29658      responseType: 'arraybuffer'
29659    });
29660    var keyRequestCallback = handleKeyResponse(segment, finishProcessingFn);
29661    var keyXhr = xhr(keyRequestOptions, keyRequestCallback);
29662
29663    activeXhrs.push(keyXhr);
29664  }
29665
29666  // optionally, request the associated media init segment
29667  if (segment.map && !segment.map.bytes) {
29668    var initSegmentOptions = _videoJs2['default'].mergeOptions(xhrOptions, {
29669      uri: segment.map.resolvedUri,
29670      responseType: 'arraybuffer',
29671      headers: segmentXhrHeaders(segment.map)
29672    });
29673    var initSegmentRequestCallback = handleInitSegmentResponse(segment, finishProcessingFn);
29674    var initSegmentXhr = xhr(initSegmentOptions, initSegmentRequestCallback);
29675
29676    activeXhrs.push(initSegmentXhr);
29677  }
29678
29679  var segmentRequestOptions = _videoJs2['default'].mergeOptions(xhrOptions, {
29680    uri: segment.resolvedUri,
29681    responseType: 'arraybuffer',
29682    headers: segmentXhrHeaders(segment)
29683  });
29684  var segmentRequestCallback = handleSegmentResponse(segment, finishProcessingFn);
29685  var segmentXhr = xhr(segmentRequestOptions, segmentRequestCallback);
29686
29687  segmentXhr.addEventListener('progress', handleProgress(segment, progressFn));
29688  activeXhrs.push(segmentXhr);
29689
29690  return function () {
29691    return abortAll(activeXhrs);
29692  };
29693};
29694exports.mediaSegmentRequest = mediaSegmentRequest;
29695}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
29696},{"./bin-utils":2}],8:[function(require,module,exports){
29697(function (global){
29698/**
29699 * @file playback-watcher.js
29700 *
29701 * Playback starts, and now my watch begins. It shall not end until my death. I shall
29702 * take no wait, hold no uncleared timeouts, father no bad seeks. I shall wear no crowns
29703 * and win no glory. I shall live and die at my post. I am the corrector of the underflow.
29704 * I am the watcher of gaps. I am the shield that guards the realms of seekable. I pledge
29705 * my life and honor to the Playback Watch, for this Player and all the Players to come.
29706 */
29707
29708'use strict';
29709
29710Object.defineProperty(exports, '__esModule', {
29711  value: true
29712});
29713
29714var _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; }; })();
29715
29716function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
29717
29718function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
29719
29720var _globalWindow = require('global/window');
29721
29722var _globalWindow2 = _interopRequireDefault(_globalWindow);
29723
29724var _ranges = require('./ranges');
29725
29726var _ranges2 = _interopRequireDefault(_ranges);
29727
29728var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
29729
29730var _videoJs2 = _interopRequireDefault(_videoJs);
29731
29732// Set of events that reset the playback-watcher time check logic and clear the timeout
29733var timerCancelEvents = ['seeking', 'seeked', 'pause', 'playing', 'error'];
29734
29735/**
29736 * @class PlaybackWatcher
29737 */
29738
29739var PlaybackWatcher = (function () {
29740  /**
29741   * Represents an PlaybackWatcher object.
29742   * @constructor
29743   * @param {object} options an object that includes the tech and settings
29744   */
29745
29746  function PlaybackWatcher(options) {
29747    var _this = this;
29748
29749    _classCallCheck(this, PlaybackWatcher);
29750
29751    this.tech_ = options.tech;
29752    this.seekable = options.seekable;
29753
29754    this.consecutiveUpdates = 0;
29755    this.lastRecordedTime = null;
29756    this.timer_ = null;
29757    this.checkCurrentTimeTimeout_ = null;
29758
29759    if (options.debug) {
29760      this.logger_ = _videoJs2['default'].log.bind(_videoJs2['default'], 'playback-watcher ->');
29761    }
29762    this.logger_('initialize');
29763
29764    var canPlayHandler = function canPlayHandler() {
29765      return _this.monitorCurrentTime_();
29766    };
29767    var waitingHandler = function waitingHandler() {
29768      return _this.techWaiting_();
29769    };
29770    var cancelTimerHandler = function cancelTimerHandler() {
29771      return _this.cancelTimer_();
29772    };
29773    var fixesBadSeeksHandler = function fixesBadSeeksHandler() {
29774      return _this.fixesBadSeeks_();
29775    };
29776
29777    this.tech_.on('seekablechanged', fixesBadSeeksHandler);
29778    this.tech_.on('waiting', waitingHandler);
29779    this.tech_.on(timerCancelEvents, cancelTimerHandler);
29780    this.tech_.on('canplay', canPlayHandler);
29781
29782    // Define the dispose function to clean up our events
29783    this.dispose = function () {
29784      _this.logger_('dispose');
29785      _this.tech_.off('seekablechanged', fixesBadSeeksHandler);
29786      _this.tech_.off('waiting', waitingHandler);
29787      _this.tech_.off(timerCancelEvents, cancelTimerHandler);
29788      _this.tech_.off('canplay', canPlayHandler);
29789      if (_this.checkCurrentTimeTimeout_) {
29790        _globalWindow2['default'].clearTimeout(_this.checkCurrentTimeTimeout_);
29791      }
29792      _this.cancelTimer_();
29793    };
29794  }
29795
29796  /**
29797   * Periodically check current time to see if playback stopped
29798   *
29799   * @private
29800   */
29801
29802  _createClass(PlaybackWatcher, [{
29803    key: 'monitorCurrentTime_',
29804    value: function monitorCurrentTime_() {
29805      this.checkCurrentTime_();
29806
29807      if (this.checkCurrentTimeTimeout_) {
29808        _globalWindow2['default'].clearTimeout(this.checkCurrentTimeTimeout_);
29809      }
29810
29811      // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
29812      this.checkCurrentTimeTimeout_ = _globalWindow2['default'].setTimeout(this.monitorCurrentTime_.bind(this), 250);
29813    }
29814
29815    /**
29816     * The purpose of this function is to emulate the "waiting" event on
29817     * browsers that do not emit it when they are waiting for more
29818     * data to continue playback
29819     *
29820     * @private
29821     */
29822  }, {
29823    key: 'checkCurrentTime_',
29824    value: function checkCurrentTime_() {
29825      if (this.tech_.seeking() && this.fixesBadSeeks_()) {
29826        this.consecutiveUpdates = 0;
29827        this.lastRecordedTime = this.tech_.currentTime();
29828        return;
29829      }
29830
29831      if (this.tech_.paused() || this.tech_.seeking()) {
29832        return;
29833      }
29834
29835      var currentTime = this.tech_.currentTime();
29836      var buffered = this.tech_.buffered();
29837
29838      if (this.lastRecordedTime === currentTime && (!buffered.length || currentTime + 
298380.1 >= buffered.end(buffered.length - 1))) {
29839        // If current time is at the end of the final buffered region, then any playback
29840        // stall is most likely caused by buffering in a low bandwidth environment. The tech
29841        // should fire a `waiting` event in this scenario, but due to browser and tech
vendor: 13,900 bytes, lines 29842-30227
29842        // inconsistencies (e.g. The Flash tech does not fire a `waiting` event when the end
29843        // of the buffer is reached and has fallen off the live window). Calling
29844        // `techWaiting_` here allows us to simulate responding to a native `waiting` event
29845        // when the tech fails to emit one.
29846        return this.techWaiting_();
29847      }
29848
29849      if (this.consecutiveUpdates >= 5 && currentTime === this.lastRecordedTime) {
29850        this.consecutiveUpdates++;
29851        this.waiting_();
29852      } else if (currentTime === this.lastRecordedTime) {
29853        this.consecutiveUpdates++;
29854      } else {
29855        this.consecutiveUpdates = 0;
29856        this.lastRecordedTime = currentTime;
29857      }
29858    }
29859
29860    /**
29861     * Cancels any pending timers and resets the 'timeupdate' mechanism
29862     * designed to detect that we are stalled
29863     *
29864     * @private
29865     */
29866  }, {
29867    key: 'cancelTimer_',
29868    value: function cancelTimer_() {
29869      this.consecutiveUpdates = 0;
29870
29871      if (this.timer_) {
29872        this.logger_('cancelTimer_');
29873        clearTimeout(this.timer_);
29874      }
29875
29876      this.timer_ = null;
29877    }
29878
29879    /**
29880     * Fixes situations where there's a bad seek
29881     *
29882     * @return {Boolean} whether an action was taken to fix the seek
29883     * @private
29884     */
29885  }, {
29886    key: 'fixesBadSeeks_',
29887    value: function fixesBadSeeks_() {
29888      var seeking = this.tech_.seeking();
29889      var seekable = this.seekable();
29890      var currentTime = this.tech_.currentTime();
29891      var seekTo = undefined;
29892
29893      if (seeking && this.afterSeekableWindow_(seekable, currentTime)) {
29894        var seekableEnd = seekable.end(seekable.length - 1);
29895
29896        // sync to live point (if VOD, our seekable was updated and we're simply adjusting)
29897        seekTo = seekableEnd;
29898      }
29899
29900      if (seeking && this.beforeSeekableWindow_(seekable, currentTime)) {
29901        var seekableStart = seekable.start(0);
29902
29903        // sync to the beginning of the live window
29904        // provide a buffer of .1 seconds to handle rounding/imprecise numbers
29905        seekTo = seekableStart + 0.1;
29906      }
29907
29908      if (typeof seekTo !== 'undefined') {
29909        this.logger_('Trying to seek outside of seekable at time ' + currentTime + ' with ' + ('seekable range ' + _ranges2['default'].printableRange(seekable) + '. Seeking to ') + (seekTo + '.'));
29910
29911        this.tech_.setCurrentTime(seekTo);
29912        return true;
29913      }
29914
29915      return false;
29916    }
29917
29918    /**
29919     * Handler for situations when we determine the player is waiting.
29920     *
29921     * @private
29922     */
29923  }, {
29924    key: 'waiting_',
29925    value: function waiting_() {
29926      if (this.techWaiting_()) {
29927        return;
29928      }
29929
29930      // All tech waiting checks failed. Use last resort correction
29931      var currentTime = this.tech_.currentTime();
29932      var buffered = this.tech_.buffered();
29933      var currentRange = _ranges2['default'].findRange(buffered, currentTime);
29934
29935      // Sometimes the player can stall for unknown reasons within a contiguous buffered
29936      // region with no indication that anything is amiss (seen in Firefox). Seeking to
29937      // currentTime is usually enough to kickstart the player. This checks that the player
29938      // is currently within a buffered region before attempting a corrective seek.
29939      // Chrome does not appear to continue `timeupdate` events after a `waiting` event
29940      // until there is ~ 3 seconds of forward buffer available. PlaybackWatcher should also
29941      // make sure there is ~3 seconds of forward buffer before taking any corrective action
29942      // to avoid triggering an `unknownwaiting` event when the network is slow.
29943      if (currentRange.length && currentTime + 3 <= currentRange.end(0)) {
29944        this.cancelTimer_();
29945        this.tech_.setCurrentTime(currentTime);
29946
29947        this.logger_('Stopped at ' + currentTime + ' while inside a buffered region ' + ('[' + currentRange.start(0) + ' -> ' + currentRange.end(0) + ']. Attempting to resume ') + 'playback by seeking to the current time.');
29948
29949        // unknown waiting corrections may be useful for monitoring QoS
29950        this.tech_.trigger({ type: 'usage', name: 'hls-unknown-waiting' });
29951        return;
29952      }
29953    }
29954
29955    /**
29956     * Handler for situations when the tech fires a `waiting` event
29957     *
29958     * @return {Boolean}
29959     *         True if an action (or none) was needed to correct the waiting. False if no
29960     *         checks passed
29961     * @private
29962     */
29963  }, {
29964    key: 'techWaiting_',
29965    value: function techWaiting_() {
29966      var seekable = this.seekable();
29967      var currentTime = this.tech_.currentTime();
29968
29969      if (this.tech_.seeking() && this.fixesBadSeeks_()) {
29970        // Tech is seeking or bad seek fixed, no action needed
29971        return true;
29972      }
29973
29974      if (this.tech_.seeking() || this.timer_ !== null) {
29975        // Tech is seeking or already waiting on another action, no action needed
29976        return true;
29977      }
29978
29979      if (this.beforeSeekableWindow_(seekable, currentTime)) {
29980        var livePoint = seekable.end(seekable.length - 1);
29981
29982        this.logger_('Fell out of live window at time ' + currentTime + '. Seeking to ' + ('live point (seekable end) ' + livePoint));
29983        this.cancelTimer_();
29984        this.tech_.setCurrentTime(livePoint);
29985
29986        // live window resyncs may be useful for monitoring QoS
29987        this.tech_.trigger({ type: 'usage', name: 'hls-live-resync' });
29988        return true;
29989      }
29990
29991      var buffered = this.tech_.buffered();
29992      var nextRange = _ranges2['default'].findNextRange(buffered, currentTime);
29993
29994      if (this.videoUnderflow_(nextRange, buffered, currentTime)) {
29995        // Even though the video underflowed and was stuck in a gap, the audio overplayed
29996        // the gap, leading currentTime into a buffered range. Seeking to currentTime
29997        // allows the video to catch up to the audio position without losing any audio
29998        // (only suffering ~3 seconds of frozen video and a pause in audio playback).
29999        this.cancelTimer_();
30000        this.tech_.setCurrentTime(currentTime);
30001
30002        // video underflow may be useful for monitoring QoS
30003        this.tech_.trigger({ type: 'usage', name: 'hls-video-underflow' });
30004        return true;
30005      }
30006
30007      // check for gap
30008      if (nextRange.length > 0) {
30009        var difference = nextRange.start(0) - currentTime;
30010
30011        this.logger_('Stopped at ' + currentTime + ', setting timer for ' + difference + ', seeking ' + ('to ' + nextRange.start(0)));
30012
30013        this.timer_ = setTimeout(this.skipTheGap_.bind(this), difference * 1000, currentTime);
30014        return true;
30015      }
30016
30017      // All checks failed. Returning false to indicate failure to correct waiting
30018      return false;
30019    }
30020  }, {
30021    key: 'afterSeekableWindow_',
30022    value: function afterSeekableWindow_(seekable, currentTime) {
30023      if (!seekable.length) {
30024        // we can't make a solid case if there's no seekable, default to false
30025        return false;
30026      }
30027
30028      // provide a buffer of .1 seconds to handle rounding/imprecise numbers
30029      if (currentTime > seekable.end(seekable.length - 1) + 0.1) {
30030        return true;
30031      }
30032
30033      return false;
30034    }
30035  }, {
30036    key: 'beforeSeekableWindow_',
30037    value: function beforeSeekableWindow_(seekable, currentTime) {
30038      if (seekable.length &&
30039      // can't fall before 0 and 0 seekable start identifies VOD stream
30040      seekable.start(0) > 0 &&
30041      // provide a buffer of .1 seconds to handle rounding/imprecise numbers
30042      currentTime < seekable.start(0) - 0.1) {
30043        return true;
30044      }
30045
30046      return false;
30047    }
30048  }, {
30049    key: 'videoUnderflow_',
30050    value: function videoUnderflow_(nextRange, buffered, currentTime) {
30051      if (nextRange.length === 0) {
30052        // Even if there is no available next range, there is still a possibility we are
30053        // stuck in a gap due to video underflow.
30054        var gap = this.gapFromVideoUnderflow_(buffered, currentTime);
30055
30056        if (gap) {
30057          this.logger_('Encountered a gap in video from ' + gap.start + ' to ' + gap.end + '. ' + ('Seeking to current time ' + currentTime));
30058
30059          return true;
30060        }
30061      }
30062
30063      return false;
30064    }
30065
30066    /**
30067     * Timer callback. If playback still has not proceeded, then we seek
30068     * to the start of the next buffered region.
30069     *
30070     * @private
30071     */
30072  }, {
30073    key: 'skipTheGap_',
30074    value: function skipTheGap_(scheduledCurrentTime) {
30075      var buffered = this.tech_.buffered();
30076      var currentTime = this.tech_.currentTime();
30077      var nextRange = _ranges2['default'].findNextRange(buffered, currentTime);
30078
30079      this.cancelTimer_();
30080
30081      if (nextRange.length === 0 || currentTime !== scheduledCurrentTime) {
30082        return;
30083      }
30084
30085      this.logger_('skipTheGap_:', 'currentTime:', currentTime, 'scheduled currentTime:', scheduledCurrentTime, 'nextRange start:', nextRange.start(0));
30086
30087      // only seek if we still have not played
30088      this.tech_.setCurrentTime(nextRange.start(0) + _ranges2['default'].TIME_FUDGE_FACTOR);
30089
30090      this.tech_.trigger({ type: 'usage', name: 'hls-gap-skip' });
30091    }
30092  }, {
30093    key: 'gapFromVideoUnderflow_',
30094    value: function gapFromVideoUnderflow_(buffered, currentTime) {
30095      // At least in Chrome, if there is a gap in the video buffer, the audio will continue
30096      // playing for ~3 seconds after the video gap starts. This is done to account for
30097      // video buffer underflow/underrun (note that this is not done when there is audio
30098      // buffer underflow/underrun -- in that case the video will stop as soon as it
30099      // encounters the gap, as audio stalls are more noticeable/jarring to a user than
30100      // video stalls). The player's time will reflect the playthrough of audio, so the
30101      // time will appear as if we are in a buffered region, even if we are stuck in a
30102      // "gap."
30103      //
30104      // Example:
30105      // video buffer:   0 => 10.1, 10.2 => 20
30106      // audio buffer:   0 => 20
30107      // overall buffer: 0 => 10.1, 10.2 => 20
30108      // current time: 13
30109      //
30110      // Chrome's video froze at 10 seconds, where the video buffer encountered the gap,
30111      // however, the audio continued playing until it reached ~3 seconds past the gap
30112      // (13 seconds), at which point it stops as well. Since current time is past the
30113      // gap, findNextRange will return no ranges.
30114      //
30115      // To check for this issue, we see if there is a gap that starts somewhere within
30116      // a 3 second range (3 seconds +/- 1 second) back from our current time.
30117      var gaps = _ranges2['default'].findGaps(buffered);
30118
30119      for (var i = 0; i < gaps.length; i++) {
30120        var start = gaps.start(i);
30121        var end = gaps.end(i);
30122
30123        // gap is starts no more than 4 seconds back
30124        if (currentTime - start < 4 && currentTime - start > 2) {
30125          return {
30126            start: start,
30127            end: end
30128          };
30129        }
30130      }
30131
30132      return null;
30133    }
30134
30135    /**
30136     * A debugging logger noop that is set to console.log only if debugging
30137     * is enabled globally
30138     *
30139     * @private
30140     */
30141  }, {
30142    key: 'logger_',
30143    value: function logger_() {}
30144  }]);
30145
30146  return PlaybackWatcher;
30147})();
30148
30149exports['default'] = PlaybackWatcher;
30150module.exports = exports['default'];
30151}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
30152},{"./ranges":12,"global/window":32}],9:[function(require,module,exports){
30153(function (global){
30154/**
30155 * @file playlist-loader.js
30156 *
30157 * A state machine that manages the loading, caching, and updating of
30158 * M3U8 playlists.
30159 *
30160 */
30161'use strict';
30162
30163Object.defineProperty(exports, '__esModule', {
30164  value: true
30165});
30166
30167function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
30168
30169var _resolveUrl = require('./resolve-url');
30170
30171var _resolveUrl2 = _interopRequireDefault(_resolveUrl);
30172
30173var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
30174
30175var _playlistJs = require('./playlist.js');
30176
30177var _m3u8Parser = require('m3u8-parser');
30178
30179var _m3u8Parser2 = _interopRequireDefault(_m3u8Parser);
30180
30181var _globalWindow = require('global/window');
30182
30183var _globalWindow2 = _interopRequireDefault(_globalWindow);
30184
30185/**
30186  * Returns a new array of segments that is the result of merging
30187  * properties from an older list of segments onto an updated
30188  * list. No properties on the updated playlist will be overridden.
30189  *
30190  * @param {Array} original the outdated list of segments
30191  * @param {Array} update the updated list of segments
30192  * @param {Number=} offset the index of the first update
30193  * segment in the original segment list. For non-live playlists,
30194  * this should always be zero and does not need to be
30195  * specified. For live playlists, it should be the difference
30196  * between the media sequence numbers in the original and updated
30197  * playlists.
30198  * @return a list of merged segment objects
30199  */
30200var updateSegments = function updateSegments(original, update, offset) {
30201  var result = update.slice();
30202  var length = undefined;
30203  var i = undefined;
30204
30205  offset = offset || 0;
30206  length = Math.min(original.length, update.length + offset);
30207
30208  for (i = offset; i < length; i++) {
30209    result[i - offset] = (0, _videoJs.mergeOptions)(original[i], result[i - offset]);
30210  }
30211  return result;
30212};
30213
30214/**
30215  * Returns a new master playlist that is the result of merging an
30216  * updated media playlist into the original version. If the
30217  * updated media playlist does not match any of the playlist
30218  * entries in the original master playlist, null is returned.
30219  *
30220  * @param {Object} master a parsed master M3U8 object
30221  * @param {Object} media a parsed media M3U8 object
30222  * @return {Object} a new object that represents the original
30223  * master playlist with the updated media playlist merged in, or
30224  * null if the merge produced no change.
30225  */
30226var updateMaster = function updateMaster(master, media) {
30227  var changed = false;
30228  var result = (0, _videoJs.mergeOptions)(master, {});
30229  var i = master.playlists.length;
30230  var playlist = undefined;
30231  var segment = undefined;
30232  var j = undefined;
30233
30234  while (i--) {
30235    playlist = result.playlists[i];
30236    if (playlist.uri === media.uri) {
30237      // consider the playlist unchanged if the number of segments
30238      // are equal and the media sequence number is unchanged
30239      if (playlist.segments && media.segments && playlist.segments.length === media.segments.length && playlist.mediaSequence === media.mediaSequence) {
30240        continue;
30241      }
30242
30243      result.playlists[i] = (0, _videoJs.mergeOptions)(playlist, media);
30244      result.playlists[media.uri] = result.playlists[i];
30245
30246      // if the update could overlap existing segment information,
30247      // merge the two lists
30248      if (playlist.segments) {
30249        result.playlists[i].segments = updateSegments(playlist.segments, media.segments, media.mediaSequence - playlist.mediaSequence);
30250      }
30251      // resolve any missing segment and key URIs
30252      j = 0;
30253      if (result.playlists[i].segments) {
30254        j = result.playlists[i].segments.length;
30255      }
30256      while (j--) {
30257        segment = result.playlists[i].segments[j];
30258        if (!segment.resolvedUri) {
30259          segment.resolvedUri = (0, _resolveUrl2['default'])(playlist.resolvedUri, segment.uri);
30260        }
30261        if (segment.key && !segment.key.resolvedUri) {
30262          segment.key.resolvedUri = (0, _resolveUrl2['default'])(playlist.resolvedUri, segment.key.uri);
30263        }
30264        if (segment.map && !segment.map.resolvedUri) {
30265          segment.map.resolvedUri = (0, _resolveUrl2['default'])(playlist.resolvedUri, segment.map.uri);
30266        }
30267      }
30268      changed = true;
30269    }
30270  }
30271  return changed ? result : null;
30272};
30273
30274/**
30275 * Load a playlist from a remote location
30276 *
30277 * @class PlaylistLoader
30278 * @extends Stream
30279 * @param {String} srcUrl the url to start with
30280 * @param {Boolean} withCredentials the withCredentials xhr option
30281 * @constructor
30282 */
30283var PlaylistLoader = function PlaylistLoader(srcUrl, hls, withCredentials) {
30284  var _this = this;
30285
30286  /* eslint-disable consistent-this */
30287  var loader = this;
30288  /* eslint-enable consistent-this */
30289  var mediaUpdateTimeout = undefined;
30290  var request = undefined;
30291  var playlistRequestError = undefined;
30292  var haveMetadata = undefined;
30293
30294  PlaylistLoader.prototype.constructor.call(this);
30295
30296  this.hls_ = hls;
30297
30298  if (!srcUrl) {
30299    throw new Error('A non-empty playlist URL is required');
30300  }
30301
30302  playlistRequestError = function (xhr, url, startingState) {
30303    loader.setBandwidth(request || xhr);
30304
30305    // any in-flight request is now finished
30306    request = null;
30307
30308    if (startingState) {
30309      loader.state = startingState;
30310    }
30311
30312    loader.error = {
30313      playlist: loader.master.playlists[url],
30314      status: xhr.status,
30315      message: 'HLS playlist request error at URL: ' + url,
30316      responseText: xhr.responseText,
30317      code: xhr.status >= 500 ? 4 : 2
30318    };
30319
30320    loader.trigger('error');
30321  };
30322
30323  // update the playlist loader's state in response to a new or
30324  // updated playlist.
30325  haveMetadata = function (xhr, url) {
30326    var parser = undefined;
30327    var refreshDelay = undefined;
30328    var update = undefined;
30329
30330    loader.setBandwidth(request || xhr);
30331
30332    // any in-flight request is now finished
30333    request = null;
30334
30335    loader.state = 'HAVE_METADATA';
30336
30337    parser = new _m3u8Parser2['default'].Parser();
30338    parser.push(xhr.responseText);
30339    parser.end();
30340    parser.manifest.uri = url;
30341    // m3u8-parser does not attach an attributes property to media playlists so make
30342    // sure that the property is attached to avoid undefined reference errors
30343    parser.manifest.attributes = parser.manifest.attributes || {};
30344
30345    // merge this playlist into the master
30346    update = updateMaster(loader.master, parser.manifest);
30347    refreshDelay = (parser.manifest.targetDuration || 10) * 1000;
30348    loader.targetDuration = parser.manifest.targetDuration;
30349    if (update) {
30350      loader.master = update;
30351      loader.media_ = loader.master.playlists[parser.manifest.uri];
30352    } else {
30353      // if the playlist is unchanged since the last reload,
30354      // try again after half the target duration
30355      refreshDelay /= 2;
30356      loader.trigger('playlistunchanged');
30357    }
30358
30359    // refresh live playlists after a target duration passes
30360    if (!loader.media().endList) {
30361      _globalWindow2['default'].clearTimeout(mediaUpdateTimeout);
30362      mediaUpdateTimeout = _globalWindow2['default'].setTimeout(function () {
30363        loader.trigger('mediaupdatetimeout');
30364      }, refreshDelay);
30365    }
30366
30367    loader.trigger('loadedplaylist');
30368  };
30369
30370  // initialize the loader state
30371  loader.state = 'HAVE_NOTHING';
30372
30373  /**
30374   * Abort any outstanding work and clean up.
30375   */
30376  loader.dispose = function () {
30377    loader.stopRequest();
30378    _globalWindow2['default'].clearTimeout(mediaUpdateTimeout);
30379    loader.off();
30380  };
30381
30382  loader.stopRequest = function () {
30383    if (request) {
30384      var oldRequest = request;
30385
30386      request = null;
30387      oldRequest.onreadystatechange = null;
30388      oldRequest.abort();
30389    }
30390  };
30391
30392  /**
30393   * Returns the number of enabled playlists on the master playlist object
30394   *
30395   * @return {Number} number of eneabled playlists
30396   */
30397  loader.enabledPlaylists_ = function () {
30398    return loader.master.playlists.filter(_playlistJs.isEnabled).length;
30399  };
30400
30401  /**
30402   * Returns whether the current playlist is the lowest rendition
30403   *
30404   * @return {Boolean} true if on lowest rendition
30405   */
30406  loader.isLowestEnabledRendition_ = function () {
30407    if (loader.master.playlists.length === 1) {
30408      return true;
30409    }
30410
30411    var media = loader.media();
30412
30413    var currentBandwidth = media.attributes.BANDWIDTH || Number.MAX_VALUE;
30414
30415    return loader.master.playlists.filter(function (playlist) {
30416      var enabled = (0, _playlistJs.isEnabled)(playlist);
30417
30418      if (!enabled) {
30419        return false;
30420      }
30421
30422      return (playlist.attributes.BANDWIDTH || 0) < currentBandwidth;
30423    }).length === 0;
30424  };
30425
30426  /**
30427   * Returns whether the current playlist is the final available rendition
30428   *
30429   * @return {Boolean} true if on final rendition
30430   */
30431  loader.isFinalRendition_ = function () {
30432    return loader.master.playlists.filter(_playlistJs.isEnabled).length === 1;
30433  };
30434
30435  /**
30436   * When called without any arguments, returns the currently
30437   * active media playlist. When called with a single argument,
30438   * triggers the playlist loader to asynchronously switch to the
30439   * specified media playlist. Calling this method while the
30440   * loader is in the HAVE_NOTHING causes an error to be emitted
30441   * but otherwise has no effect.
30442   *
30443   * @param {Object=} playlist the parsed media playlist
30444   * object to switch to
30445   * @return {Playlist} the current loaded media
30446   */
30447  loader.media = function (playlist) {
30448    var startingState = loader.state;
30449    var mediaChange = undefined;
30450
30451    // getter
30452    if (!playlist) {
30453      return loader.media_;
30454    }
30455
30456    // setter
30457    if (loader.state === 'HAVE_NOTHING') {
30458      throw new Error('Cannot switch media playlist from ' + loader.state);
30459    }
30460
30461    // find the playlist object if the target playlist has been
30462    // specified by URI
30463    if (typeof playlist === 'string') {
30464      if (!loader.master.playlists[playlist]) {
30465        throw new Error('Unknown playlist URI: ' + playlist);
30466      }
30467      playlist = loader.master.playlists[playlist];
30468    }
30469
30470    mediaChange = !loader.media_ || playlist.uri !== loader.media_.uri;
30471
30472    // switch to fully loaded playlists immediately
30473    if (loader.master.playlists[playlist.uri].endList) {
30474      // abort outstanding playlist requests
30475      if (request) {
30476        request.onreadystatechange = null;
30477        request.abort();
30478        request = null;
30479      }
30480      loader.state = 'HAVE_METADATA';
30481      loader.media_ = playlist;
30482
30483      // trigger media change if the active media has been updated
30484      if (mediaChange) {
30485        loader.trigger('mediachanging');
30486        loader.trigger('mediachange');
30487      }
30488      return;
30489    }
30490
30491    // switching to the active playlist is a no-op
30492    if (!mediaChange) {
30493      return;
30494    }
30495
30496    loader.state = 'SWITCHING_MEDIA';
30497
30498    // there is already an outstanding playlist request
30499    if (request) {
30500      if ((0, _resolveUrl2['default'])(loader.master.uri, playlist.uri) === request.url) {
30501        // requesting to switch to the same playlist multiple times
30502        // has no effect after the first
30503        return;
30504      }
30505      request.onreadystatechange = null;
30506      request.abort();
30507      request = null;
30508    }
30509
30510    // request the new playlist
30511    if (this.media_) {
30512      this.trigger('mediachanging');
30513    }
30514
30515    request = this.hls_.xhr({
30516      uri: (0, _resolveUrl2['default'])(loader.master.uri, playlist.uri),
30517      withCredentials: withCredentials
30518    }, function (error, req) {
30519      // disposed
30520      if (!request) {
30521        return;
30522      }
30523
30524      if (error) {
30525        return playlistRequestError(request, playlist.uri, startingState);
30526      }
30527
30528      haveMetadata(req, playlist.uri);
30529
30530      // fire loadedmetadata the first time a media playlist is loaded
30531      if (startingState === 'HAVE_MASTER') {
30532        loader.trigger('loadedmetadata');
30533      } else {
30534        loader.trigger('mediachange');
30535      }
30536    });
30537  };
30538
30539  /**
30540   * set the bandwidth on an xhr to the bandwidth on the playlist
30541   */
30542  loader.setBandwidth = function (xhr) {
30543    loader.bandwidth = xhr.bandwidth;
30544  };
30545
30546  // live playlist staleness timeout
30547  loader.on('mediaupdatetimeout', function () {
30548    if (loader.state !== 'HAVE_METADATA') {
30549      // only refresh the media playlist if no other activity is going on
30550      return;
30551    }
30552
30553    loader.state = 'HAVE_CURRENT_METADATA';
30554
30555    request = this.hls_.xhr({
30556      uri: (0, _resolveUrl2['default'])(loader.master.uri, loader.media().uri),
30557      withCredentials: withCredentials
30558    }, function (error, req) {
30559      // disposed
30560      if (!request) {
30561        return;
30562      }
30563
30564      if (error) {
30565        return playlistRequestError(request, loader.media().uri, 'HAVE_METADATA');
30566      }
30567
30568      haveMetadata(request, loader.media().uri);
30569    });
30570  });
30571
30572  /**
30573   * pause loading of the playlist
30574   */
30575  loader.pause = function () {
30576    loader.stopRequest();
30577    _globalWindow2['default'].clearTimeout(mediaUpdateTimeout);
30578    if (loader.state === 'HAVE_NOTHING') {
30579      // If we pause the loader before any data has been retrieved, its as if we never
30580      // started, so reset to an unstarted state.
30581      loader.started = false;
30582    }
30583    // Need to restore state now that no activity is happening
30584    if (loader.state === 'SWITCHING_MEDIA') {
30585      // if the loader was in the process of switching media, it should either return to
30586      // HAVE_MASTER or HAVE_METADATA depending on if the loader has loaded a media
30587      // playlist yet. This is determined by the existence of loader.media_
30588      if (loader.media_) {
30589        loader.state = 'HAVE_METADATA';
30590      } else {
30591        loader.state = 'HAVE_MASTER';
30592      }
30593    } else if (loader.state === 'HAVE_CURRENT_METADATA') {
30594      loader.state = 'HAVE_METADATA';
30595    }
30596  };
30597
30598  /**
30599   * start loading of the playlist
30600   */
30601  loader.load = function (isFinalRendition) {
30602    var media = loader.media();
30603
30604    _globalWindow2['default'].clearTimeout(mediaUpdateTimeout);
30605
30606    if (isFinalRendition) {
30607      var refreshDelay = media ? media.targetDuration / 2 * 1000 : 5 * 1000;
30608
30609      mediaUpdateTimeout = _globalWindow2['default'].setTimeout(loader.load.bind(null, false), refreshDelay);
30610      return;
30611    }
30612
30613    if (!loader.started) {
30614      loader.start();
30615      return;
30616    }
30617
30618    if (media && !media.endList) {
30619      loader.trigger('mediaupdatetimeout');
30620    } else {
30621      loader.trigger('loadedplaylist');
30622    }
30623  };
30624
30625  /**
30626   * start loading of the playlist
30627   */
30628  loader.start = function () {
30629    loader.started = true;
30630
30631    // request the specified URL
30632    request = _this.hls_.xhr({
30633      uri: srcUrl,
30634      withCredentials: withCredentials
30635    }, function (error, req) {
30636      var parser = undefined;
30637      var playlist = undefined;
30638      var i = undefined;
30639
30640      // disposed
30641      if (!request) {
30642        return;
30643      }
30644
30645      // clear the loader's request reference
30646      request = null;
30647
30648      if (error) {
30649        loader.error = {
30650          status: req.status,
30651          message: 'HLS playlist request error at URL: ' + srcUrl,
30652          responseText: req.responseText,
30653          // MEDIA_ERR_NETWORK
30654          code: 2
30655        };
30656        if (loader.state === 'HAVE_NOTHING') {
30657          loader.started = false;
30658        }
30659        return loader.trigger('error');
30660      }
30661
30662      parser = new _m3u8Parser2['default'].Parser();
30663      parser.push(req.responseText);
30664      parser.end();
30665
30666      loader.state = 'HAVE_MASTER';
30667
30668      parser.manifest.uri = srcUrl;
30669
30670      // loaded a master playlist
30671      if (parser.manifest.playlists) {
30672        loader.master = parser.manifest;
30673
30674        // setup by-URI lookups and resolve media playlist URIs
30675        i = loader.master.playlists.length;
30676        while (i--) {
30677          playlist = loader.master.playlists[i];
30678          loader.master.playlists[playlist.uri] = playlist;
30679          playlist.resolvedUri = (0, _resolveUrl2['default'])(loader.master.uri, playlist.uri);
30680
30681          if (!playlist.attributes) {
30682            // Although the spec states an #EXT-X-STREAM-INF tag MUST have a
30683            // BANDWIDTH attribute, we can play the stream without it. This means a poorly
30684            // formatted master playlist may not have an attribute list. An attributes
30685            // property is added here to prevent undefined references when we encounter
30686            // this scenario.
30687            playlist.attributes = {};
30688
30689            _videoJs.log.warn('Invalid playlist STREAM-INF detected. Missing BANDWIDTH attribute.');
30690          }
30691        }
30692
30693        // resolve any media group URIs
30694        ['AUDIO', 'SUBTITLES'].forEach(function (mediaType) {
30695          for (var groupKey in loader.master.mediaGroups[mediaType]) {
30696            for (var labelKey in loader.master.mediaGroups[mediaType][groupKey]) {
30697              var mediaProperties = loader.master.mediaGroups[mediaType][groupKey][labelKey];
30698
30699              if (mediaProperties.uri) {
30700                mediaProperties.resolvedUri = (0, _resolveUrl2['default'])(loader.master.uri, mediaProperties.uri);
30701              }
30702            }
30703          }
30704        });
30705
30706        loader.trigger('loadedplaylist');
30707        if (!request) {
30708          // no media playlist was specifically selected so start
30709          // from the first listed one
30710          loader.media(parser.manifest.playlists[0]);
30711        }
30712        return;
30713      }
30714
30715      // loaded a media playlist
30716      // infer a master playlist if none was previously requested
30717      loader.master = {
30718        mediaGroups: {
30719          'AUDIO': {},
30720          'VIDEO': {},
30721          'CLOSED-CAPTIONS': {},
30722          'SUBTITLES': {}
30723        },
30724        uri: _globalWindow2['default'].location.href,
30725        playlists: [{
30726          uri: srcUrl
30727        }]
30728      };
30729      loader.master.playlists[srcUrl] = loader.master.playlists[0];
30730      loader.master.playlists[0].resolvedUri = srcUrl;
30731      // m3u8-parser does not attach an attributes property to media playlists so make
30732      // sure that the property is attached to avoid undefined reference errors
30733      loader.master.playlists[0].attributes = loader.master.playlists[0].attributes || {};
30734      haveMetadata(req, srcUrl);
30735      return loader.trigger('loadedmetadata');
30736    });
30737  };
30738};
30739
30740PlaylistLoader.prototype = new _videoJs.EventTarget();
30741
30742exports['default'] = PlaylistLoader;
30743module.exports = exports['default'];
30744}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
30745},{"./playlist.js":11,"./resolve-url":15,"global/window":32,"m3u8-parser":33}],10:[function(require,module,exports){
30746'use strict';
30747
30748Object.defineProperty(exports, '__esModule', {
30749  value: true
30750});
30751
30752function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
30753
30754var _config = require('./config');
30755
30756var _config2 = _interopRequireDefault(_config);
30757
30758var _playlist = require('./playlist');
30759
30760var _playlist2 = _interopRequireDefault(_playlist);
30761
30762var _utilCodecsJs = require('./util/codecs.js');
30763
30764// Utilities
30765
30766/**
30767 * Returns the CSS value for the specified property on an element
30768 * using `getComputedStyle`. Firefox has a long-standing issue where
30769 * getComputedStyle() may return null when running in an iframe with
30770 * `display: none`.
30771 *
30772 * @see https://bugzilla.mozilla.org/show_bug.cgi?id=548397
30773 * @param {HTMLElement} el the htmlelement to work on
30774 * @param {string} the proprety to get the style for
30775 */
30776var safeGetComputedStyle = function safeGetComputedStyle(el, property) {
30777  var result = undefined;
30778
30779  if (!el) {
30780    return '';
30781  }
30782
30783  result = window.getComputedStyle(el);
30784  if (!result) {
30785    return '';
30786  }
30787
30788  return result[property];
30789};
30790
30791/**
30792 * Resuable stable sort function
30793 *
30794 * @param {Playlists} array
30795 * @param {Function}
vendor: 30,766 bytes, lines 30795-31678
30795 sortFn Different comparators
30796 * @function stableSort
30797 */
30798var stableSort = function stableSort(array, sortFn) {
30799  var newArray = array.slice();
30800
30801  array.sort(function (left, right) {
30802    var cmp = sortFn(left, right);
30803
30804    if (cmp === 0) {
30805      return newArray.indexOf(left) - newArray.indexOf(right);
30806    }
30807    return cmp;
30808  });
30809};
30810
30811/**
30812 * A comparator function to sort two playlist object by bandwidth.
30813 *
30814 * @param {Object} left a media playlist object
30815 * @param {Object} right a media playlist object
30816 * @return {Number} Greater than zero if the bandwidth attribute of
30817 * left is greater than the corresponding attribute of right. Less
30818 * than zero if the bandwidth of right is greater than left and
30819 * exactly zero if the two are equal.
30820 */
30821var comparePlaylistBandwidth = function comparePlaylistBandwidth(left, right) {
30822  var leftBandwidth = undefined;
30823  var rightBandwidth = undefined;
30824
30825  if (left.attributes.BANDWIDTH) {
30826    leftBandwidth = left.attributes.BANDWIDTH;
30827  }
30828  leftBandwidth = leftBandwidth || window.Number.MAX_VALUE;
30829  if (right.attributes.BANDWIDTH) {
30830    rightBandwidth = right.attributes.BANDWIDTH;
30831  }
30832  rightBandwidth = rightBandwidth || window.Number.MAX_VALUE;
30833
30834  return leftBandwidth - rightBandwidth;
30835};
30836
30837exports.comparePlaylistBandwidth = comparePlaylistBandwidth;
30838/**
30839 * A comparator function to sort two playlist object by resolution (width).
30840 * @param {Object} left a media playlist object
30841 * @param {Object} right a media playlist object
30842 * @return {Number} Greater than zero if the resolution.width attribute of
30843 * left is greater than the corresponding attribute of right. Less
30844 * than zero if the resolution.width of right is greater than left and
30845 * exactly zero if the two are equal.
30846 */
30847var comparePlaylistResolution = function comparePlaylistResolution(left, right) {
30848  var leftWidth = undefined;
30849  var rightWidth = undefined;
30850
30851  if (left.attributes.RESOLUTION && left.attributes.RESOLUTION.width) {
30852    leftWidth = left.attributes.RESOLUTION.width;
30853  }
30854
30855  leftWidth = leftWidth || window.Number.MAX_VALUE;
30856
30857  if (right.attributes.RESOLUTION && right.attributes.RESOLUTION.width) {
30858    rightWidth = right.attributes.RESOLUTION.width;
30859  }
30860
30861  rightWidth = rightWidth || window.Number.MAX_VALUE;
30862
30863  // NOTE - Fallback to bandwidth sort as appropriate in cases where multiple renditions
30864  // have the same media dimensions/ resolution
30865  if (leftWidth === rightWidth && left.attributes.BANDWIDTH && right.attributes.BANDWIDTH) {
30866    return left.attributes.BANDWIDTH - right.attributes.BANDWIDTH;
30867  }
30868  return leftWidth - rightWidth;
30869};
30870
30871exports.comparePlaylistResolution = comparePlaylistResolution;
30872/**
30873 * Chooses the appropriate media playlist based on bandwidth and player size
30874 *
30875 * @param {Object} master
30876 *        Object representation of the master manifest
30877 * @param {Number} playerBandwidth
30878 *        Current calculated bandwidth of the player
30879 * @param {Number} playerWidth
30880 *        Current width of the player element
30881 * @param {Number} playerHeight
30882 *        Current height of the player element
30883 * @return {Playlist} the highest bitrate playlist less than the
30884 * currently detected bandwidth, accounting for some amount of
30885 * bandwidth variance
30886 */
30887var simpleSelector = function simpleSelector(master, playerBandwidth, playerWidth, playerHeight) {
30888  // convert the playlists to an intermediary representation to make comparisons easier
30889  var sortedPlaylistReps = master.playlists.map(function (playlist) {
30890    var width = undefined;
30891    var height = undefined;
30892    var bandwidth = undefined;
30893
30894    width = playlist.attributes.RESOLUTION && playlist.attributes.RESOLUTION.width;
30895    height = playlist.attributes.RESOLUTION && playlist.attributes.RESOLUTION.height;
30896    bandwidth = playlist.attributes.BANDWIDTH;
30897
30898    bandwidth = bandwidth || window.Number.MAX_VALUE;
30899
30900    return {
30901      bandwidth: bandwidth,
30902      width: width,
30903      height: height,
30904      playlist: playlist
30905    };
30906  });
30907
30908  stableSort(sortedPlaylistReps, function (left, right) {
30909    return left.bandwidth - right.bandwidth;
30910  });
30911
30912  // filter out any playlists that have been excluded due to
30913  // incompatible configurations or playback errors
30914  sortedPlaylistReps = sortedPlaylistReps.filter(function (rep) {
30915    return _playlist2['default'].isEnabled(rep.playlist);
30916  });
30917
30918  // filter out any variant that has greater effective bitrate
30919  // than the current estimated bandwidth
30920  var bandwidthPlaylistReps = sortedPlaylistReps.filter(function (rep) {
30921    return rep.bandwidth * _config2['default'].BANDWIDTH_VARIANCE < playerBandwidth;
30922  });
30923
30924  var highestRemainingBandwidthRep = bandwidthPlaylistReps[bandwidthPlaylistReps.length - 1];
30925
30926  // get all of the renditions with the same (highest) bandwidth
30927  // and then taking the very first element
30928  var bandwidthBestRep = bandwidthPlaylistReps.filter(function (rep) {
30929    return rep.bandwidth === highestRemainingBandwidthRep.bandwidth;
30930  })[0];
30931
30932  // filter out playlists without resolution information
30933  var haveResolution = bandwidthPlaylistReps.filter(function (rep) {
30934    return rep.width && rep.height;
30935  });
30936
30937  // sort variants by resolution
30938  stableSort(haveResolution, function (left, right) {
30939    return left.width - right.width;
30940  });
30941
30942  // if we have the exact resolution as the player use it
30943  var resolutionBestRepList = haveResolution.filter(function (rep) {
30944    return rep.width === playerWidth && rep.height === playerHeight;
30945  });
30946
30947  highestRemainingBandwidthRep = resolutionBestRepList[resolutionBestRepList.length - 1];
30948  // ensure that we pick the highest bandwidth variant that have exact resolution
30949  var resolutionBestRep = resolutionBestRepList.filter(function (rep) {
30950    return rep.bandwidth === highestRemainingBandwidthRep.bandwidth;
30951  })[0];
30952
30953  var resolutionPlusOneList = undefined;
30954  var resolutionPlusOneSmallest = undefined;
30955  var resolutionPlusOneRep = undefined;
30956
30957  // find the smallest variant that is larger than the player
30958  // if there is no match of exact resolution
30959  if (!resolutionBestRep) {
30960    resolutionPlusOneList = haveResolution.filter(function (rep) {
30961      return rep.width > playerWidth || rep.height > playerHeight;
30962    });
30963
30964    // find all the variants have the same smallest resolution
30965    resolutionPlusOneSmallest = resolutionPlusOneList.filter(function (rep) {
30966      return rep.width === resolutionPlusOneList[0].width && rep.height === resolutionPlusOneList[0].height;
30967    });
30968
30969    // ensure that we also pick the highest bandwidth variant that
30970    // is just-larger-than the video player
30971    highestRemainingBandwidthRep = resolutionPlusOneSmallest[resolutionPlusOneSmallest.length - 1];
30972    resolutionPlusOneRep = resolutionPlusOneSmallest.filter(function (rep) {
30973      return rep.bandwidth === highestRemainingBandwidthRep.bandwidth;
30974    })[0];
30975  }
30976
30977  // fallback chain of variants
30978  return (resolutionPlusOneRep || resolutionBestRep || bandwidthBestRep || sortedPlaylistReps[0]).playlist;
30979};
30980
30981exports.simpleSelector = simpleSelector;
30982// Playlist Selectors
30983
30984/**
30985 * Chooses the appropriate media playlist based on the most recent
30986 * bandwidth estimate and the player size.
30987 *
30988 * Expects to be called within the context of an instance of HlsHandler
30989 *
30990 * @return {Playlist} the highest bitrate playlist less than the
30991 * currently detected bandwidth, accounting for some amount of
30992 * bandwidth variance
30993 */
30994var lastBandwidthSelector = function lastBandwidthSelector() {
30995  return simpleSelector(this.playlists.master, this.systemBandwidth, parseInt(safeGetComputedStyle(this.tech_.el(), 'width'), 10), parseInt(safeGetComputedStyle(this.tech_.el(), 'height'), 10));
30996};
30997
30998exports.lastBandwidthSelector = lastBandwidthSelector;
30999/**
31000 * Chooses the appropriate media playlist based on an
31001 * exponential-weighted moving average of the bandwidth after
31002 * filtering for player size.
31003 *
31004 * Expects to be called within the context of an instance of HlsHandler
31005 *
31006 * @param {Number} decay - a number between 0 and 1. Higher values of
31007 * this parameter will cause previous bandwidth estimates to lose
31008 * significance more quickly.
31009 * @return {Function} a function which can be invoked to create a new
31010 * playlist selector function.
31011 * @see https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
31012 */
31013var movingAverageBandwidthSelector = function movingAverageBandwidthSelector(decay) {
31014  var average = -1;
31015
31016  if (decay < 0 || decay > 1) {
31017    throw new Error('Moving average bandwidth decay must be between 0 and 1.');
31018  }
31019
31020  return function () {
31021    if (average < 0) {
31022      average = this.systemBandwidth;
31023    }
31024
31025    average = decay * this.systemBandwidth + (1 - decay) * average;
31026    return simpleSelector(this.playlists.master, average, parseInt(safeGetComputedStyle(this.tech_.el(), 'width'), 10), parseInt(safeGetComputedStyle(this.tech_.el(), 'height'), 10));
31027  };
31028};
31029
31030exports.movingAverageBandwidthSelector = movingAverageBandwidthSelector;
31031/**
31032 * Chooses the appropriate media playlist based on the potential to rebuffer
31033 *
31034 * @param {Object} settings
31035 *        Object of information required to use this selector
31036 * @param {Object} settings.master
31037 *        Object representation of the master manifest
31038 * @param {Number} settings.currentTime
31039 *        The current time of the player
31040 * @param {Number} settings.bandwidth
31041 *        Current measured bandwidth
31042 * @param {Number} settings.duration
31043 *        Duration of the media
31044 * @param {Number} settings.segmentDuration
31045 *        Segment duration to be used in round trip time calculations
31046 * @param {Number} settings.timeUntilRebuffer
31047 *        Time left in seconds until the player has to rebuffer
31048 * @param {Number} settings.currentTimeline
31049 *        The current timeline segments are being loaded from
31050 * @param {SyncController} settings.syncController
31051 *        SyncController for determining if we have a sync point for a given playlist
31052 * @return {Object|null}
31053 *         {Object} return.playlist
31054 *         The highest bandwidth playlist with the least amount of rebuffering
31055 *         {Number} return.rebufferingImpact
31056 *         The amount of time in seconds switching to this playlist will rebuffer. A
31057 *         negative value means that switching will cause zero rebuffering.
31058 */
31059var minRebufferMaxBandwidthSelector = function minRebufferMaxBandwidthSelector(settings) {
31060  var master = settings.master;
31061  var currentTime = settings.currentTime;
31062  var bandwidth = settings.bandwidth;
31063  var duration = settings.duration;
31064  var segmentDuration = settings.segmentDuration;
31065  var timeUntilRebuffer = settings.timeUntilRebuffer;
31066  var currentTimeline = settings.currentTimeline;
31067  var syncController = settings.syncController;
31068
31069  var bandwidthPlaylists = master.playlists.filter(function (playlist) {
31070    return _playlist2['default'].isEnabled(playlist) && _playlist2['default'].hasAttribute('BANDWIDTH', playlist);
31071  });
31072
31073  var rebufferingEstimates = bandwidthPlaylists.map(function (playlist) {
31074    var syncPoint = syncController.getSyncPoint(playlist, duration, currentTimeline, currentTime);
31075    // If there is no sync point for this playlist, switching to it will require a
31076    // sync request first. This will double the request time
31077    var numRequests = syncPoint ? 1 : 2;
31078    var requestTimeEstimate = _playlist2['default'].estimateSegmentRequestTime(segmentDuration, bandwidth, playlist);
31079    var rebufferingImpact = requestTimeEstimate * numRequests - timeUntilRebuffer;
31080
31081    return {
31082      playlist: playlist,
31083      rebufferingImpact: rebufferingImpact
31084    };
31085  });
31086
31087  var noRebufferingPlaylists = rebufferingEstimates.filter(function (estimate) {
31088    return estimate.rebufferingImpact <= 0;
31089  });
31090
31091  // Sort by bandwidth DESC
31092  stableSort(noRebufferingPlaylists, function (a, b) {
31093    return comparePlaylistBandwidth(b.playlist, a.playlist);
31094  });
31095
31096  if (noRebufferingPlaylists.length) {
31097    return noRebufferingPlaylists[0];
31098  }
31099
31100  stableSort(rebufferingEstimates, function (a, b) {
31101    return a.rebufferingImpact - b.rebufferingImpact;
31102  });
31103
31104  return rebufferingEstimates[0] || null;
31105};
31106
31107exports.minRebufferMaxBandwidthSelector = minRebufferMaxBandwidthSelector;
31108/**
31109 * Chooses the appropriate media playlist, which in this case is the lowest bitrate
31110 * one with video.  If no renditions with video exist, return the lowest audio rendition.
31111 *
31112 * Expects to be called within the context of an instance of HlsHandler
31113 *
31114 * @return {Object|null}
31115 *         {Object} return.playlist
31116 *         The lowest bitrate playlist that contains a video codec.  If no such rendition
31117 *         exists pick the lowest audio rendition.
31118 */
31119var lowestBitrateCompatibleVariantSelector = function lowestBitrateCompatibleVariantSelector() {
31120  // filter out any playlists that have been excluded due to
31121  // incompatible configurations or playback errors
31122  var playlists = this.playlists.master.playlists.filter(_playlist2['default'].isEnabled);
31123
31124  // Sort ascending by bitrate
31125  stableSort(playlists, function (a, b) {
31126    return comparePlaylistBandwidth(a, b);
31127  });
31128
31129  // Parse and assume that playlists with no video codec have no video
31130  // (this is not necessarily true, although it is generally true).
31131  //
31132  // If an entire manifest has no valid videos everything will get filtered
31133  // out.
31134  var playlistsWithVideo = playlists.filter(function (playlist) {
31135    return (0, _utilCodecsJs.parseCodecs)(playlist.attributes.CODECS).videoCodec;
31136  });
31137
31138  return playlistsWithVideo[0] || null;
31139};
31140exports.lowestBitrateCompatibleVariantSelector = lowestBitrateCompatibleVariantSelector;
31141},{"./config":3,"./playlist":11,"./util/codecs.js":19}],11:[function(require,module,exports){
31142(function (global){
31143/**
31144 * @file playlist.js
31145 *
31146 * Playlist related utilities.
31147 */
31148'use strict';
31149
31150Object.defineProperty(exports, '__esModule', {
31151  value: true
31152});
31153
31154function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
31155
31156var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
31157
31158var _globalWindow = require('global/window');
31159
31160var _globalWindow2 = _interopRequireDefault(_globalWindow);
31161
31162var Playlist = {
31163  /**
31164   * The number of segments that are unsafe to start playback at in
31165   * a live stream. Changing this value can cause playback stalls.
31166   * See HTTP Live Streaming, "Playing the Media Playlist File"
31167   * https://tools.ietf.org/html/draft-pantos-http-live-streaming-18#section-6.3.3
31168   */
31169  UNSAFE_LIVE_SEGMENTS: 3
31170};
31171
31172/**
31173 * walk backward until we find a duration we can use
31174 * or return a failure
31175 *
31176 * @param {Playlist} playlist the playlist to walk through
31177 * @param {Number} endSequence the mediaSequence to stop walking on
31178 */
31179
31180var backwardDuration = function backwardDuration(playlist, endSequence) {
31181  var result = 0;
31182  var i = endSequence - playlist.mediaSequence;
31183  // if a start time is available for segment immediately following
31184  // the interval, use it
31185  var segment = playlist.segments[i];
31186
31187  // Walk backward until we find the latest segment with timeline
31188  // information that is earlier than endSequence
31189  if (segment) {
31190    if (typeof segment.start !== 'undefined') {
31191      return { result: segment.start, precise: true };
31192    }
31193    if (typeof segment.end !== 'undefined') {
31194      return {
31195        result: segment.end - segment.duration,
31196        precise: true
31197      };
31198    }
31199  }
31200  while (i--) {
31201    segment = playlist.segments[i];
31202    if (typeof segment.end !== 'undefined') {
31203      return { result: result + segment.end, precise: true };
31204    }
31205
31206    result += segment.duration;
31207
31208    if (typeof segment.start !== 'undefined') {
31209      return { result: result + segment.start, precise: true };
31210    }
31211  }
31212  return { result: result, precise: false };
31213};
31214
31215/**
31216 * walk forward until we find a duration we can use
31217 * or return a failure
31218 *
31219 * @param {Playlist} playlist the playlist to walk through
31220 * @param {Number} endSequence the mediaSequence to stop walking on
31221 */
31222var forwardDuration = function forwardDuration(playlist, endSequence) {
31223  var result = 0;
31224  var segment = undefined;
31225  var i = endSequence - playlist.mediaSequence;
31226  // Walk forward until we find the earliest segment with timeline
31227  // information
31228
31229  for (; i < playlist.segments.length; i++) {
31230    segment = playlist.segments[i];
31231    if (typeof segment.start !== 'undefined') {
31232      return {
31233        result: segment.start - result,
31234        precise: true
31235      };
31236    }
31237
31238    result += segment.duration;
31239
31240    if (typeof segment.end !== 'undefined') {
31241      return {
31242        result: segment.end - result,
31243        precise: true
31244      };
31245    }
31246  }
31247  // indicate we didn't find a useful duration estimate
31248  return { result: -1, precise: false };
31249};
31250
31251/**
31252  * Calculate the media duration from the segments associated with a
31253  * playlist. The duration of a subinterval of the available segments
31254  * may be calculated by specifying an end index.
31255  *
31256  * @param {Object} playlist a media playlist object
31257  * @param {Number=} endSequence an exclusive upper boundary
31258  * for the playlist.  Defaults to playlist length.
31259  * @param {Number} expired the amount of time that has dropped
31260  * off the front of the playlist in a live scenario
31261  * @return {Number} the duration between the first available segment
31262  * and end index.
31263  */
31264var intervalDuration = function intervalDuration(playlist, endSequence, expired) {
31265  var backward = undefined;
31266  var forward = undefined;
31267
31268  if (typeof endSequence === 'undefined') {
31269    endSequence = playlist.mediaSequence + playlist.segments.length;
31270  }
31271
31272  if (endSequence < playlist.mediaSequence) {
31273    return 0;
31274  }
31275
31276  // do a backward walk to estimate the duration
31277  backward = backwardDuration(playlist, endSequence);
31278  if (backward.precise) {
31279    // if we were able to base our duration estimate on timing
31280    // information provided directly from the Media Source, return
31281    // it
31282    return backward.result;
31283  }
31284
31285  // walk forward to see if a precise duration estimate can be made
31286  // that way
31287  forward = forwardDuration(playlist, endSequence);
31288  if (forward.precise) {
31289    // we found a segment that has been buffered and so it's
31290    // position is known precisely
31291    return forward.result;
31292  }
31293
31294  // return the less-precise, playlist-based duration estimate
31295  return backward.result + expired;
31296};
31297
31298/**
31299  * Calculates the duration of a playlist. If a start and end index
31300  * are specified, the duration will be for the subset of the media
31301  * timeline between those two indices. The total duration for live
31302  * playlists is always Infinity.
31303  *
31304  * @param {Object} playlist a media playlist object
31305  * @param {Number=} endSequence an exclusive upper
31306  * boundary for the playlist. Defaults to the playlist media
31307  * sequence number plus its length.
31308  * @param {Number=} expired the amount of time that has
31309  * dropped off the front of the playlist in a live scenario
31310  * @return {Number} the duration between the start index and end
31311  * index.
31312  */
31313var duration = function duration(playlist, endSequence, expired) {
31314  if (!playlist) {
31315    return 0;
31316  }
31317
31318  if (typeof expired !== 'number') {
31319    expired = 0;
31320  }
31321
31322  // if a slice of the total duration is not requested, use
31323  // playlist-level duration indicators when they're present
31324  if (typeof endSequence === 'undefined') {
31325    // if present, use the duration specified in the playlist
31326    if (playlist.totalDuration) {
31327      return playlist.totalDuration;
31328    }
31329
31330    // duration should be Infinity for live playlists
31331    if (!playlist.endList) {
31332      return _globalWindow2['default'].Infinity;
31333    }
31334  }
31335
31336  // calculate the total duration based on the segment durations
31337  return intervalDuration(playlist, endSequence, expired);
31338};
31339
31340exports.duration = duration;
31341/**
31342  * Calculate the time between two indexes in the current playlist
31343  * neight the start- nor the end-index need to be within the current
31344  * playlist in which case, the targetDuration of the playlist is used
31345  * to approximate the durations of the segments
31346  *
31347  * @param {Object} playlist a media playlist object
31348  * @param {Number} startIndex
31349  * @param {Number} endIndex
31350  * @return {Number} the number of seconds between startIndex and endIndex
31351  */
31352var sumDurations = function sumDurations(playlist, startIndex, endIndex) {
31353  var durations = 0;
31354
31355  if (startIndex > endIndex) {
31356    var _ref = [endIndex, startIndex];
31357    startIndex = _ref[0];
31358    endIndex = _ref[1];
31359  }
31360
31361  if (startIndex < 0) {
31362    for (var i = startIndex; i < Math.min(0, endIndex); i++) {
31363      durations += playlist.targetDuration;
31364    }
31365    startIndex = 0;
31366  }
31367
31368  for (var i = startIndex; i < endIndex; i++) {
31369    durations += playlist.segments[i].duration;
31370  }
31371
31372  return durations;
31373};
31374
31375exports.sumDurations = sumDurations;
31376/**
31377 * Calculates the playlist end time
31378 *
31379 * @param {Object} playlist a media playlist object
31380 * @param {Number=} expired the amount of time that has
31381 *                  dropped off the front of the playlist in a live scenario
31382 * @param {Boolean|false} useSafeLiveEnd a boolean value indicating whether or not the
31383 *                        playlist end calculation should consider the safe live end
31384 *                        (truncate the playlist end by three segments). This is normally
31385 *                        used for calculating the end of the playlist's seekable range.
31386 * @returns {Number} the end time of playlist
31387 * @function playlistEnd
31388 */
31389var playlistEnd = function playlistEnd(playlist, expired, useSafeLiveEnd) {
31390  if (!playlist || !playlist.segments) {
31391    return null;
31392  }
31393  if (playlist.endList) {
31394    return duration(playlist);
31395  }
31396
31397  if (expired === null) {
31398    return null;
31399  }
31400
31401  expired = expired || 0;
31402
31403  var endSequence = useSafeLiveEnd ? Math.max(0, playlist.segments.length - Playlist.UNSAFE_LIVE_SEGMENTS) : Math.max(0, playlist.segments.length);
31404
31405  return intervalDuration(playlist, playlist.mediaSequence + endSequence, expired);
31406};
31407
31408exports.playlistEnd = playlistEnd;
31409/**
31410  * Calculates the interval of time that is currently seekable in a
31411  * playlist. The returned time ranges are relative to the earliest
31412  * moment in the specified playlist that is still available. A full
31413  * seekable implementation for live streams would need to offset
31414  * these values by the duration of content that has expired from the
31415  * stream.
31416  *
31417  * @param {Object} playlist a media playlist object
31418  * dropped off the front of the playlist in a live scenario
31419  * @param {Number=} expired the amount of time that has
31420  * dropped off the front of the playlist in a live scenario
31421  * @return {TimeRanges} the periods of time that are valid targets
31422  * for seeking
31423  */
31424var seekable = function seekable(playlist, expired) {
31425  var useSafeLiveEnd = true;
31426  var seekableStart = expired || 0;
31427  var seekableEnd = playlistEnd(playlist, expired, useSafeLiveEnd);
31428
31429  if (seekableEnd === null) {
31430    return (0, _videoJs.createTimeRange)();
31431  }
31432  return (0, _videoJs.createTimeRange)(seekableStart, seekableEnd);
31433};
31434
31435exports.seekable = seekable;
31436var isWholeNumber = function isWholeNumber(num) {
31437  return num - Math.floor(num) === 0;
31438};
31439
31440var roundSignificantDigit = function roundSignificantDigit(increment, num) {
31441  // If we have a whole number, just add 1 to it
31442  if (isWholeNumber(num)) {
31443    return num + increment * 0.1;
31444  }
31445
31446  var numDecimalDigits = num.toString().split('.')[1].length;
31447
31448  for (var i = 1; i <= numDecimalDigits; i++) {
31449    var scale = Math.pow(10, i);
31450    var temp = num * scale;
31451
31452    if (isWholeNumber(temp) || i === numDecimalDigits) {
31453      return (temp + increment) / scale;
31454    }
31455  }
31456};
31457
31458var ceilLeastSignificantDigit = roundSignificantDigit.bind(null, 1);
31459var floorLeastSignificantDigit = roundSignificantDigit.bind(null, -1);
31460
31461/**
31462 * Determine the index and estimated starting time of the segment that
31463 * contains a specified playback position in a media playlist.
31464 *
31465 * @param {Object} playlist the media playlist to query
31466 * @param {Number} currentTime The number of seconds since the earliest
31467 * possible position to determine the containing segment for
31468 * @param {Number} startIndex
31469 * @param {Number} startTime
31470 * @return {Object}
31471 */
31472var getMediaInfoForTime = function getMediaInfoForTime(playlist, currentTime, startIndex, startTime) {
31473  var i = undefined;
31474  var segment = undefined;
31475  var numSegments = playlist.segments.length;
31476
31477  var time = currentTime - startTime;
31478
31479  if (time < 0) {
31480    // Walk backward from startIndex in the playlist, adding durations
31481    // until we find a segment that contains `time` and return it
31482    if (startIndex > 0) {
31483      for (i = startIndex - 1; i >= 0; i--) {
31484        segment = playlist.segments[i];
31485        time += floorLeastSignificantDigit(segment.duration);
31486        if (time > 0) {
31487          return {
31488            mediaIndex: i,
31489            startTime: startTime - sumDurations(playlist, startIndex, i)
31490          };
31491        }
31492      }
31493    }
31494    // We were unable to find a good segment within the playlist
31495    // so select the first segment
31496    return {
31497      mediaIndex: 0,
31498      startTime: currentTime
31499    };
31500  }
31501
31502  // When startIndex is negative, we first walk forward to first segment
31503  // adding target durations. If we "run out of time" before getting to
31504  // the first segment, return the first segment
31505  if (startIndex < 0) {
31506    for (i = startIndex; i < 0; i++) {
31507      time -= playlist.targetDuration;
31508      if (time < 0) {
31509        return {
31510          mediaIndex: 0,
31511          startTime: currentTime
31512        };
31513      }
31514    }
31515    startIndex = 0;
31516  }
31517
31518  // Walk forward from startIndex in the playlist, subtracting durations
31519  // until we find a segment that contains `time` and return it
31520  for (i = startIndex; i < numSegments; i++) {
31521    segment = playlist.segments[i];
31522    time -= ceilLeastSignificantDigit(segment.duration);
31523    if (time < 0) {
31524      return {
31525        mediaIndex: i,
31526        startTime: startTime + sumDurations(playlist, startIndex, i)
31527      };
31528    }
31529  }
31530
31531  // We are out of possible candidates so load the last one...
31532  return {
31533    mediaIndex: numSegments - 1,
31534    startTime: currentTime
31535  };
31536};
31537
31538exports.getMediaInfoForTime = getMediaInfoForTime;
31539/**
31540 * Check whether the playlist is blacklisted or not.
31541 *
31542 * @param {Object} playlist the media playlist object
31543 * @return {boolean} whether the playlist is blacklisted or not
31544 * @function isBlacklisted
31545 */
31546var isBlacklisted = function isBlacklisted(playlist) {
31547  return playlist.excludeUntil && playlist.excludeUntil > Date.now();
31548};
31549
31550exports.isBlacklisted = isBlacklisted;
31551/**
31552 * Check whether the playlist is enabled or not.
31553 *
31554 * @param {Object} playlist the media playlist object
31555 * @return {boolean} whether the playlist is enabled or not
31556 * @function isEnabled
31557 */
31558var isEnabled = function isEnabled(playlist) {
31559  var blacklisted = isBlacklisted(playlist);
31560
31561  return !playlist.disabled && !blacklisted;
31562};
31563
31564exports.isEnabled = isEnabled;
31565/**
31566 * Returns whether the current playlist is an AES encrypted HLS stream
31567 *
31568 * @return {Boolean} true if it's an AES encrypted HLS stream
31569 */
31570var isAes = function isAes(media) {
31571  for (var i = 0; i < media.segments.length; i++) {
31572    if (media.segments[i].key) {
31573      return true;
31574    }
31575  }
31576  return false;
31577};
31578
31579exports.isAes = isAes;
31580/**
31581 * Returns whether the current playlist contains fMP4
31582 *
31583 * @return {Boolean} true if the playlist contains fMP4
31584 */
31585var isFmp4 = function isFmp4(media) {
31586  for (var i = 0; i < media.segments.length; i++) {
31587    if (media.segments[i].map) {
31588      return true;
31589    }
31590  }
31591  return false;
31592};
31593
31594exports.isFmp4 = isFmp4;
31595/**
31596 * Checks if the playlist has a value for the specified attribute
31597 *
31598 * @param {String} attr
31599 *        Attribute to check for
31600 * @param {Object} playlist
31601 *        The media playlist object
31602 * @return {Boolean}
31603 *         Whether the playlist contains a value for the attribute or not
31604 * @function hasAttribute
31605 */
31606var hasAttribute = function hasAttribute(attr, playlist) {
31607  return playlist.attributes && playlist.attributes[attr];
31608};
31609
31610exports.hasAttribute = hasAttribute;
31611/**
31612 * Estimates the time required to complete a segment download from the specified playlist
31613 *
31614 * @param {Number} segmentDuration
31615 *        Duration of requested segment
31616 * @param {Number} bandwidth
31617 *        Current measured bandwidth of the player
31618 * @param {Object} playlist
31619 *        The media playlist object
31620 * @param {Number=} bytesReceived
31621 *        Number of bytes already received for the request. Defaults to 0
31622 * @return {Number|NaN}
31623 *         The estimated time to request the segment. NaN if bandwidth information for
31624 *         the given playlist is unavailable
31625 * @function estimateSegmentRequestTime
31626 */
31627var estimateSegmentRequestTime = function estimateSegmentRequestTime(segmentDuration, bandwidth, playlist) {
31628  var bytesReceived = arguments.length <= 3 || arguments[3] === undefined ? 0 : arguments[3];
31629
31630  if (!hasAttribute('BANDWIDTH', playlist)) {
31631    return NaN;
31632  }
31633
31634  var size = segmentDuration * playlist.attributes.BANDWIDTH;
31635
31636  return (size - bytesReceived * 8) / bandwidth;
31637};
31638
31639exports.estimateSegmentRequestTime = estimateSegmentRequestTime;
31640Playlist.duration = duration;
31641Playlist.seekable = seekable;
31642Playlist.getMediaInfoForTime = getMediaInfoForTime;
31643Playlist.isEnabled = isEnabled;
31644Playlist.isBlacklisted = isBlacklisted;
31645Playlist.playlistEnd = playlistEnd;
31646Playlist.isAes = isAes;
31647Playlist.isFmp4 = isFmp4;
31648Playlist.hasAttribute = hasAttribute;
31649Playlist.estimateSegmentRequestTime = estimateSegmentRequestTime;
31650
31651// exports
31652exports['default'] = Playlist;
31653}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
31654},{"global/window":32}],12:[function(require,module,exports){
31655(function (global){
31656/**
31657 * ranges
31658 *
31659 * Utilities for working with TimeRanges.
31660 *
31661 */
31662
31663'use strict';
31664
31665Object.defineProperty(exports, '__esModule', {
31666  value: true
31667});
31668
31669var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
31670
31671function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
31672
31673var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
31674
31675var _videoJs2 = _interopRequireDefault(_videoJs);
31676
31677// Fudge factor to account for TimeRanges rounding
31678var TIME_FUDGE_FACTOR = 1 / 30
vendor: 11,462 bytes, lines 31678-32024
31678;
31679
31680/**
31681 * Clamps a value to within a range
31682 * @param {Number} num - the value to clamp
31683 * @param {Number} start - the start of the range to clamp within, inclusive
31684 * @param {Number} end - the end of the range to clamp within, inclusive
31685 * @return {Number}
31686 */
31687var clamp = function clamp(num, _ref) {
31688  var _ref2 = _slicedToArray(_ref, 2);
31689
31690  var start = _ref2[0];
31691  var end = _ref2[1];
31692
31693  return Math.min(Math.max(start, num), end);
31694};
31695var filterRanges = function filterRanges(timeRanges, predicate) {
31696  var results = [];
31697  var i = undefined;
31698
31699  if (timeRanges && timeRanges.length) {
31700    // Search for ranges that match the predicate
31701    for (i = 0; i < timeRanges.length; i++) {
31702      if (predicate(timeRanges.start(i), timeRanges.end(i))) {
31703        results.push([timeRanges.start(i), timeRanges.end(i)]);
31704      }
31705    }
31706  }
31707
31708  return _videoJs2['default'].createTimeRanges(results);
31709};
31710
31711/**
31712 * Attempts to find the buffered TimeRange that contains the specified
31713 * time.
31714 * @param {TimeRanges} buffered - the TimeRanges object to query
31715 * @param {number} time  - the time to filter on.
31716 * @returns {TimeRanges} a new TimeRanges object
31717 */
31718var findRange = function findRange(buffered, time) {
31719  return filterRanges(buffered, function (start, end) {
31720    return start - TIME_FUDGE_FACTOR <= time && end + TIME_FUDGE_FACTOR >= time;
31721  });
31722};
31723
31724/**
31725 * Returns the TimeRanges that begin later than the specified time.
31726 * @param {TimeRanges} timeRanges - the TimeRanges object to query
31727 * @param {number} time - the time to filter on.
31728 * @returns {TimeRanges} a new TimeRanges object.
31729 */
31730var findNextRange = function findNextRange(timeRanges, time) {
31731  return filterRanges(timeRanges, function (start) {
31732    return start - TIME_FUDGE_FACTOR >= time;
31733  });
31734};
31735
31736/**
31737 * Returns gaps within a list of TimeRanges
31738 * @param {TimeRanges} buffered - the TimeRanges object
31739 * @return {TimeRanges} a TimeRanges object of gaps
31740 */
31741var findGaps = function findGaps(buffered) {
31742  if (buffered.length < 2) {
31743    return _videoJs2['default'].createTimeRanges();
31744  }
31745
31746  var ranges = [];
31747
31748  for (var i = 1; i < buffered.length; i++) {
31749    var start = buffered.end(i - 1);
31750    var end = buffered.start(i);
31751
31752    ranges.push([start, end]);
31753  }
31754
31755  return _videoJs2['default'].createTimeRanges(ranges);
31756};
31757
31758/**
31759 * Search for a likely end time for the segment that was just appened
31760 * based on the state of the `buffered` property before and after the
31761 * append. If we fin only one such uncommon end-point return it.
31762 * @param {TimeRanges} original - the buffered time ranges before the update
31763 * @param {TimeRanges} update - the buffered time ranges after the update
31764 * @returns {Number|null} the end time added between `original` and `update`,
31765 * or null if one cannot be unambiguously determined.
31766 */
31767var findSoleUncommonTimeRangesEnd = function findSoleUncommonTimeRangesEnd(original, update) {
31768  var i = undefined;
31769  var start = undefined;
31770  var end = undefined;
31771  var result = [];
31772  var edges = [];
31773
31774  // In order to qualify as a possible candidate, the end point must:
31775  //  1) Not have already existed in the `original` ranges
31776  //  2) Not result from the shrinking of a range that already existed
31777  //     in the `original` ranges
31778  //  3) Not be contained inside of a range that existed in `original`
31779  var overlapsCurrentEnd = function overlapsCurrentEnd(span) {
31780    return span[0] <= end && span[1] >= end;
31781  };
31782
31783  if (original) {
31784    // Save all the edges in the `original` TimeRanges object
31785    for (i = 0; i < original.length; i++) {
31786      start = original.start(i);
31787      end = original.end(i);
31788
31789      edges.push([start, end]);
31790    }
31791  }
31792
31793  if (update) {
31794    // Save any end-points in `update` that are not in the `original`
31795    // TimeRanges object
31796    for (i = 0; i < update.length; i++) {
31797      start = update.start(i);
31798      end = update.end(i);
31799
31800      if (edges.some(overlapsCurrentEnd)) {
31801        continue;
31802      }
31803
31804      // at this point it must be a unique non-shrinking end edge
31805      result.push(end);
31806    }
31807  }
31808
31809  // we err on the side of caution and return null if didn't find
31810  // exactly *one* differing end edge in the search above
31811  if (result.length !== 1) {
31812    return null;
31813  }
31814
31815  return result[0];
31816};
31817
31818/**
31819 * Calculate the intersection of two TimeRanges
31820 * @param {TimeRanges} bufferA
31821 * @param {TimeRanges} bufferB
31822 * @returns {TimeRanges} The interesection of `bufferA` with `bufferB`
31823 */
31824var bufferIntersection = function bufferIntersection(bufferA, bufferB) {
31825  var start = null;
31826  var end = null;
31827  var arity = 0;
31828  var extents = [];
31829  var ranges = [];
31830
31831  if (!bufferA || !bufferA.length || !bufferB || !bufferB.length) {
31832    return _videoJs2['default'].createTimeRange();
31833  }
31834
31835  // Handle the case where we have both buffers and create an
31836  // intersection of the two
31837  var count = bufferA.length;
31838
31839  // A) Gather up all start and end times
31840  while (count--) {
31841    extents.push({ time: bufferA.start(count), type: 'start' });
31842    extents.push({ time: bufferA.end(count), type: 'end' });
31843  }
31844  count = bufferB.length;
31845  while (count--) {
31846    extents.push({ time: bufferB.start(count), type: 'start' });
31847    extents.push({ time: bufferB.end(count), type: 'end' });
31848  }
31849  // B) Sort them by time
31850  extents.sort(function (a, b) {
31851    return a.time - b.time;
31852  });
31853
31854  // C) Go along one by one incrementing arity for start and decrementing
31855  //    arity for ends
31856  for (count = 0; count < extents.length; count++) {
31857    if (extents[count].type === 'start') {
31858      arity++;
31859
31860      // D) If arity is ever incremented to 2 we are entering an
31861      //    overlapping range
31862      if (arity === 2) {
31863        start = extents[count].time;
31864      }
31865    } else if (extents[count].type === 'end') {
31866      arity--;
31867
31868      // E) If arity is ever decremented to 1 we leaving an
31869      //    overlapping range
31870      if (arity === 1) {
31871        end = extents[count].time;
31872      }
31873    }
31874
31875    // F) Record overlapping ranges
31876    if (start !== null && end !== null) {
31877      ranges.push([start, end]);
31878      start = null;
31879      end = null;
31880    }
31881  }
31882
31883  return _videoJs2['default'].createTimeRanges(ranges);
31884};
31885
31886/**
31887 * Calculates the percentage of `segmentRange` that overlaps the
31888 * `buffered` time ranges.
31889 * @param {TimeRanges} segmentRange - the time range that the segment
31890 * covers adjusted according to currentTime
31891 * @param {TimeRanges} referenceRange - the original time range that the
31892 * segment covers
31893 * @param {Number} currentTime - time in seconds where the current playback
31894 * is at
31895 * @param {TimeRanges} buffered - the currently buffered time ranges
31896 * @returns {Number} percent of the segment currently buffered
31897 */
31898var calculateBufferedPercent = function calculateBufferedPercent(adjustedRange, referenceRange, currentTime, buffered) {
31899  var referenceDuration = referenceRange.end(0) - referenceRange.start(0);
31900  var adjustedDuration = adjustedRange.end(0) - adjustedRange.start(0);
31901  var bufferMissingFromAdjusted = referenceDuration - adjustedDuration;
31902  var adjustedIntersection = bufferIntersection(adjustedRange, buffered);
31903  var referenceIntersection = bufferIntersection(referenceRange, buffered);
31904  var adjustedOverlap = 0;
31905  var referenceOverlap = 0;
31906
31907  var count = adjustedIntersection.length;
31908
31909  while (count--) {
31910    adjustedOverlap += adjustedIntersection.end(count) - adjustedIntersection.start(count);
31911
31912    // If the current overlap segment starts at currentTime, then increase the
31913    // overlap duration so that it actually starts at the beginning of referenceRange
31914    // by including the difference between the two Range's durations
31915    // This is a work around for the way Flash has no buffer before currentTime
31916    if (adjustedIntersection.start(count) === currentTime) {
31917      adjustedOverlap += bufferMissingFromAdjusted;
31918    }
31919  }
31920
31921  count = referenceIntersection.length;
31922
31923  while (count--) {
31924    referenceOverlap += referenceIntersection.end(count) - referenceIntersection.start(count);
31925  }
31926
31927  // Use whichever value is larger for the percentage-buffered since that value
31928  // is likely more accurate because the only way
31929  return Math.max(adjustedOverlap, referenceOverlap) / referenceDuration * 100;
31930};
31931
31932/**
31933 * Return the amount of a range specified by the startOfSegment and segmentDuration
31934 * overlaps the current buffered content.
31935 *
31936 * @param {Number} startOfSegment - the time where the segment begins
31937 * @param {Number} segmentDuration - the duration of the segment in seconds
31938 * @param {Number} currentTime - time in seconds where the current playback
31939 * is at
31940 * @param {TimeRanges} buffered - the state of the buffer
31941 * @returns {Number} percentage of the segment's time range that is
31942 * already in `buffered`
31943 */
31944var getSegmentBufferedPercent = function getSegmentBufferedPercent(startOfSegment, segmentDuration, currentTime, buffered) {
31945  var endOfSegment = startOfSegment + segmentDuration;
31946
31947  // The entire time range of the segment
31948  var originalSegmentRange = _videoJs2['default'].createTimeRanges([[startOfSegment, endOfSegment]]);
31949
31950  // The adjusted segment time range that is setup such that it starts
31951  // no earlier than currentTime
31952  // Flash has no notion of a back-buffer so adjustedSegmentRange adjusts
31953  // for that and the function will still return 100% if a only half of a
31954  // segment is actually in the buffer as long as the currentTime is also
31955  // half-way through the segment
31956  var adjustedSegmentRange = _videoJs2['default'].createTimeRanges([[clamp(startOfSegment, [currentTime, endOfSegment]), endOfSegment]]);
31957
31958  // This condition happens when the currentTime is beyond the segment's
31959  // end time
31960  if (adjustedSegmentRange.start(0) === adjustedSegmentRange.end(0)) {
31961    return 0;
31962  }
31963
31964  var percent = calculateBufferedPercent(adjustedSegmentRange, originalSegmentRange, currentTime, buffered);
31965
31966  // If the segment is reported as having a zero duration, return 0%
31967  // since it is likely that we will need to fetch the segment
31968  if (isNaN(percent) || percent === Infinity || percent === -Infinity) {
31969    return 0;
31970  }
31971
31972  return percent;
31973};
31974
31975/**
31976 * Gets a human readable string for a TimeRange
31977 *
31978 * @param {TimeRange} range
31979 * @returns {String} a human readable string
31980 */
31981var printableRange = function printableRange(range) {
31982  var strArr = [];
31983
31984  if (!range || !range.length) {
31985    return '';
31986  }
31987
31988  for (var i = 0; i < range.length; i++) {
31989    strArr.push(range.start(i) + ' => ' + range.end(i));
31990  }
31991
31992  return strArr.join(', ');
31993};
31994
31995/**
31996 * Calculates the amount of time left in seconds until the player hits the end of the
31997 * buffer and causes a rebuffer
31998 *
31999 * @param {TimeRange} buffered
32000 *        The state of the buffer
32001 * @param {Numnber} currentTime
32002 *        The current time of the player
32003 * @param {Number} playbackRate
32004 *        The current playback rate of the player. Defaults to 1.
32005 * @return {Number}
32006 *         Time until the player has to start rebuffering in seconds.
32007 * @function timeUntilRebuffer
32008 */
32009var timeUntilRebuffer = function timeUntilRebuffer(buffered, currentTime) {
32010  var playbackRate = arguments.length <= 2 || arguments[2] === undefined ? 1 : arguments[2];
32011
32012  var bufferedEnd = buffered.length ? buffered.end(buffered.length - 1) : 0;
32013
32014  return (bufferedEnd - currentTime) / playbackRate;
32015};
32016
32017exports['default'] = {
32018  findRange: findRange,
32019  findNextRange: findNextRange,
32020  findGaps: findGaps,
32021  findSoleUncommonTimeRangesEnd: findSoleUncommonTimeRangesEnd,
32022  getSegmentBufferedPercent: getSegmentBufferedPercent,
32023  TIME_FUDGE_FACTOR: TIME_FUDGE_FACTOR,
32024  
vendor: 14,363 bytes, lines 32024-32419
32024printableRange: printableRange,
32025  timeUntilRebuffer: timeUntilRebuffer
32026};
32027module.exports = exports['default'];
32028}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
32029},{}],13:[function(require,module,exports){
32030(function (global){
32031'use strict';
32032
32033Object.defineProperty(exports, '__esModule', {
32034  value: true
32035});
32036
32037function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
32038
32039var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
32040
32041var _videoJs2 = _interopRequireDefault(_videoJs);
32042
32043var defaultOptions = {
32044  errorInterval: 30,
32045  getSource: function getSource(next) {
32046    var tech = this.tech({ IWillNotUseThisInPlugins: true });
32047    var sourceObj = tech.currentSource_;
32048
32049    return next(sourceObj);
32050  }
32051};
32052
32053/**
32054 * Main entry point for the plugin
32055 *
32056 * @param {Player} player a reference to a videojs Player instance
32057 * @param {Object} [options] an object with plugin options
32058 * @private
32059 */
32060var initPlugin = function initPlugin(player, options) {
32061  var lastCalled = 0;
32062  var seekTo = 0;
32063  var localOptions = _videoJs2['default'].mergeOptions(defaultOptions, options);
32064
32065  player.ready(function () {
32066    player.trigger({ type: 'usage', name: 'hls-error-reload-initialized' });
32067  });
32068
32069  /**
32070   * Player modifications to perform that must wait until `loadedmetadata`
32071   * has been triggered
32072   *
32073   * @private
32074   */
32075  var loadedMetadataHandler = function loadedMetadataHandler() {
32076    if (seekTo) {
32077      player.currentTime(seekTo);
32078    }
32079  };
32080
32081  /**
32082   * Set the source on the player element, play, and seek if necessary
32083   *
32084   * @param {Object} sourceObj An object specifying the source url and mime-type to play
32085   * @private
32086   */
32087  var setSource = function setSource(sourceObj) {
32088    if (sourceObj === null || sourceObj === undefined) {
32089      return;
32090    }
32091    seekTo = player.duration() !== Infinity && player.currentTime() || 0;
32092
32093    player.one('loadedmetadata', loadedMetadataHandler);
32094
32095    player.src(sourceObj);
32096    player.trigger({ type: 'usage', name: 'hls-error-reload' });
32097    player.play();
32098  };
32099
32100  /**
32101   * Attempt to get a source from either the built-in getSource function
32102   * or a custom function provided via the options
32103   *
32104   * @private
32105   */
32106  var errorHandler = function errorHandler() {
32107    // Do not attempt to reload the source if a source-reload occurred before
32108    // 'errorInterval' time has elapsed since the last source-reload
32109    if (Date.now() - lastCalled < localOptions.errorInterval * 1000) {
32110      player.trigger({ type: 'usage', name: 'hls-error-reload-canceled' });
32111      return;
32112    }
32113
32114    if (!localOptions.getSource || typeof localOptions.getSource !== 'function') {
32115      _videoJs2['default'].log.error('ERROR: reloadSourceOnError - The option getSource must be a function!');
32116      return;
32117    }
32118    lastCalled = Date.now();
32119
32120    return localOptions.getSource.call(player, setSource);
32121  };
32122
32123  /**
32124   * Unbind any event handlers that were bound by the plugin
32125   *
32126   * @private
32127   */
32128  var cleanupEvents = function cleanupEvents() {
32129    player.off('loadedmetadata', loadedMetadataHandler);
32130    player.off('error', errorHandler);
32131    player.off('dispose', cleanupEvents);
32132  };
32133
32134  /**
32135   * Cleanup before re-initializing the plugin
32136   *
32137   * @param {Object} [newOptions] an object with plugin options
32138   * @private
32139   */
32140  var reinitPlugin = function reinitPlugin(newOptions) {
32141    cleanupEvents();
32142    initPlugin(player, newOptions);
32143  };
32144
32145  player.on('error', errorHandler);
32146  player.on('dispose', cleanupEvents);
32147
32148  // Overwrite the plugin function so that we can correctly cleanup before
32149  // initializing the plugin
32150  player.reloadSourceOnError = reinitPlugin;
32151};
32152
32153/**
32154 * Reload the source when an error is detected as long as there
32155 * wasn't an error previously within the last 30 seconds
32156 *
32157 * @param {Object} [options] an object with plugin options
32158 */
32159var reloadSourceOnError = function reloadSourceOnError(options) {
32160  initPlugin(this, options);
32161};
32162
32163exports['default'] = reloadSourceOnError;
32164module.exports = exports['default'];
32165}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
32166},{}],14:[function(require,module,exports){
32167'use strict';
32168
32169Object.defineProperty(exports, '__esModule', {
32170  value: true
32171});
32172
32173function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
32174
32175var _playlistJs = require('./playlist.js');
32176
32177/**
32178 * Enable/disable playlist function. It is intended to have the first two
32179 * arguments partially-applied in order to create the final per-playlist
32180 * function.
32181 *
32182 * @param {PlaylistLoader} playlist - The rendition or media-playlist
32183 * @param {Function} changePlaylistFn - A function to be called after a
32184 * playlist's enabled-state has been changed. Will NOT be called if a
32185 * playlist's enabled-state is unchanged
32186 * @param {Boolean=} enable - Value to set the playlist enabled-state to
32187 * or if undefined returns the current enabled-state for the playlist
32188 * @return {Boolean} The current enabled-state of the playlist
32189 */
32190var enableFunction = function enableFunction(loader, playlistUri, changePlaylistFn, enable) {
32191  var playlist = loader.master.playlists[playlistUri];
32192  var blacklisted = (0, _playlistJs.isBlacklisted)(playlist);
32193  var currentlyEnabled = (0, _playlistJs.isEnabled)(playlist);
32194
32195  if (typeof enable === 'undefined') {
32196    return currentlyEnabled;
32197  }
32198
32199  if (enable) {
32200    delete playlist.disabled;
32201  } else {
32202    playlist.disabled = true;
32203  }
32204
32205  if (enable !== currentlyEnabled && !blacklisted) {
32206    // Ensure the outside world knows about our changes
32207    changePlaylistFn();
32208    if (enable) {
32209      loader.trigger('renditionenabled');
32210    } else {
32211      loader.trigger('renditiondisabled');
32212    }
32213  }
32214  return enable;
32215};
32216
32217/**
32218 * The representation object encapsulates the publicly visible information
32219 * in a media playlist along with a setter/getter-type function (enabled)
32220 * for changing the enabled-state of a particular playlist entry
32221 *
32222 * @class Representation
32223 */
32224
32225var Representation = function Representation(hlsHandler, playlist, id) {
32226  _classCallCheck(this, Representation);
32227
32228  // Get a reference to a bound version of fastQualityChange_
32229  var fastChangeFunction = hlsHandler.masterPlaylistController_.fastQualityChange_.bind(hlsHandler.masterPlaylistController_);
32230
32231  // some playlist attributes are optional
32232  if (playlist.attributes.RESOLUTION) {
32233    var resolution = playlist.attributes.RESOLUTION;
32234
32235    this.width = resolution.width;
32236    this.height = resolution.height;
32237  }
32238
32239  this.bandwidth = playlist.attributes.BANDWIDTH;
32240
32241  // The id is simply the ordinality of the media playlist
32242  // within the master playlist
32243  this.id = id;
32244
32245  // Partially-apply the enableFunction to create a playlist-
32246  // specific variant
32247  this.enabled = enableFunction.bind(this, hlsHandler.playlists, playlist.uri, fastChangeFunction);
32248}
32249
32250/**
32251 * A mixin function that adds the `representations` api to an instance
32252 * of the HlsHandler class
32253 * @param {HlsHandler} hlsHandler - An instance of HlsHandler to add the
32254 * representation API into
32255 */
32256;
32257
32258var renditionSelectionMixin = function renditionSelectionMixin(hlsHandler) {
32259  var playlists = hlsHandler.playlists;
32260
32261  // Add a single API-specific function to the HlsHandler instance
32262  hlsHandler.representations = function () {
32263    return playlists.master.playlists.filter(function (media) {
32264      return !(0, _playlistJs.isBlacklisted)(media);
32265    }).map(function (e, i) {
32266      return new Representation(hlsHandler, e, e.uri);
32267    });
32268  };
32269};
32270
32271exports['default'] = renditionSelectionMixin;
32272module.exports = exports['default'];
32273},{"./playlist.js":11}],15:[function(require,module,exports){
32274/**
32275 * @file resolve-url.js
32276 */
32277
32278'use strict';
32279
32280Object.defineProperty(exports, '__esModule', {
32281  value: true
32282});
32283
32284function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
32285
32286var _urlToolkit = require('url-toolkit');
32287
32288var _urlToolkit2 = _interopRequireDefault(_urlToolkit);
32289
32290var _globalWindow = require('global/window');
32291
32292var _globalWindow2 = _interopRequireDefault(_globalWindow);
32293
32294var resolveUrl = function resolveUrl(baseURL, relativeURL) {
32295  // return early if we don't need to resolve
32296  if (/^[a-z]+:/i.test(relativeURL)) {
32297    return relativeURL;
32298  }
32299
32300  // if the base URL is relative then combine with the current location
32301  if (!/\/\//i.test(baseURL)) {
32302    baseURL = _urlToolkit2['default'].buildAbsoluteURL(_globalWindow2['default'].location.href, baseURL);
32303  }
32304
32305  return _urlToolkit2['default'].buildAbsoluteURL(baseURL, relativeURL);
32306};
32307
32308exports['default'] = resolveUrl;
32309module.exports = exports['default'];
32310},{"global/window":32,"url-toolkit":63}],16:[function(require,module,exports){
32311(function (global){
32312/**
32313 * @file segment-loader.js
32314 */
32315'use strict';
32316
32317Object.defineProperty(exports, '__esModule', {
32318  value: true
32319});
32320
32321var _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; }; })();
32322
32323var _get = function get(_x4, _x5, _x6) { var _again = true; _function: while (_again) { var object = _x4, property = _x5, receiver = _x6; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x4 = parent; _x5 = property; _x6 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
32324
32325function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
32326
32327function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
32328
32329function _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; }
32330
32331var _playlist = require('./playlist');
32332
32333var _playlist2 = _interopRequireDefault(_playlist);
32334
32335var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
32336
32337var _videoJs2 = _interopRequireDefault(_videoJs);
32338
32339var _sourceUpdater = require('./source-updater');
32340
32341var _sourceUpdater2 = _interopRequireDefault(_sourceUpdater);
32342
32343var _config = require('./config');
32344
32345var _config2 = _interopRequireDefault(_config);
32346
32347var _globalWindow = require('global/window');
32348
32349var _globalWindow2 = _interopRequireDefault(_globalWindow);
32350
32351var _videojsContribMediaSourcesEs5RemoveCuesFromTrackJs = require('videojs-contrib-media-sources/es5/remove-cues-from-track.js');
32352
32353var _videojsContribMediaSourcesEs5RemoveCuesFromTrackJs2 = _interopRequireDefault(_videojsContribMediaSourcesEs5RemoveCuesFromTrackJs);
32354
32355var _binUtils = require('./bin-utils');
32356
32357var _mediaSegmentRequest = require('./media-segment-request');
32358
32359var _ranges = require('./ranges');
32360
32361var _playlistSelectors = require('./playlist-selectors');
32362
32363// in ms
32364var CHECK_BUFFER_DELAY = 500;
32365
32366/**
32367 * Determines if we should call endOfStream on the media source based
32368 * on the state of the buffer or if appened segment was the final
32369 * segment in the playlist.
32370 *
32371 * @param {Object} playlist a media playlist object
32372 * @param {Object} mediaSource the MediaSource object
32373 * @param {Number} segmentIndex the index of segment we last appended
32374 * @returns {Boolean} do we need to call endOfStream on the MediaSource
32375 */
32376var detectEndOfStream = function detectEndOfStream(playlist, mediaSource, segmentIndex) {
32377  if (!playlist || !mediaSource) {
32378    return false;
32379  }
32380
32381  var segments = playlist.segments;
32382
32383  // determine a few boolean values to help make the branch below easier
32384  // to read
32385  var appendedLastSegment = segmentIndex === segments.length;
32386
32387  // if we've buffered to the end of the video, we need to call endOfStream
32388  // so that MediaSources can trigger the `ended` event when it runs out of
32389  // buffered data instead of waiting for me
32390  return playlist.endList && mediaSource.readyState === 'open' && appendedLastSegment;
32391};
32392
32393var finite = function finite(num) {
32394  return typeof num === 'number' && isFinite(num);
32395};
32396
32397var illegalMediaSwitch = function illegalMediaSwitch(loaderType, startingMedia, newSegmentMedia) {
32398  // Although these checks should most likely cover non 'main' types, for now it narrows
32399  // the scope of our checks.
32400  if (loaderType !== 'main' || !startingMedia || !newSegmentMedia) {
32401    return null;
32402  }
32403
32404  if (!newSegmentMedia.containsAudio && !newSegmentMedia.containsVideo) {
32405    return 'Neither audio nor video found in segment.';
32406  }
32407
32408  if (startingMedia.containsVideo && !newSegmentMedia.containsVideo) {
32409    return 'Only audio found in segment when we expected video.' + ' We can\'t switch to audio only from a stream that had video.' + ' To get rid of this message, please add codec information to the manifest.';
32410  }
32411
32412  if (!startingMedia.containsVideo && newSegmentMedia.containsVideo) {
32413    return 'Video found in segment when we expected only audio.' + ' We can\'t switch to a stream with video from an audio only stream.' + ' To get rid of this message, please add codec information to the manifest.';
32414  }
32415
32416  return null;
32417};
32418
32419exports.illegalMediaSwitch = illegalMediaSwitch
vendor: 28,468 bytes, lines 32419-33283
32419;
32420/**
32421 * An object that manages segment loading and appending.
32422 *
32423 * @class SegmentLoader
32424 * @param {Object} options required and optional options
32425 * @extends videojs.EventTarget
32426 */
32427
32428var SegmentLoader = (function (_videojs$EventTarget) {
32429  _inherits(SegmentLoader, _videojs$EventTarget);
32430
32431  function SegmentLoader(settings) {
32432    var _this = this;
32433
32434    var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
32435
32436    _classCallCheck(this, SegmentLoader);
32437
32438    _get(Object.getPrototypeOf(SegmentLoader.prototype), 'constructor', this).call(this);
32439    // check pre-conditions
32440    if (!settings) {
32441      throw new TypeError('Initialization settings are required');
32442    }
32443    if (typeof settings.currentTime !== 'function') {
32444      throw new TypeError('No currentTime getter specified');
32445    }
32446    if (!settings.mediaSource) {
32447      throw new TypeError('No MediaSource specified');
32448    }
32449    // public properties
32450    this.state = 'INIT';
32451    this.bandwidth = settings.bandwidth;
32452    this.throughput = { rate: 0, count: 0 };
32453    this.roundTrip = NaN;
32454    this.resetStats_();
32455    this.mediaIndex = null;
32456
32457    // private settings
32458    this.hasPlayed_ = settings.hasPlayed;
32459    this.currentTime_ = settings.currentTime;
32460    this.seekable_ = settings.seekable;
32461    this.seeking_ = settings.seeking;
32462    this.duration_ = settings.duration;
32463    this.mediaSource_ = settings.mediaSource;
32464    this.hls_ = settings.hls;
32465    this.loaderType_ = settings.loaderType;
32466    this.startingMedia_ = void 0;
32467    this.segmentMetadataTrack_ = settings.segmentMetadataTrack;
32468    this.goalBufferLength_ = settings.goalBufferLength;
32469
32470    // private instance variables
32471    this.checkBufferTimeout_ = null;
32472    this.error_ = void 0;
32473    this.currentTimeline_ = -1;
32474    this.pendingSegment_ = null;
32475    this.mimeType_ = null;
32476    this.sourceUpdater_ = null;
32477    this.xhrOptions_ = null;
32478
32479    // Fragmented mp4 playback
32480    this.activeInitSegmentId_ = null;
32481    this.initSegments_ = {};
32482
32483    this.decrypter_ = settings.decrypter;
32484
32485    // Manages the tracking and generation of sync-points, mappings
32486    // between a time in the display time and a segment index within
32487    // a playlist
32488    this.syncController_ = settings.syncController;
32489    this.syncPoint_ = {
32490      segmentIndex: 0,
32491      time: 0
32492    };
32493
32494    this.syncController_.on('syncinfoupdate', function () {
32495      return _this.trigger('syncinfoupdate');
32496    });
32497
32498    this.mediaSource_.addEventListener('sourceopen', function () {
32499      return _this.ended_ = false;
32500    });
32501
32502    // ...for determining the fetch location
32503    this.fetchAtBuffer_ = false;
32504
32505    if (options.debug) {
32506      this.logger_ = _videoJs2['default'].log.bind(_videoJs2['default'], 'segment-loader', this.loaderType_, '->');
32507    }
32508  }
32509
32510  /**
32511   * reset all of our media stats
32512   *
32513   * @private
32514   */
32515
32516  _createClass(SegmentLoader, [{
32517    key: 'resetStats_',
32518    value: function resetStats_() {
32519      this.mediaBytesTransferred = 0;
32520      this.mediaRequests = 0;
32521      this.mediaRequestsAborted = 0;
32522      this.mediaRequestsTimedout = 0;
32523      this.mediaRequestsErrored = 0;
32524      this.mediaTransferDuration = 0;
32525      this.mediaSecondsLoaded = 0;
32526    }
32527
32528    /**
32529     * dispose of the SegmentLoader and reset to the default state
32530     */
32531  }, {
32532    key: 'dispose',
32533    value: function dispose() {
32534      this.state = 'DISPOSED';
32535      this.pause();
32536      this.abort_();
32537      if (this.sourceUpdater_) {
32538        this.sourceUpdater_.dispose();
32539      }
32540      this.resetStats_();
32541    }
32542
32543    /**
32544     * abort anything that is currently doing on with the SegmentLoader
32545     * and reset to a default state
32546     */
32547  }, {
32548    key: 'abort',
32549    value: function abort() {
32550      if (this.state !== 'WAITING') {
32551        if (this.pendingSegment_) {
32552          this.pendingSegment_ = null;
32553        }
32554        return;
32555      }
32556
32557      this.abort_();
32558
32559      // We aborted the requests we were waiting on, so reset the loader's state to READY
32560      // since we are no longer "waiting" on any requests. XHR callback is not always run
32561      // when the request is aborted. This will prevent the loader from being stuck in the
32562      // WAITING state indefinitely.
32563      this.state = 'READY';
32564
32565      // don't wait for buffer check timeouts to begin fetching the
32566      // next segment
32567      if (!this.paused()) {
32568        this.monitorBuffer_();
32569      }
32570    }
32571
32572    /**
32573     * abort all pending xhr requests and null any pending segements
32574     *
32575     * @private
32576     */
32577  }, {
32578    key: 'abort_',
32579    value: function abort_() {
32580      if (this.pendingSegment_) {
32581        this.pendingSegment_.abortRequests();
32582      }
32583
32584      // clear out the segment being processed
32585      this.pendingSegment_ = null;
32586    }
32587
32588    /**
32589     * set an error on the segment loader and null out any pending segements
32590     *
32591     * @param {Error} error the error to set on the SegmentLoader
32592     * @return {Error} the error that was set or that is currently set
32593     */
32594  }, {
32595    key: 'error',
32596    value: function error(_error) {
32597      if (typeof _error !== 'undefined') {
32598        this.error_ = _error;
32599      }
32600
32601      this.pendingSegment_ = null;
32602      return this.error_;
32603    }
32604  }, {
32605    key: 'endOfStream',
32606    value: function endOfStream() {
32607      this.ended_ = true;
32608      this.pause();
32609      this.trigger('ended');
32610    }
32611
32612    /**
32613     * Indicates which time ranges are buffered
32614     *
32615     * @return {TimeRange}
32616     *         TimeRange object representing the current buffered ranges
32617     */
32618  }, {
32619    key: 'buffered_',
32620    value: function buffered_() {
32621      if (!this.sourceUpdater_) {
32622        return _videoJs2['default'].createTimeRanges();
32623      }
32624
32625      return this.sourceUpdater_.buffered();
32626    }
32627
32628    /**
32629     * Gets and sets init segment for the provided map
32630     *
32631     * @param {Object} map
32632     *        The map object representing the init segment to get or set
32633     * @param {Boolean=} set
32634     *        If true, the init segment for the provided map should be saved
32635     * @return {Object}
32636     *         map object for desired init segment
32637     */
32638  }, {
32639    key: 'initSegment',
32640    value: function initSegment(map) {
32641      var set = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
32642
32643      if (!map) {
32644        return null;
32645      }
32646
32647      var id = (0, _binUtils.initSegmentId)(map);
32648      var storedMap = this.initSegments_[id];
32649
32650      if (set && !storedMap && map.bytes) {
32651        this.initSegments_[id] = storedMap = {
32652          resolvedUri: map.resolvedUri,
32653          byterange: map.byterange,
32654          bytes: map.bytes
32655        };
32656      }
32657
32658      return storedMap || map;
32659    }
32660
32661    /**
32662     * Returns true if all configuration required for loading is present, otherwise false.
32663     *
32664     * @return {Boolean} True if the all configuration is ready for loading
32665     * @private
32666     */
32667  }, {
32668    key: 'couldBeginLoading_',
32669    value: function couldBeginLoading_() {
32670      return this.playlist_ && (
32671      // the source updater is created when init_ is called, so either having a
32672      // source updater or being in the INIT state with a mimeType is enough
32673      // to say we have all the needed configuration to start loading.
32674      this.sourceUpdater_ || this.mimeType_ && this.state === 'INIT') && !this.paused();
32675    }
32676
32677    /**
32678     * load a playlist and start to fill the buffer
32679     */
32680  }, {
32681    key: 'load',
32682    value: function load() {
32683      // un-pause
32684      this.monitorBuffer_();
32685
32686      // if we don't have a playlist yet, keep waiting for one to be
32687      // specified
32688      if (!this.playlist_) {
32689        return;
32690      }
32691
32692      // not sure if this is the best place for this
32693      this.syncController_.setDateTimeMapping(this.playlist_);
32694
32695      // if all the configuration is ready, initialize and begin loading
32696      if (this.state === 'INIT' && this.couldBeginLoading_()) {
32697        return this.init_();
32698      }
32699
32700      // if we're in the middle of processing a segment already, don't
32701      // kick off an additional segment request
32702      if (!this.couldBeginLoading_() || this.state !== 'READY' && this.state !== 'INIT') {
32703        return;
32704      }
32705
32706      this.state = 'READY';
32707    }
32708
32709    /**
32710     * Once all the starting parameters have been specified, begin
32711     * operation. This method should only be invoked from the INIT
32712     * state.
32713     *
32714     * @private
32715     */
32716  }, {
32717    key: 'init_',
32718    value: function init_() {
32719      this.state = 'READY';
32720      this.sourceUpdater_ = new _sourceUpdater2['default'](this.mediaSource_, this.mimeType_);
32721      this.resetEverything();
32722      return this.monitorBuffer_();
32723    }
32724
32725    /**
32726     * set a playlist on the segment loader
32727     *
32728     * @param {PlaylistLoader} media the playlist to set on the segment loader
32729     */
32730  }, {
32731    key: 'playlist',
32732    value: function playlist(newPlaylist) {
32733      var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
32734
32735      if (!newPlaylist) {
32736        return;
32737      }
32738
32739      var oldPlaylist = this.playlist_;
32740      var segmentInfo = this.pendingSegment_;
32741
32742      this.playlist_ = newPlaylist;
32743      this.xhrOptions_ = options;
32744
32745      // when we haven't started playing yet, the start of a live playlist
32746      // is always our zero-time so force a sync update each time the playlist
32747      // is refreshed from the server
32748      if (!this.hasPlayed_()) {
32749        newPlaylist.syncInfo = {
32750          mediaSequence: newPlaylist.mediaSequence,
32751          time: 0
32752        };
32753      }
32754
32755      // in VOD, this is always a rendition switch (or we updated our syncInfo above)
32756      // in LIVE, we always want to update with new playlists (including refreshes)
32757      this.trigger('syncinfoupdate');
32758
32759      // if we were unpaused but waiting for a playlist, start
32760      // buffering now
32761      if (this.state === 'INIT' && this.couldBeginLoading_()) {
32762        return this.init_();
32763      }
32764
32765      if (!oldPlaylist || oldPlaylist.uri !== newPlaylist.uri) {
32766        if (this.mediaIndex !== null) {
32767          // we must "resync" the segment loader when we switch renditions and
32768          // the segment loader is already synced to the previous rendition
32769          this.resyncLoader();
32770        }
32771
32772        // the rest of this function depends on `oldPlaylist` being defined
32773        return;
32774      }
32775
32776      // we reloaded the same playlist so we are in a live scenario
32777      // and we will likely need to adjust the mediaIndex
32778      var mediaSequenceDiff = newPlaylist.mediaSequence - oldPlaylist.mediaSequence;
32779
32780      this.logger_('mediaSequenceDiff', mediaSequenceDiff);
32781
32782      // update the mediaIndex on the SegmentLoader
32783      // this is important because we can abort a request and this value must be
32784      // equal to the last appended mediaIndex
32785      if (this.mediaIndex !== null) {
32786        this.mediaIndex -= mediaSequenceDiff;
32787      }
32788
32789      // update the mediaIndex on the SegmentInfo object
32790      // this is important because we will update this.mediaIndex with this value
32791      // in `handleUpdateEnd_` after the segment has been successfully appended
32792      if (segmentInfo) {
32793        segmentInfo.mediaIndex -= mediaSequenceDiff;
32794
32795        // we need to update the referenced segment so that timing information is
32796        // saved for the new playlist's segment, however, if the segment fell off the
32797        // playlist, we can leave the old reference and just lose the timing info
32798        if (segmentInfo.mediaIndex >= 0) {
32799          segmentInfo.segment = newPlaylist.segments[segmentInfo.mediaIndex];
32800        }
32801      }
32802
32803      this.syncController_.saveExpiredSegmentInfo(oldPlaylist, newPlaylist);
32804    }
32805
32806    /**
32807     * Prevent the loader from fetching additional segments. If there
32808     * is a segment request outstanding, it will finish processing
32809     * before the loader halts. A segment loader can be unpaused by
32810     * calling load().
32811     */
32812  }, {
32813    key: 'pause',
32814    value: function pause() {
32815      if (this.checkBufferTimeout_) {
32816        _globalWindow2['default'].clearTimeout(this.checkBufferTimeout_);
32817
32818        this.checkBufferTimeout_ = null;
32819      }
32820    }
32821
32822    /**
32823     * Returns whether the segment loader is fetching additional
32824     * segments when given the opportunity. This property can be
32825     * modified through calls to pause() and load().
32826     */
32827  }, {
32828    key: 'paused',
32829    value: function paused() {
32830      return this.checkBufferTimeout_ === null;
32831    }
32832
32833    /**
32834     * create/set the following mimetype on the SourceBuffer through a
32835     * SourceUpdater
32836     *
32837     * @param {String} mimeType the mime type string to use
32838     */
32839  }, {
32840    key: 'mimeType',
32841    value: function mimeType(_mimeType) {
32842      if (this.mimeType_) {
32843        return;
32844      }
32845
32846      this.mimeType_ = _mimeType;
32847      // if we were unpaused but waiting for a sourceUpdater, start
32848      // buffering now
32849      if (this.state === 'INIT' && this.couldBeginLoading_()) {
32850        this.init_();
32851      }
32852    }
32853
32854    /**
32855     * Delete all the buffered data and reset the SegmentLoader
32856     */
32857  }, {
32858    key: 'resetEverything',
32859    value: function resetEverything() {
32860      this.ended_ = false;
32861      this.resetLoader();
32862      this.remove(0, this.duration_());
32863      this.trigger('reseteverything');
32864    }
32865
32866    /**
32867     * Force the SegmentLoader to resync and start loading around the currentTime instead
32868     * of starting at the end of the buffer
32869     *
32870     * Useful for fast quality changes
32871     */
32872  }, {
32873    key: 'resetLoader',
32874    value: function resetLoader() {
32875      this.fetchAtBuffer_ = false;
32876      this.resyncLoader();
32877    }
32878
32879    /**
32880     * Force the SegmentLoader to restart synchronization and make a conservative guess
32881     * before returning to the simple walk-forward method
32882     */
32883  }, {
32884    key: 'resyncLoader',
32885    value: function resyncLoader() {
32886      this.mediaIndex = null;
32887      this.syncPoint_ = null;
32888      this.abort();
32889    }
32890
32891    /**
32892     * Remove any data in the source buffer between start and end times
32893     * @param {Number} start - the start time of the region to remove from the buffer
32894     * @param {Number} end - the end time of the region to remove from the buffer
32895     */
32896  }, {
32897    key: 'remove',
32898    value: function remove(start, end) {
32899      if (this.sourceUpdater_) {
32900        this.sourceUpdater_.remove(start, end);
32901      }
32902      (0, _videojsContribMediaSourcesEs5RemoveCuesFromTrackJs2['default'])(start, end, this.segmentMetadataTrack_);
32903    }
32904
32905    /**
32906     * (re-)schedule monitorBufferTick_ to run as soon as possible
32907     *
32908     * @private
32909     */
32910  }, {
32911    key: 'monitorBuffer_',
32912    value: function monitorBuffer_() {
32913      if (this.checkBufferTimeout_) {
32914        _globalWindow2['default'].clearTimeout(this.checkBufferTimeout_);
32915      }
32916
32917      this.checkBufferTimeout_ = _globalWindow2['default'].setTimeout(this.monitorBufferTick_.bind(this), 1);
32918    }
32919
32920    /**
32921     * As long as the SegmentLoader is in the READY state, periodically
32922     * invoke fillBuffer_().
32923     *
32924     * @private
32925     */
32926  }, {
32927    key: 'monitorBufferTick_',
32928    value: function monitorBufferTick_() {
32929      if (this.state === 'READY') {
32930        this.fillBuffer_();
32931      }
32932
32933      if (this.checkBufferTimeout_) {
32934        _globalWindow2['default'].clearTimeout(this.checkBufferTimeout_);
32935      }
32936
32937      this.checkBufferTimeout_ = _globalWindow2['default'].setTimeout(this.monitorBufferTick_.bind(this), CHECK_BUFFER_DELAY);
32938    }
32939
32940    /**
32941     * fill the buffer with segements unless the sourceBuffers are
32942     * currently updating
32943     *
32944     * Note: this function should only ever be called by monitorBuffer_
32945     * and never directly
32946     *
32947     * @private
32948     */
32949  }, {
32950    key: 'fillBuffer_',
32951    value: function fillBuffer_() {
32952      if (this.sourceUpdater_.updating()) {
32953        return;
32954      }
32955
32956      if (!this.syncPoint_) {
32957        this.syncPoint_ = this.syncController_.getSyncPoint(this.playlist_, this.duration_(), this.currentTimeline_, this.currentTime_());
32958      }
32959
32960      // see if we need to begin loading immediately
32961      var segmentInfo = this.checkBuffer_(this.buffered_(), this.playlist_, this.mediaIndex, this.hasPlayed_(), this.currentTime_(), this.syncPoint_);
32962
32963      if (!segmentInfo) {
32964        return;
32965      }
32966
32967      var isEndOfStream = detectEndOfStream(this.playlist_, this.mediaSource_, segmentInfo.mediaIndex);
32968
32969      if (isEndOfStream) {
32970        this.endOfStream();
32971        return;
32972      }
32973
32974      if (segmentInfo.mediaIndex === this.playlist_.segments.length - 1 && this.mediaSource_.readyState === 'ended' && !this.seeking_()) {
32975        return;
32976      }
32977
32978      // We will need to change timestampOffset of the sourceBuffer if either of
32979      // the following conditions are true:
32980      // - The segment.timeline !== this.currentTimeline
32981      //   (we are crossing a discontinuity somehow)
32982      // - The "timestampOffset" for the start of this segment is less than
32983      //   the currently set timestampOffset
32984      if (segmentInfo.timeline !== this.currentTimeline_ || segmentInfo.startOfSegment !== null && segmentInfo.startOfSegment < this.sourceUpdater_.timestampOffset()) {
32985        this.syncController_.reset();
32986        segmentInfo.timestampOffset = segmentInfo.startOfSegment;
32987      }
32988
32989      this.loadSegment_(segmentInfo);
32990    }
32991
32992    /**
32993     * Determines what segment request should be made, given current playback
32994     * state.
32995     *
32996     * @param {TimeRanges} buffered - the state of the buffer
32997     * @param {Object} playlist - the playlist object to fetch segments from
32998     * @param {Number} mediaIndex - the previous mediaIndex fetched or null
32999     * @param {Boolean} hasPlayed - a flag indicating whether we have played or not
33000     * @param {Number} currentTime - the playback position in seconds
33001     * @param {Object} syncPoint - a segment info object that describes the
33002     * @returns {Object} a segment request object that describes the segment to load
33003     */
33004  }, {
33005    key: 'checkBuffer_',
33006    value: function checkBuffer_(buffered, playlist, mediaIndex, hasPlayed, currentTime, syncPoint) {
33007      var lastBufferedEnd = 0;
33008      var startOfSegment = undefined;
33009
33010      if (buffered.length) {
33011        lastBufferedEnd = buffered.end(buffered.length - 1);
33012      }
33013
33014      var bufferedTime = Math.max(0, lastBufferedEnd - currentTime);
33015
33016      if (!playlist.segments.length) {
33017        return null;
33018      }
33019
33020      // if there is plenty of content buffered, and the video has
33021      // been played before relax for awhile
33022      if (bufferedTime >= this.goalBufferLength_()) {
33023        return null;
33024      }
33025
33026      // if the video has not yet played once, and we already have
33027      // one segment downloaded do nothing
33028      if (!hasPlayed && bufferedTime >= 1) {
33029        return null;
33030      }
33031
33032      this.logger_('checkBuffer_', 'mediaIndex:', mediaIndex, 'hasPlayed:', hasPlayed, 'currentTime:', currentTime, 'syncPoint:', syncPoint, 'fetchAtBuffer:', this.fetchAtBuffer_, 'bufferedTime:', bufferedTime);
33033
33034      // When the syncPoint is null, there is no way of determining a good
33035      // conservative segment index to fetch from
33036      // The best thing to do here is to get the kind of sync-point data by
33037      // making a request
33038      if (syncPoint === null) {
33039        mediaIndex = this.getSyncSegmentCandidate_(playlist);
33040        this.logger_('getSync', 'mediaIndex:', mediaIndex);
33041        return this.generateSegmentInfo_(playlist, mediaIndex, null, true);
33042      }
33043
33044      // Under normal playback conditions fetching is a simple walk forward
33045      if (mediaIndex !== null) {
33046        this.logger_('walkForward', 'mediaIndex:', mediaIndex + 1);
33047        var segment = playlist.segments[mediaIndex];
33048
33049        if (segment && segment.end) {
33050          startOfSegment = segment.end;
33051        } else {
33052          startOfSegment = lastBufferedEnd;
33053        }
33054        return this.generateSegmentInfo_(playlist, mediaIndex + 1, startOfSegment, false);
33055      }
33056
33057      // There is a sync-point but the lack of a mediaIndex indicates that
33058      // we need to make a good conservative guess about which segment to
33059      // fetch
33060      if (this.fetchAtBuffer_) {
33061        // Find the segment containing the end of the buffer
33062        var mediaSourceInfo = _playlist2['default'].getMediaInfoForTime(playlist, lastBufferedEnd, syncPoint.segmentIndex, syncPoint.time);
33063
33064        mediaIndex = mediaSourceInfo.mediaIndex;
33065        startOfSegment = mediaSourceInfo.startTime;
33066      } else {
33067        // Find the segment containing currentTime
33068        var mediaSourceInfo = _playlist2['default'].getMediaInfoForTime(playlist, currentTime, syncPoint.segmentIndex, syncPoint.time);
33069
33070        mediaIndex = mediaSourceInfo.mediaIndex;
33071        startOfSegment = mediaSourceInfo.startTime;
33072      }
33073      this.logger_('getMediaIndexForTime', 'mediaIndex:', mediaIndex, 'startOfSegment:', startOfSegment);
33074
33075      return this.generateSegmentInfo_(playlist, mediaIndex, startOfSegment, false);
33076    }
33077
33078    /**
33079     * The segment loader has no recourse except to fetch a segment in the
33080     * current playlist and use the internal timestamps in that segment to
33081     * generate a syncPoint. This function returns a good candidate index
33082     * for that process.
33083     *
33084     * @param {Object} playlist - the playlist object to look for a
33085     * @returns {Number} An index of a segment from the playlist to load
33086     */
33087  }, {
33088    key: 'getSyncSegmentCandidate_',
33089    value: function getSyncSegmentCandidate_(playlist) {
33090      var _this2 = this;
33091
33092      if (this.currentTimeline_ === -1) {
33093        return 0;
33094      }
33095
33096      var segmentIndexArray = playlist.segments.map(function (s, i) {
33097        return {
33098          timeline: s.timeline,
33099          segmentIndex: i
33100        };
33101      }).filter(function (s) {
33102        return s.timeline === _this2.currentTimeline_;
33103      });
33104
33105      if (segmentIndexArray.length) {
33106        return segmentIndexArray[Math.min(segmentIndexArray.length - 1, 1)].segmentIndex;
33107      }
33108
33109      return Math.max(playlist.segments.length - 1, 0);
33110    }
33111  }, {
33112    key: 'generateSegmentInfo_',
33113    value: function generateSegmentInfo_(playlist, mediaIndex, startOfSegment, isSyncRequest) {
33114      if (mediaIndex < 0 || mediaIndex >= playlist.segments.length) {
33115        return null;
33116      }
33117
33118      var segment = playlist.segments[mediaIndex];
33119
33120      return {
33121        requestId: 'segment-loader-' + Math.random(),
33122        // resolve the segment URL relative to the playlist
33123        uri: segment.resolvedUri,
33124        // the segment's mediaIndex at the time it was requested
33125        mediaIndex: mediaIndex,
33126        // whether or not to update the SegmentLoader's state with this
33127        // segment's mediaIndex
33128        isSyncRequest: isSyncRequest,
33129        startOfSegment: startOfSegment,
33130        // the segment's playlist
33131        playlist: playlist,
33132        // unencrypted bytes of the segment
33133        bytes: null,
33134        // when a key is defined for this segment, the encrypted bytes
33135        encryptedBytes: null,
33136        // The target timestampOffset for this segment when we append it
33137        // to the source buffer
33138        timestampOffset: null,
33139        // The timeline that the segment is in
33140        timeline: segment.timeline,
33141        // The expected duration of the segment in seconds
33142        duration: segment.duration,
33143        // retain the segment in case the playlist updates while doing an async process
33144        segment: segment
33145      };
33146    }
33147
33148    /**
33149     * Determines if the network has enough bandwidth to complete the current segment
33150     * request in a timely manner. If not, the request will be aborted early and bandwidth
33151     * updated to trigger a playlist switch.
33152     *
33153     * @param {Object} stats
33154     *        Object containing stats about the request timing and size
33155     * @return {Boolean} True if the request was aborted, false otherwise
33156     * @private
33157     */
33158  }, {
33159    key: 'abortRequestEarly_',
33160    value: function abortRequestEarly_(stats) {
33161      if (this.hls_.tech_.paused() ||
33162      // Don't abort if the current playlist is on the lowestEnabledRendition
33163      // TODO: Replace using timeout with a boolean indicating whether this playlist is
33164      //       the lowestEnabledRendition.
33165      !this.xhrOptions_.timeout ||
33166      // Don't abort if we have no bandwidth information to estimate segment sizes
33167      !this.playlist_.attributes.BANDWIDTH) {
33168        return false;
33169      }
33170
33171      // Wait at least 1 second since the first byte of data has been received before
33172      // using the calculated bandwidth from the progress event to allow the bitrate
33173      // to stabilize
33174      if (Date.now() - (stats.firstBytesReceivedAt || Date.now()) < 1000) {
33175        return false;
33176      }
33177
33178      var currentTime = this.currentTime_();
33179      var measuredBandwidth = stats.bandwidth;
33180      var segmentDuration = this.pendingSegment_.duration;
33181
33182      var requestTimeRemaining = _playlist2['default'].estimateSegmentRequestTime(segmentDuration, measuredBandwidth, this.playlist_, stats.bytesReceived);
33183
33184      // Subtract 1 from the timeUntilRebuffer so we still consider an early abort
33185      // if we are only left with less than 1 second when the request completes.
33186      // A negative timeUntilRebuffering indicates we are already rebuffering
33187      var timeUntilRebuffer = (0, _ranges.timeUntilRebuffer)(this.buffered_(), currentTime, this.hls_.tech_.playbackRate()) - 1;
33188
33189      // Only consider aborting early if the estimated time to finish the download
33190      // is larger than the estimated time until the player runs out of forward buffer
33191      if (requestTimeRemaining <= timeUntilRebuffer) {
33192        return false;
33193      }
33194
33195      var switchCandidate = (0, _playlistSelectors.minRebufferMaxBandwidthSelector)({
33196        master: this.hls_.playlists.master,
33197        currentTime: currentTime,
33198        bandwidth: measuredBandwidth,
33199        duration: this.duration_(),
33200        segmentDuration: segmentDuration,
33201        timeUntilRebuffer: timeUntilRebuffer,
33202        currentTimeline: this.currentTimeline_,
33203        syncController: this.syncController_
33204      });
33205
33206      if (!switchCandidate) {
33207        return;
33208      }
33209
33210      var rebufferingImpact = requestTimeRemaining - timeUntilRebuffer;
33211
33212      var timeSavedBySwitching = rebufferingImpact - switchCandidate.rebufferingImpact;
33213
33214      var minimumTimeSaving = 0.5;
33215
33216      // If we are already rebuffering, increase the amount of variance we add to the
33217      // potential round trip time of the new request so that we are not too aggressive
33218      // with switching to a playlist that might save us a fraction of a second.
33219      if (timeUntilRebuffer <= _ranges.TIME_FUDGE_FACTOR) {
33220        minimumTimeSaving = 1;
33221      }
33222
33223      if (!switchCandidate.playlist || switchCandidate.playlist.uri === this.playlist_.uri || timeSavedBySwitching < minimumTimeSaving) {
33224        return false;
33225      }
33226
33227      // set the bandwidth to that of the desired playlist being sure to scale by
33228      // BANDWIDTH_VARIANCE and add one so the playlist selector does not exclude it
33229      // don't trigger a bandwidthupdate as the bandwidth is artifial
33230      this.bandwidth = switchCandidate.playlist.attributes.BANDWIDTH * _config2['default'].BANDWIDTH_VARIANCE + 1;
33231      this.abort();
33232      this.trigger('earlyabort');
33233      return true;
33234    }
33235
33236    /**
33237     * XHR `progress` event handler
33238     *
33239     * @param {Event}
33240     *        The XHR `progress` event
33241     * @param {Object} simpleSegment
33242     *        A simplified segment object copy
33243     * @private
33244     */
33245  }, {
33246    key: 'handleProgress_',
33247    value: function handleProgress_(event, simpleSegment) {
33248      if (!this.pendingSegment_ || simpleSegment.requestId !== this.pendingSegment_.requestId || this.abortRequestEarly_(simpleSegment.stats)) {
33249        return;
33250      }
33251
33252      this.trigger('progress');
33253    }
33254
33255    /**
33256     * load a specific segment from a request into the buffer
33257     *
33258     * @private
33259     */
33260  }, {
33261    key: 'loadSegment_',
33262    value: function loadSegment_(segmentInfo) {
33263      this.state = 'WAITING';
33264      this.pendingSegment_ = segmentInfo;
33265      this.trimBackBuffer_(segmentInfo);
33266
33267      segmentInfo.abortRequests = (0, _mediaSegmentRequest.mediaSegmentRequest)(this.hls_.xhr, this.xhrOptions_, this.decrypter_, this.createSimplifiedSegmentObj_(segmentInfo),
33268      // progress callback
33269      this.handleProgress_.bind(this), this.segmentRequestFinished_.bind(this));
33270    }
33271
33272    /**
33273     * trim the back buffer so that we don't have too much data
33274     * in the source buffer
33275     *
33276     * @private
33277     *
33278     * @param {Object} segmentInfo - the current segment
33279     */
33280  }, {
33281    key: 'trimBackBuffer_',
33282    value: function trimBackBuffer_(segmentInfo) {
33283      var 
33283seekable = this.seekable_();
33284      var currentTime = this.currentTime_();
33285      var removeToTime = 0;
33286
33287      // Chrome has a hard limit of 150MB of
33288      // buffer and a very conservative "garbage collector"
33289      // We manually clear out the old buffer to ensure
33290      // we don't trigger the QuotaExceeded error
33291      // on the source buffer during subsequent appends
33292
33293      // If we have a seekable range use that as the limit for what can be removed safely
33294      // otherwise remove anything older than 30 seconds before the current play head
33295      if (seekable.length && seekable.start(0) > 0 && seekable.start(0) < currentTime) {
33296        removeToTime = seekable.start(0);
33297      } else {
33298        removeToTime = currentTime - 30;
33299      }
33300
33301      if (removeToTime > 0) {
33302        this.remove(0, removeToTime);
33303      }
33304    }
33305
33306    /**
33307     * created a simplified copy of the segment object with just the
33308     * information necessary to perform the XHR and decryption
33309     *
33310     * @private
33311     *
33312     * @param {Object} segmentInfo - the current segment
33313     * @returns {Object}
vendor: 14,230 bytes, lines 33313-33705
33313 a simplified segment object copy
33314     */
33315  }, {
33316    key: 'createSimplifiedSegmentObj_',
33317    value: function createSimplifiedSegmentObj_(segmentInfo) {
33318      var segment = segmentInfo.segment;
33319      var simpleSegment = {
33320        resolvedUri: segment.resolvedUri,
33321        byterange: segment.byterange,
33322        requestId: segmentInfo.requestId
33323      };
33324
33325      if (segment.key) {
33326        // if the media sequence is greater than 2^32, the IV will be incorrect
33327        // assuming 10s segments, that would be about 1300 years
33328        var iv = segment.key.iv || new Uint32Array([0, 0, 0, segmentInfo.mediaIndex + segmentInfo.playlist.mediaSequence]);
33329
33330        simpleSegment.key = {
33331          resolvedUri: segment.key.resolvedUri,
33332          iv: iv
33333        };
33334      }
33335
33336      if (segment.map) {
33337        simpleSegment.map = this.initSegment(segment.map);
33338      }
33339
33340      return simpleSegment;
33341    }
33342
33343    /**
33344     * Handle the callback from the segmentRequest function and set the
33345     * associated SegmentLoader state and errors if necessary
33346     *
33347     * @private
33348     */
33349  }, {
33350    key: 'segmentRequestFinished_',
33351    value: function segmentRequestFinished_(error, simpleSegment) {
33352      // every request counts as a media request even if it has been aborted
33353      // or canceled due to a timeout
33354      this.mediaRequests += 1;
33355
33356      if (simpleSegment.stats) {
33357        this.mediaBytesTransferred += simpleSegment.stats.bytesReceived;
33358        this.mediaTransferDuration += simpleSegment.stats.roundTripTime;
33359      }
33360
33361      // The request was aborted and the SegmentLoader has already been reset
33362      if (!this.pendingSegment_) {
33363        this.mediaRequestsAborted += 1;
33364        return;
33365      }
33366
33367      // the request was aborted and the SegmentLoader has already started
33368      // another request. this can happen when the timeout for an aborted
33369      // request triggers due to a limitation in the XHR library
33370      // do not count this as any sort of request or we risk double-counting
33371      if (simpleSegment.requestId !== this.pendingSegment_.requestId) {
33372        return;
33373      }
33374
33375      // an error occurred from the active pendingSegment_ so reset everything
33376      if (error) {
33377        this.pendingSegment_ = null;
33378        this.state = 'READY';
33379
33380        // the requests were aborted just record the aborted stat and exit
33381        // this is not a true error condition and nothing corrective needs
33382        // to be done
33383        if (error.code === _mediaSegmentRequest.REQUEST_ERRORS.ABORTED) {
33384          this.mediaRequestsAborted += 1;
33385          return;
33386        }
33387
33388        this.pause();
33389
33390        // the error is really just that at least one of the requests timed-out
33391        // set the bandwidth to a very low value and trigger an ABR switch to
33392        // take emergency action
33393        if (error.code === _mediaSegmentRequest.REQUEST_ERRORS.TIMEOUT) {
33394          this.mediaRequestsTimedout += 1;
33395          this.bandwidth = 1;
33396          this.roundTrip = NaN;
33397          this.trigger('bandwidthupdate');
33398          return;
33399        }
33400
33401        // if control-flow has arrived here, then the error is real
33402        // emit an error event to blacklist the current playlist
33403        this.mediaRequestsErrored += 1;
33404        this.error(error);
33405        this.trigger('error');
33406        return;
33407      }
33408
33409      // the response was a success so set any bandwidth stats the request
33410      // generated for ABR purposes
33411      this.bandwidth = simpleSegment.stats.bandwidth;
33412      this.roundTrip = simpleSegment.stats.roundTripTime;
33413
33414      // if this request included an initialization segment, save that data
33415      // to the initSegment cache
33416      if (simpleSegment.map) {
33417        simpleSegment.map = this.initSegment(simpleSegment.map, true);
33418      }
33419
33420      this.processSegmentResponse_(simpleSegment);
33421    }
33422
33423    /**
33424     * Move any important data from the simplified segment object
33425     * back to the real segment object for future phases
33426     *
33427     * @private
33428     */
33429  }, {
33430    key: 'processSegmentResponse_',
33431    value: function processSegmentResponse_(simpleSegment) {
33432      var segmentInfo = this.pendingSegment_;
33433
33434      segmentInfo.bytes = simpleSegment.bytes;
33435      if (simpleSegment.map) {
33436        segmentInfo.segment.map.bytes = simpleSegment.map.bytes;
33437      }
33438
33439      segmentInfo.endOfAllRequests = simpleSegment.endOfAllRequests;
33440      this.handleSegment_();
33441    }
33442
33443    /**
33444     * append a decrypted segement to the SourceBuffer through a SourceUpdater
33445     *
33446     * @private
33447     */
33448  }, {
33449    key: 'handleSegment_',
33450    value: function handleSegment_() {
33451      var _this3 = this;
33452
33453      if (!this.pendingSegment_) {
33454        this.state = 'READY';
33455        return;
33456      }
33457
33458      var segmentInfo = this.pendingSegment_;
33459      var segment = segmentInfo.segment;
33460      var timingInfo = this.syncController_.probeSegmentInfo(segmentInfo);
33461
33462      // When we have our first timing info, determine what media types this loader is
33463      // dealing with. Although we're maintaining extra state, it helps to preserve the
33464      // separation of segment loader from the actual source buffers.
33465      if (typeof this.startingMedia_ === 'undefined' && timingInfo && (
33466      // Guard against cases where we're not getting timing info at all until we are
33467      // certain that all streams will provide it.
33468      timingInfo.containsAudio || timingInfo.containsVideo)) {
33469        this.startingMedia_ = {
33470          containsAudio: timingInfo.containsAudio,
33471          containsVideo: timingInfo.containsVideo
33472        };
33473      }
33474
33475      var illegalMediaSwitchError = illegalMediaSwitch(this.loaderType_, this.startingMedia_, timingInfo);
33476
33477      if (illegalMediaSwitchError) {
33478        this.error({
33479          message: illegalMediaSwitchError
33480        });
33481        this.trigger('error');
33482        return;
33483      }
33484
33485      this.state = 'APPENDING';
33486
33487      if (segmentInfo.isSyncRequest) {
33488        this.trigger('syncinfoupdate');
33489        this.pendingSegment_ = null;
33490        this.state = 'READY';
33491        return;
33492      }
33493
33494      if (segmentInfo.timestampOffset !== null && segmentInfo.timestampOffset !== this.sourceUpdater_.timestampOffset()) {
33495        this.sourceUpdater_.timestampOffset(segmentInfo.timestampOffset);
33496        // fired when a timestamp offset is set in HLS (can also identify discontinuities)
33497        this.trigger('timestampoffset');
33498      }
33499
33500      // if the media initialization segment is changing, append it
33501      // before the content segment
33502      if (segment.map) {
33503        (function () {
33504          var initId = (0, _binUtils.initSegmentId)(segment.map);
33505
33506          if (!_this3.activeInitSegmentId_ || _this3.activeInitSegmentId_ !== initId) {
33507            var initSegment = _this3.initSegment(segment.map);
33508
33509            _this3.sourceUpdater_.appendBuffer(initSegment.bytes, function () {
33510              _this3.activeInitSegmentId_ = initId;
33511            });
33512          }
33513        })();
33514      }
33515
33516      segmentInfo.byteLength = segmentInfo.bytes.byteLength;
33517      if (typeof segment.start === 'number' && typeof segment.end === 'number') {
33518        this.mediaSecondsLoaded += segment.end - segment.start;
33519      } else {
33520        this.mediaSecondsLoaded += segment.duration;
33521      }
33522
33523      this.sourceUpdater_.appendBuffer(segmentInfo.bytes, this.handleUpdateEnd_.bind(this));
33524    }
33525
33526    /**
33527     * callback to run when appendBuffer is finished. detects if we are
33528     * in a good state to do things with the data we got, or if we need
33529     * to wait for more
33530     *
33531     * @private
33532     */
33533  }, {
33534    key: 'handleUpdateEnd_',
33535    value: function handleUpdateEnd_() {
33536      this.logger_('handleUpdateEnd_', 'segmentInfo:', this.pendingSegment_);
33537
33538      if (!this.pendingSegment_) {
33539        this.state = 'READY';
33540        if (!this.paused()) {
33541          this.monitorBuffer_();
33542        }
33543        return;
33544      }
33545
33546      var segmentInfo = this.pendingSegment_;
33547      var segment = segmentInfo.segment;
33548      var isWalkingForward = this.mediaIndex !== null;
33549
33550      this.pendingSegment_ = null;
33551      this.recordThroughput_(segmentInfo);
33552      this.addSegmentMetadataCue_(segmentInfo);
33553
33554      this.state = 'READY';
33555
33556      this.mediaIndex = segmentInfo.mediaIndex;
33557      this.fetchAtBuffer_ = true;
33558      this.currentTimeline_ = segmentInfo.timeline;
33559
33560      // We must update the syncinfo to recalculate the seekable range before
33561      // the following conditional otherwise it may consider this a bad "guess"
33562      // and attempt to resync when the post-update seekable window and live
33563      // point would mean that this was the perfect segment to fetch
33564      this.trigger('syncinfoupdate');
33565
33566      // If we previously appended a segment that ends more than 3 targetDurations before
33567      // the currentTime_ that means that our conservative guess was too conservative.
33568      // In that case, reset the loader state so that we try to use any information gained
33569      // from the previous request to create a new, more accurate, sync-point.
33570      if (segment.end && this.currentTime_() - segment.end > segmentInfo.playlist.targetDuration * 3) {
33571        this.resetEverything();
33572        return;
33573      }
33574
33575      // Don't do a rendition switch unless we have enough time to get a sync segment
33576      // and conservatively guess
33577      if (isWalkingForward) {
33578        this.trigger('bandwidthupdate');
33579      }
33580      this.trigger('progress');
33581
33582      // any time an update finishes and the last segment is in the
33583      // buffer, end the stream. this ensures the "ended" event will
33584      // fire if playback reaches that point.
33585      var isEndOfStream = detectEndOfStream(segmentInfo.playlist, this.mediaSource_, segmentInfo.mediaIndex + 1);
33586
33587      if (isEndOfStream) {
33588        this.endOfStream();
33589      }
33590
33591      if (!this.paused()) {
33592        this.monitorBuffer_();
33593      }
33594    }
33595
33596    /**
33597     * Records the current throughput of the decrypt, transmux, and append
33598     * portion of the semgment pipeline. `throughput.rate` is a the cumulative
33599     * moving average of the throughput. `throughput.count` is the number of
33600     * data points in the average.
33601     *
33602     * @private
33603     * @param {Object} segmentInfo the object returned by loadSegment
33604     */
33605  }, {
33606    key: 'recordThroughput_',
33607    value: function recordThroughput_(segmentInfo) {
33608      var rate = this.throughput.rate;
33609      // Add one to the time to ensure that we don't accidentally attempt to divide
33610      // by zero in the case where the throughput is ridiculously high
33611      var segmentProcessingTime = Date.now() - segmentInfo.endOfAllRequests + 1;
33612      // Multiply by 8000 to convert from bytes/millisecond to bits/second
33613      var segmentProcessingThroughput = Math.floor(segmentInfo.byteLength / segmentProcessingTime * 8 * 1000);
33614
33615      // This is just a cumulative moving average calculation:
33616      //   newAvg = oldAvg + (sample - oldAvg) / (sampleCount + 1)
33617      this.throughput.rate += (segmentProcessingThroughput - rate) / ++this.throughput.count;
33618    }
33619
33620    /**
33621     * A debugging logger noop that is set to console.log only if debugging
33622     * is enabled globally
33623     *
33624     * @private
33625     */
33626  }, {
33627    key: 'logger_',
33628    value: function logger_() {}
33629
33630    /**
33631     * Adds a cue to the segment-metadata track with some metadata information about the
33632     * segment
33633     *
33634     * @private
33635     * @param {Object} segmentInfo
33636     *        the object returned by loadSegment
33637     * @method addSegmentMetadataCue_
33638     */
33639  }, {
33640    key: 'addSegmentMetadataCue_',
33641    value: function addSegmentMetadataCue_(segmentInfo) {
33642      if (!this.segmentMetadataTrack_) {
33643        return;
33644      }
33645
33646      var segment = segmentInfo.segment;
33647      var start = segment.start;
33648      var end = segment.end;
33649
33650      // Do not try adding the cue if the start and end times are invalid.
33651      if (!finite(start) || !finite(end)) {
33652        return;
33653      }
33654
33655      (0, _videojsContribMediaSourcesEs5RemoveCuesFromTrackJs2['default'])(start, end, this.segmentMetadataTrack_);
33656
33657      var Cue = _globalWindow2['default'].WebKitDataCue || _globalWindow2['default'].VTTCue;
33658      var value = {
33659        uri: segmentInfo.uri,
33660        timeline: segmentInfo.timeline,
33661        playlist: segmentInfo.playlist.uri,
33662        start: start,
33663        end: end
33664      };
33665      var data = JSON.stringify(value);
33666      var cue = new Cue(start, end, data);
33667
33668      // Attach the metadata to the value property of the cue to keep consistency between
33669      // the differences of WebKitDataCue in safari and VTTCue in other browsers
33670      cue.value = value;
33671
33672      this.segmentMetadataTrack_.addCue(cue);
33673    }
33674  }]);
33675
33676  return SegmentLoader;
33677})(_videoJs2['default'].EventTarget);
33678
33679exports['default'] = SegmentLoader;
33680}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
33681},{"./bin-utils":2,"./config":3,"./media-segment-request":7,"./playlist":11,"./playlist-selectors":10,"./ranges":12,"./source-updater":17,"global/window":32,"videojs-contrib-media-sources/es5/remove-cues-from-track.js":72}],17:[function(require,module,exports){
33682(function (global){
33683/**
33684 * @file source-updater.js
33685 */
33686'use strict';
33687
33688Object.defineProperty(exports, '__esModule', {
33689  value: true
33690});
33691
33692var _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; }; })();
33693
33694function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
33695
33696function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
33697
33698var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
33699
33700var _videoJs2 = _interopRequireDefault(_videoJs);
33701
33702var noop = function noop() {};
33703
33704/**
33705 * A queue of callbacks to be serialized and applied when a
33706 * MediaSource and its associated SourceBuffers are not in the
33707 * updating state. It is used by the segment loader to update the
33708 * underlying SourceBuffers when new data is loaded, for instance.
33709 *
33710 * @class SourceUpdater
33711 * @param {MediaSource} mediaSource the MediaSource to create the
33712 * SourceBuffer from
33713 * @param {String} mimeType the desired MIME type of the underlying
33714 * SourceBuffer
33715 */
33716
33717var SourceUpdater = (function () {
33718  function SourceUpdater(mediaSource, mimeType) {
33719    var _this = this;
33720
33721    _classCallCheck(this, SourceUpdater);
33722
33723    var createSourceBuffer = function createSourceBuffer() {
33724      _this.sourceBuffer_ = mediaSource.addSourceBuffer(mimeType);
33725
33726      // run completion handlers and process callbacks as updateend
33727      // events fire
33728      _this.onUpdateendCallback_ = function () {
33729        var pendingCallback = _this.pendingCallback_;
33730
33731        _this.pendingCallback_ = null;
33732
33733        if (pendingCallback) {
33734          pendingCallback();
33735        }
33736
33737        _this.runCallback_();
33738      };
33739
33740      _this.sourceBuffer_.addEventListener('updateend', _this.onUpdateendCallback_);
33741
33742      _this.runCallback_();
33743    };
33744
33745    this.callbacks_ = [];
33746    this.pendingCallback_ = null;
33747    this.timestampOffset_ = 0;
33748    this.mediaSource = mediaSource;
33749    this.processedAppend_ = false;
33750
33751    if (mediaSource.readyState === 'closed') {
33752      mediaSource.addEventListener('sourceopen', createSourceBuffer);
33753    } else {
33754      createSourceBuffer();
33755    }
33756  }
33757
33758  /**
33759   * Aborts the current segment and resets the segment parser.
33760   *
33761   * @param {Function} done function to call when done
33762   * @see http://w3c.github.io/media-source/#widl-SourceBuffer-abort-void
33763   */
33764
33765  _createClass(SourceUpdater, [{
33766    key: 'abort',
33767    value: function abort(done) {
33768      var _this2 = this;
33769
33770      if (this.processedAppend_) {
33771        this.queueCallback_(function () {
33772          _this2.sourceBuffer_.abort();
33773        }, done);
33774      }
33775    }
33776
33777    /**
33778     * Queue an update to append an ArrayBuffer.
33779     *
33780     * @param {ArrayBuffer} bytes
33781     * @param {Function} done the function to call when done
33782     * @see http://www.w3.org/TR/media-source/#widl-SourceBuffer-appendBuffer-void-ArrayBuffer-data
33783     */
33784  }, {
33785    key: 'appendBuffer',
33786    value: function appendBuffer(bytes, done) {
33787      var _this3 = this;
33788
33789      this.processedAppend_ = true;
vendor: 174,357 bytes, lines 33790-39116
33790
33791      this.queueCallback_(function () {
33792        _this3.sourceBuffer_.appendBuffer(bytes);
33793      }, done);
33794    }
33795
33796    /**
33797     * Indicates what TimeRanges are buffered in the managed SourceBuffer.
33798     *
33799     * @see http://www.w3.org/TR/media-source/#widl-SourceBuffer-buffered
33800     */
33801  }, {
33802    key: 'buffered',
33803    value: function buffered() {
33804      if (!this.sourceBuffer_) {
33805        return _videoJs2['default'].createTimeRanges();
33806      }
33807      return this.sourceBuffer_.buffered;
33808    }
33809
33810    /**
33811     * Queue an update to remove a time range from the buffer.
33812     *
33813     * @param {Number} start where to start the removal
33814     * @param {Number} end where to end the removal
33815     * @see http://www.w3.org/TR/media-source/#widl-SourceBuffer-remove-void-double-start-unrestricted-double-end
33816     */
33817  }, {
33818    key: 'remove',
33819    value: function remove(start, end) {
33820      var _this4 = this;
33821
33822      if (this.processedAppend_) {
33823        this.queueCallback_(function () {
33824          _this4.sourceBuffer_.remove(start, end);
33825        }, noop);
33826      }
33827    }
33828
33829    /**
33830     * Whether the underlying sourceBuffer is updating or not
33831     *
33832     * @return {Boolean} the updating status of the SourceBuffer
33833     */
33834  }, {
33835    key: 'updating',
33836    value: function updating() {
33837      return !this.sourceBuffer_ || this.sourceBuffer_.updating || this.pendingCallback_;
33838    }
33839
33840    /**
33841     * Set/get the timestampoffset on the SourceBuffer
33842     *
33843     * @return {Number} the timestamp offset
33844     */
33845  }, {
33846    key: 'timestampOffset',
33847    value: function timestampOffset(offset) {
33848      var _this5 = this;
33849
33850      if (typeof offset !== 'undefined') {
33851        this.queueCallback_(function () {
33852          _this5.sourceBuffer_.timestampOffset = offset;
33853        });
33854        this.timestampOffset_ = offset;
33855      }
33856      return this.timestampOffset_;
33857    }
33858
33859    /**
33860     * Queue a callback to run
33861     */
33862  }, {
33863    key: 'queueCallback_',
33864    value: function queueCallback_(callback, done) {
33865      this.callbacks_.push([callback.bind(this), done]);
33866      this.runCallback_();
33867    }
33868
33869    /**
33870     * Run a queued callback
33871     */
33872  }, {
33873    key: 'runCallback_',
33874    value: function runCallback_() {
33875      var callbacks = undefined;
33876
33877      if (!this.updating() && this.callbacks_.length) {
33878        callbacks = this.callbacks_.shift();
33879        this.pendingCallback_ = callbacks[1];
33880        callbacks[0]();
33881      }
33882    }
33883
33884    /**
33885     * dispose of the source updater and the underlying sourceBuffer
33886     */
33887  }, {
33888    key: 'dispose',
33889    value: function dispose() {
33890      this.sourceBuffer_.removeEventListener('updateend', this.onUpdateendCallback_);
33891      if (this.sourceBuffer_ && this.mediaSource.readyState === 'open') {
33892        this.sourceBuffer_.abort();
33893      }
33894    }
33895  }]);
33896
33897  return SourceUpdater;
33898})();
33899
33900exports['default'] = SourceUpdater;
33901module.exports = exports['default'];
33902}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
33903},{}],18:[function(require,module,exports){
33904(function (global){
33905/**
33906 * @file sync-controller.js
33907 */
33908
33909'use strict';
33910
33911Object.defineProperty(exports, '__esModule', {
33912  value: true
33913});
33914
33915var _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; }; })();
33916
33917var _get = function get(_x2, _x3, _x4) { var _again = true; _function: while (_again) { var object = _x2, property = _x3, receiver = _x4; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x2 = parent; _x3 = property; _x4 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
33918
33919function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
33920
33921function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
33922
33923function _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; }
33924
33925var _muxJsLibMp4Probe = require('mux.js/lib/mp4/probe');
33926
33927var _muxJsLibMp4Probe2 = _interopRequireDefault(_muxJsLibMp4Probe);
33928
33929var _muxJsLibToolsTsInspectorJs = require('mux.js/lib/tools/ts-inspector.js');
33930
33931var _playlist = require('./playlist');
33932
33933var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
33934
33935var _videoJs2 = _interopRequireDefault(_videoJs);
33936
33937var syncPointStrategies = [
33938// Stategy "VOD": Handle the VOD-case where the sync-point is *always*
33939//                the equivalence display-time 0 === segment-index 0
33940{
33941  name: 'VOD',
33942  run: function run(syncController, playlist, duration, currentTimeline, currentTime) {
33943    if (duration !== Infinity) {
33944      var syncPoint = {
33945        time: 0,
33946        segmentIndex: 0
33947      };
33948
33949      return syncPoint;
33950    }
33951    return null;
33952  }
33953},
33954// Stategy "ProgramDateTime": We have a program-date-time tag in this playlist
33955{
33956  name: 'ProgramDateTime',
33957  run: function run(syncController, playlist, duration, currentTimeline, currentTime) {
33958    if (syncController.datetimeToDisplayTime && playlist.dateTimeObject) {
33959      var playlistTime = playlist.dateTimeObject.getTime() / 1000;
33960      var playlistStart = playlistTime + syncController.datetimeToDisplayTime;
33961      var syncPoint = {
33962        time: playlistStart,
33963        segmentIndex: 0
33964      };
33965
33966      return syncPoint;
33967    }
33968    return null;
33969  }
33970},
33971// Stategy "Segment": We have a known time mapping for a timeline and a
33972//                    segment in the current timeline with timing data
33973{
33974  name: 'Segment',
33975  run: function run(syncController, playlist, duration, currentTimeline, currentTime) {
33976    var segments = playlist.segments || [];
33977    var syncPoint = null;
33978    var lastDistance = null;
33979
33980    currentTime = currentTime || 0;
33981
33982    for (var i = 0; i < segments.length; i++) {
33983      var segment = segments[i];
33984
33985      if (segment.timeline === currentTimeline && typeof segment.start !== 'undefined') {
33986        var distance = Math.abs(currentTime - segment.start);
33987
33988        // Once the distance begins to increase, we have passed
33989        // currentTime and can stop looking for better candidates
33990        if (lastDistance !== null && lastDistance < distance) {
33991          break;
33992        }
33993
33994        if (!syncPoint || lastDistance === null || lastDistance >= distance) {
33995          lastDistance = distance;
33996          syncPoint = {
33997            time: segment.start,
33998            segmentIndex: i
33999          };
34000        }
34001      }
34002    }
34003    return syncPoint;
34004  }
34005},
34006// Stategy "Discontinuity": We have a discontinuity with a known
34007//                          display-time
34008{
34009  name: 'Discontinuity',
34010  run: function run(syncController, playlist, duration, currentTimeline, currentTime) {
34011    var syncPoint = null;
34012
34013    currentTime = currentTime || 0;
34014
34015    if (playlist.discontinuityStarts && playlist.discontinuityStarts.length) {
34016      var lastDistance = null;
34017
34018      for (var i = 0; i < playlist.discontinuityStarts.length; i++) {
34019        var segmentIndex = playlist.discontinuityStarts[i];
34020        var discontinuity = playlist.discontinuitySequence + i + 1;
34021        var discontinuitySync = syncController.discontinuities[discontinuity];
34022
34023        if (discontinuitySync) {
34024          var distance = Math.abs(currentTime - discontinuitySync.time);
34025
34026          // Once the distance begins to increase, we have passed
34027          // currentTime and can stop looking for better candidates
34028          if (lastDistance !== null && lastDistance < distance) {
34029            break;
34030          }
34031
34032          if (!syncPoint || lastDistance === null || lastDistance >= distance) {
34033            lastDistance = distance;
34034            syncPoint = {
34035              time: discontinuitySync.time,
34036              segmentIndex: segmentIndex
34037            };
34038          }
34039        }
34040      }
34041    }
34042    return syncPoint;
34043  }
34044},
34045// Stategy "Playlist": We have a playlist with a known mapping of
34046//                     segment index to display time
34047{
34048  name: 'Playlist',
34049  run: function run(syncController, playlist, duration, currentTimeline, currentTime) {
34050    if (playlist.syncInfo) {
34051      var syncPoint = {
34052        time: playlist.syncInfo.time,
34053        segmentIndex: playlist.syncInfo.mediaSequence - playlist.mediaSequence
34054      };
34055
34056      return syncPoint;
34057    }
34058    return null;
34059  }
34060}];
34061
34062exports.syncPointStrategies = syncPointStrategies;
34063
34064var SyncController = (function (_videojs$EventTarget) {
34065  _inherits(SyncController, _videojs$EventTarget);
34066
34067  function SyncController() {
34068    var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
34069
34070    _classCallCheck(this, SyncController);
34071
34072    _get(Object.getPrototypeOf(SyncController.prototype), 'constructor', this).call(this);
34073    // Segment Loader state variables...
34074    // ...for synching across variants
34075    this.inspectCache_ = undefined;
34076
34077    // ...for synching across variants
34078    this.timelines = [];
34079    this.discontinuities = [];
34080    this.datetimeToDisplayTime = null;
34081
34082    if (options.debug) {
34083      this.logger_ = _videoJs2['default'].log.bind(_videoJs2['default'], 'sync-controller ->');
34084    }
34085  }
34086
34087  /**
34088   * Find a sync-point for the playlist specified
34089   *
34090   * A sync-point is defined as a known mapping from display-time to
34091   * a segment-index in the current playlist.
34092   *
34093   * @param {Playlist} playlist
34094   *        The playlist that needs a sync-point
34095   * @param {Number} duration
34096   *        Duration of the MediaSource (Infinite if playing a live source)
34097   * @param {Number} currentTimeline
34098   *        The last timeline from which a segment was loaded
34099   * @returns {Object}
34100   *          A sync-point object
34101   */
34102
34103  _createClass(SyncController, [{
34104    key: 'getSyncPoint',
34105    value: function getSyncPoint(playlist, duration, currentTimeline, currentTime) {
34106      var syncPoints = this.runStrategies_(playlist, duration, currentTimeline, currentTime);
34107
34108      if (!syncPoints.length) {
34109        // Signal that we need to attempt to get a sync-point manually
34110        // by fetching a segment in the playlist and constructing
34111        // a sync-point from that information
34112        return null;
34113      }
34114
34115      // Now find the sync-point that is closest to the currentTime because
34116      // that should result in the most accurate guess about which segment
34117      // to fetch
34118      return this.selectSyncPoint_(syncPoints, { key: 'time', value: currentTime });
34119    }
34120
34121    /**
34122     * Calculate the amount of time that has expired off the playlist during playback
34123     *
34124     * @param {Playlist} playlist
34125     *        Playlist object to calculate expired from
34126     * @param {Number} duration
34127     *        Duration of the MediaSource (Infinity if playling a live source)
34128     * @returns {Number|null}
34129     *          The amount of time that has expired off the playlist during playback. Null
34130     *          if no sync-points for the playlist can be found.
34131     */
34132  }, {
34133    key: 'getExpiredTime',
34134    value: function getExpiredTime(playlist, duration) {
34135      if (!playlist || !playlist.segments) {
34136        return null;
34137      }
34138
34139      var syncPoints = this.runStrategies_(playlist, duration, playlist.discontinuitySequence, 0);
34140
34141      // Without sync-points, there is not enough information to determine the expired time
34142      if (!syncPoints.length) {
34143        return null;
34144      }
34145
34146      var syncPoint = this.selectSyncPoint_(syncPoints, {
34147        key: 'segmentIndex',
34148        value: 0
34149      });
34150
34151      // If the sync-point is beyond the start of the playlist, we want to subtract the
34152      // duration from index 0 to syncPoint.segmentIndex instead of adding.
34153      if (syncPoint.segmentIndex > 0) {
34154        syncPoint.time *= -1;
34155      }
34156
34157      return Math.abs(syncPoint.time + (0, _playlist.sumDurations)(playlist, syncPoint.segmentIndex, 0));
34158    }
34159
34160    /**
34161     * Runs each sync-point strategy and returns a list of sync-points returned by the
34162     * strategies
34163     *
34164     * @private
34165     * @param {Playlist} playlist
34166     *        The playlist that needs a sync-point
34167     * @param {Number} duration
34168     *        Duration of the MediaSource (Infinity if playing a live source)
34169     * @param {Number} currentTimeline
34170     *        The last timeline from which a segment was loaded
34171     * @returns {Array}
34172     *          A list of sync-point objects
34173     */
34174  }, {
34175    key: 'runStrategies_',
34176    value: function runStrategies_(playlist, duration, currentTimeline, currentTime) {
34177      var syncPoints = [];
34178
34179      // Try to find a sync-point in by utilizing various strategies...
34180      for (var i = 0; i < syncPointStrategies.length; i++) {
34181        var strategy = syncPointStrategies[i];
34182        var syncPoint = strategy.run(this, playlist, duration, currentTimeline, currentTime);
34183
34184        if (syncPoint) {
34185          syncPoint.strategy = strategy.name;
34186          syncPoints.push({
34187            strategy: strategy.name,
34188            syncPoint: syncPoint
34189          });
34190          this.logger_('syncPoint found via <' + strategy.name + '>:', syncPoint);
34191        }
34192      }
34193
34194      return syncPoints;
34195    }
34196
34197    /**
34198     * Selects the sync-point nearest the specified target
34199     *
34200     * @private
34201     * @param {Array} syncPoints
34202     *        List of sync-points to select from
34203     * @param {Object} target
34204     *        Object specifying the property and value we are targeting
34205     * @param {String} target.key
34206     *        Specifies the property to target. Must be either 'time' or 'segmentIndex'
34207     * @param {Number} target.value
34208     *        The value to target for the specified key.
34209     * @returns {Object}
34210     *          The sync-point nearest the target
34211     */
34212  }, {
34213    key: 'selectSyncPoint_',
34214    value: function selectSyncPoint_(syncPoints, target) {
34215      var bestSyncPoint = syncPoints[0].syncPoint;
34216      var bestDistance = Math.abs(syncPoints[0].syncPoint[target.key] - target.value);
34217      var bestStrategy = syncPoints[0].strategy;
34218
34219      for (var i = 1; i < syncPoints.length; i++) {
34220        var newDistance = Math.abs(syncPoints[i].syncPoint[target.key] - target.value);
34221
34222        if (newDistance < bestDistance) {
34223          bestDistance = newDistance;
34224          bestSyncPoint = syncPoints[i].syncPoint;
34225          bestStrategy = syncPoints[i].strategy;
34226        }
34227      }
34228
34229      this.logger_('syncPoint with strategy <' + bestStrategy + '> chosen: ', bestSyncPoint);
34230      return bestSyncPoint;
34231    }
34232
34233    /**
34234     * Save any meta-data present on the segments when segments leave
34235     * the live window to the playlist to allow for synchronization at the
34236     * playlist level later.
34237     *
34238     * @param {Playlist} oldPlaylist - The previous active playlist
34239     * @param {Playlist} newPlaylist - The updated and most current playlist
34240     */
34241  }, {
34242    key: 'saveExpiredSegmentInfo',
34243    value: function saveExpiredSegmentInfo(oldPlaylist, newPlaylist) {
34244      var mediaSequenceDiff = newPlaylist.mediaSequence - oldPlaylist.mediaSequence;
34245
34246      // When a segment expires from the playlist and it has a start time
34247      // save that information as a possible sync-point reference in future
34248      for (var i = mediaSequenceDiff - 1; i >= 0; i--) {
34249        var lastRemovedSegment = oldPlaylist.segments[i];
34250
34251        if (lastRemovedSegment && typeof lastRemovedSegment.start !== 'undefined') {
34252          newPlaylist.syncInfo = {
34253            mediaSequence: oldPlaylist.mediaSequence + i,
34254            time: lastRemovedSegment.start
34255          };
34256          this.logger_('playlist sync:', newPlaylist.syncInfo);
34257          this.trigger('syncinfoupdate');
34258          break;
34259        }
34260      }
34261    }
34262
34263    /**
34264     * Save the mapping from playlist's ProgramDateTime to display. This should
34265     * only ever happen once at the start of playback.
34266     *
34267     * @param {Playlist} playlist - The currently active playlist
34268     */
34269  }, {
34270    key: 'setDateTimeMapping',
34271    value: function setDateTimeMapping(playlist) {
34272      if (!this.datetimeToDisplayTime && playlist.dateTimeObject) {
34273        var playlistTimestamp = playlist.dateTimeObject.getTime() / 1000;
34274
34275        this.datetimeToDisplayTime = -playlistTimestamp;
34276      }
34277    }
34278
34279    /**
34280     * Reset the state of the inspection cache when we do a rendition
34281     * switch
34282     */
34283  }, {
34284    key: 'reset',
34285    value: function reset() {
34286      this.inspectCache_ = undefined;
34287    }
34288
34289    /**
34290     * Probe or inspect a fmp4 or an mpeg2-ts segment to determine the start
34291     * and end of the segment in it's internal "media time". Used to generate
34292     * mappings from that internal "media time" to the display time that is
34293     * shown on the player.
34294     *
34295     * @param {SegmentInfo} segmentInfo - The current active request information
34296     */
34297  }, {
34298    key: 'probeSegmentInfo',
34299    value: function probeSegmentInfo(segmentInfo) {
34300      var segment = segmentInfo.segment;
34301      var playlist = segmentInfo.playlist;
34302      var timingInfo = undefined;
34303
34304      if (segment.map) {
34305        timingInfo = this.probeMp4Segment_(segmentInfo);
34306      } else {
34307        timingInfo = this.probeTsSegment_(segmentInfo);
34308      }
34309
34310      if (timingInfo) {
34311        if (this.calculateSegmentTimeMapping_(segmentInfo, timingInfo)) {
34312          this.saveDiscontinuitySyncInfo_(segmentInfo);
34313
34314          // If the playlist does not have sync information yet, record that information
34315          // now with segment timing information
34316          if (!playlist.syncInfo) {
34317            playlist.syncInfo = {
34318              mediaSequence: playlist.mediaSequence + segmentInfo.mediaIndex,
34319              time: segment.start
34320            };
34321          }
34322        }
34323      }
34324
34325      return timingInfo;
34326    }
34327
34328    /**
34329     * Probe an fmp4 or an mpeg2-ts segment to determine the start of the segment
34330     * in it's internal "media time".
34331     *
34332     * @private
34333     * @param {SegmentInfo} segmentInfo - The current active request information
34334     * @return {object} The start and end time of the current segment in "media time"
34335     */
34336  }, {
34337    key: 'probeMp4Segment_',
34338    value: function probeMp4Segment_(segmentInfo) {
34339      var segment = segmentInfo.segment;
34340      var timescales = _muxJsLibMp4Probe2['default'].timescale(segment.map.bytes);
34341      var startTime = _muxJsLibMp4Probe2['default'].startTime(timescales, segmentInfo.bytes);
34342
34343      if (segmentInfo.timestampOffset !== null) {
34344        segmentInfo.timestampOffset -= startTime;
34345      }
34346
34347      return {
34348        start: startTime,
34349        end: startTime + segment.duration
34350      };
34351    }
34352
34353    /**
34354     * Probe an mpeg2-ts segment to determine the start and end of the segment
34355     * in it's internal "media time".
34356     *
34357     * @private
34358     * @param {SegmentInfo} segmentInfo - The current active request information
34359     * @return {object} The start and end time of the current segment in "media time"
34360     */
34361  }, {
34362    key: 'probeTsSegment_',
34363    value: function probeTsSegment_(segmentInfo) {
34364      var timeInfo = (0, _muxJsLibToolsTsInspectorJs.inspect)(segmentInfo.bytes, this.inspectCache_);
34365      var segmentStartTime = undefined;
34366      var segmentEndTime = undefined;
34367
34368      if (!timeInfo) {
34369        return null;
34370      }
34371
34372      if (timeInfo.video && timeInfo.video.length === 2) {
34373        this.inspectCache_ = timeInfo.video[1].dts;
34374        segmentStartTime = timeInfo.video[0].dtsTime;
34375        segmentEndTime = timeInfo.video[1].dtsTime;
34376      } else if (timeInfo.audio && timeInfo.audio.length === 2) {
34377        this.inspectCache_ = timeInfo.audio[1].dts;
34378        segmentStartTime = timeInfo.audio[0].dtsTime;
34379        segmentEndTime = timeInfo.audio[1].dtsTime;
34380      }
34381
34382      return {
34383        start: segmentStartTime,
34384        end: segmentEndTime,
34385        containsVideo: timeInfo.video && timeInfo.video.length === 2,
34386        containsAudio: timeInfo.audio && timeInfo.audio.length === 2
34387      };
34388    }
34389  }, {
34390    key: 'timestampOffsetForTimeline',
34391    value: function timestampOffsetForTimeline(timeline) {
34392      if (typeof this.timelines[timeline] === 'undefined') {
34393        return null;
34394      }
34395      return this.timelines[timeline].time;
34396    }
34397
34398    /**
34399     * Use the "media time" for a segment to generate a mapping to "display time" and
34400     * save that display time to the segment.
34401     *
34402     * @private
34403     * @param {SegmentInfo} segmentInfo
34404     *        The current active request information
34405     * @param {object} timingInfo
34406     *        The start and end time of the current segment in "media time"
34407     * @returns {Boolean}
34408     *          Returns false if segment time mapping could not be calculated
34409     */
34410  }, {
34411    key: 'calculateSegmentTimeMapping_',
34412    value: function calculateSegmentTimeMapping_(segmentInfo, timingInfo) {
34413      var segment = segmentInfo.segment;
34414      var mappingObj = this.timelines[segmentInfo.timeline];
34415
34416      if (segmentInfo.timestampOffset !== null) {
34417        this.logger_('tsO:', segmentInfo.timestampOffset);
34418
34419        mappingObj = {
34420          time: segmentInfo.startOfSegment,
34421          mapping: segmentInfo.startOfSegment - timingInfo.start
34422        };
34423        this.timelines[segmentInfo.timeline] = mappingObj;
34424        this.trigger('timestampoffset');
34425
34426        segment.start = segmentInfo.startOfSegment;
34427        segment.end = timingInfo.end + mappingObj.mapping;
34428      } else if (mappingObj) {
34429        segment.start = timingInfo.start + mappingObj.mapping;
34430        segment.end = timingInfo.end + mappingObj.mapping;
34431      } else {
34432        return false;
34433      }
34434
34435      return true;
34436    }
34437
34438    /**
34439     * Each time we have discontinuity in the playlist, attempt to calculate the location
34440     * in display of the start of the discontinuity and save that. We also save an accuracy
34441     * value so that we save values with the most accuracy (closest to 0.)
34442     *
34443     * @private
34444     * @param {SegmentInfo} segmentInfo - The current active request information
34445     */
34446  }, {
34447    key: 'saveDiscontinuitySyncInfo_',
34448    value: function saveDiscontinuitySyncInfo_(segmentInfo) {
34449      var playlist = segmentInfo.playlist;
34450      var segment = segmentInfo.segment;
34451
34452      // If the current segment is a discontinuity then we know exactly where
34453      // the start of the range and it's accuracy is 0 (greater accuracy values
34454      // mean more approximation)
34455      if (segment.discontinuity) {
34456        this.discontinuities[segment.timeline] = {
34457          time: segment.start,
34458          accuracy: 0
34459        };
34460      } else if (playlist.discontinuityStarts.length) {
34461        // Search for future discontinuities that we can provide better timing
34462        // information for and save that information for sync purposes
34463        for (var i = 0; i < playlist.discontinuityStarts.length; i++) {
34464          var segmentIndex = playlist.discontinuityStarts[i];
34465          var discontinuity = playlist.discontinuitySequence + i + 1;
34466          var mediaIndexDiff = segmentIndex - segmentInfo.mediaIndex;
34467          var accuracy = Math.abs(mediaIndexDiff);
34468
34469          if (!this.discontinuities[discontinuity] || this.discontinuities[discontinuity].accuracy > accuracy) {
34470            var time = undefined;
34471
34472            if (mediaIndexDiff < 0) {
34473              time = segment.start - (0, _playlist.sumDurations)(playlist, segmentInfo.mediaIndex, segmentIndex);
34474            } else {
34475              time = segment.end + (0, _playlist.sumDurations)(playlist, segmentInfo.mediaIndex + 1, segmentIndex);
34476            }
34477
34478            this.discontinuities[discontinuity] = {
34479              time: time,
34480              accuracy: accuracy
34481            };
34482          }
34483        }
34484      }
34485    }
34486
34487    /**
34488     * A debugging logger noop that is set to console.log only if debugging
34489     * is enabled globally
34490     *
34491     * @private
34492     */
34493  }, {
34494    key: 'logger_',
34495    value: function logger_() {}
34496  }]);
34497
34498  return SyncController;
34499})(_videoJs2['default'].EventTarget);
34500
34501exports['default'] = SyncController;
34502}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
34503},{"./playlist":11,"mux.js/lib/mp4/probe":57,"mux.js/lib/tools/ts-inspector.js":59}],19:[function(require,module,exports){
34504
34505/**
34506 * @file - codecs.js - Handles tasks regarding codec strings such as translating them to
34507 * codec strings, or translating codec strings into objects that can be examined.
34508 */
34509
34510/**
34511 * Parses a codec string to retrieve the number of codecs specified,
34512 * the video codec and object type indicator, and the audio profile.
34513 */
34514
34515'use strict';
34516
34517Object.defineProperty(exports, '__esModule', {
34518  value: true
34519});
34520var parseCodecs = function parseCodecs() {
34521  var codecs = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
34522
34523  var result = {
34524    codecCount: 0
34525  };
34526  var parsed = undefined;
34527
34528  result.codecCount = codecs.split(',').length;
34529  result.codecCount = result.codecCount || 2;
34530
34531  // parse the video codec
34532  parsed = /(^|\s|,)+(avc1)([^ ,]*)/i.exec(codecs);
34533  if (parsed) {
34534    result.videoCodec = parsed[2];
34535    result.videoObjectTypeIndicator = parsed[3];
34536  }
34537
34538  // parse the last field of the audio codec
34539  result.audioProfile = /(^|\s|,)+mp4a.[0-9A-Fa-f]+\.([0-9A-Fa-f]+)/i.exec(codecs);
34540  result.audioProfile = result.audioProfile && result.audioProfile[2];
34541
34542  return result;
34543};
34544exports.parseCodecs = parseCodecs;
34545},{}],20:[function(require,module,exports){
34546(function (global){
34547/**
34548 * @file vtt-segment-loader.js
34549 */
34550'use strict';
34551
34552Object.defineProperty(exports, '__esModule', {
34553  value: true
34554});
34555
34556var _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; }; })();
34557
34558var _get = function get(_x3, _x4, _x5) { var _again = true; _function: while (_again) { var object = _x3, property = _x4, receiver = _x5; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x3 = parent; _x4 = property; _x5 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
34559
34560function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
34561
34562function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
34563
34564function _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; }
34565
34566var _segmentLoader = require('./segment-loader');
34567
34568var _segmentLoader2 = _interopRequireDefault(_segmentLoader);
34569
34570var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
34571
34572var _videoJs2 = _interopRequireDefault(_videoJs);
34573
34574var _globalWindow = require('global/window');
34575
34576var _globalWindow2 = _interopRequireDefault(_globalWindow);
34577
34578var _videojsContribMediaSourcesEs5RemoveCuesFromTrackJs = require('videojs-contrib-media-sources/es5/remove-cues-from-track.js');
34579
34580var _videojsContribMediaSourcesEs5RemoveCuesFromTrackJs2 = _interopRequireDefault(_videojsContribMediaSourcesEs5RemoveCuesFromTrackJs);
34581
34582var _binUtils = require('./bin-utils');
34583
34584var VTT_LINE_TERMINATORS = new Uint8Array('\n\n'.split('').map(function (char) {
34585  return char.charCodeAt(0);
34586}));
34587
34588var uintToString = function uintToString(uintArray) {
34589  return String.fromCharCode.apply(null, uintArray);
34590};
34591
34592/**
34593 * An object that manages segment loading and appending.
34594 *
34595 * @class VTTSegmentLoader
34596 * @param {Object} options required and optional options
34597 * @extends videojs.EventTarget
34598 */
34599
34600var VTTSegmentLoader = (function (_SegmentLoader) {
34601  _inherits(VTTSegmentLoader, _SegmentLoader);
34602
34603  function VTTSegmentLoader(settings) {
34604    var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
34605
34606    _classCallCheck(this, VTTSegmentLoader);
34607
34608    _get(Object.getPrototypeOf(VTTSegmentLoader.prototype), 'constructor', this).call(this, settings, options);
34609
34610    // SegmentLoader requires a MediaSource be specified or it will throw an error;
34611    // however, VTTSegmentLoader has no need of a media source, so delete the reference
34612    this.mediaSource_ = null;
34613
34614    this.subtitlesTrack_ = null;
34615  }
34616
34617  /**
34618   * Indicates which time ranges are buffered
34619   *
34620   * @return {TimeRange}
34621   *         TimeRange object representing the current buffered ranges
34622   */
34623
34624  _createClass(VTTSegmentLoader, [{
34625    key: 'buffered_',
34626    value: function buffered_() {
34627      if (!this.subtitlesTrack_ || !this.subtitlesTrack_.cues.length) {
34628        return _videoJs2['default'].createTimeRanges();
34629      }
34630
34631      var cues = this.subtitlesTrack_.cues;
34632      var start = cues[0].startTime;
34633      var end = cues[cues.length - 1].startTime;
34634
34635      return _videoJs2['default'].createTimeRanges([[start, end]]);
34636    }
34637
34638    /**
34639     * Gets and sets init segment for the provided map
34640     *
34641     * @param {Object} map
34642     *        The map object representing the init segment to get or set
34643     * @param {Boolean=} set
34644     *        If true, the init segment for the provided map should be saved
34645     * @return {Object}
34646     *         map object for desired init segment
34647     */
34648  }, {
34649    key: 'initSegment',
34650    value: function initSegment(map) {
34651      var set = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
34652
34653      if (!map) {
34654        return null;
34655      }
34656
34657      var id = (0, _binUtils.initSegmentId)(map);
34658      var storedMap = this.initSegments_[id];
34659
34660      if (set && !storedMap && map.bytes) {
34661        // append WebVTT line terminators to the media initialization segment if it exists
34662        // to follow the WebVTT spec (https://w3c.github.io/webvtt/#file-structure) that
34663        // requires two or more WebVTT line terminators between the WebVTT header and the
34664        // rest of the file
34665        var combinedByteLength = VTT_LINE_TERMINATORS.byteLength + map.bytes.byteLength;
34666        var combinedSegment = new Uint8Array(combinedByteLength);
34667
34668        combinedSegment.set(map.bytes);
34669        combinedSegment.set(VTT_LINE_TERMINATORS, map.bytes.byteLength);
34670
34671        this.initSegments_[id] = storedMap = {
34672          resolvedUri: map.resolvedUri,
34673          byterange: map.byterange,
34674          bytes: combinedSegment
34675        };
34676      }
34677
34678      return storedMap || map;
34679    }
34680
34681    /**
34682     * Returns true if all configuration required for loading is present, otherwise false.
34683     *
34684     * @return {Boolean} True if the all configuration is ready for loading
34685     * @private
34686     */
34687  }, {
34688    key: 'couldBeginLoading_',
34689    value: function couldBeginLoading_() {
34690      return this.playlist_ && this.subtitlesTrack_ && !this.paused();
34691    }
34692
34693    /**
34694     * Once all the starting parameters have been specified, begin
34695     * operation. This method should only be invoked from the INIT
34696     * state.
34697     *
34698     * @private
34699     */
34700  }, {
34701    key: 'init_',
34702    value: function init_() {
34703      this.state = 'READY';
34704      this.resetEverything();
34705      return this.monitorBuffer_();
34706    }
34707
34708    /**
34709     * Set a subtitle track on the segment loader to add subtitles to
34710     *
34711     * @param {TextTrack=} track
34712     *        The text track to add loaded subtitles to
34713     * @return {TextTrack}
34714     *        Returns the subtitles track
34715     */
34716  }, {
34717    key: 'track',
34718    value: function track(_track) {
34719      if (typeof _track === 'undefined') {
34720        return this.subtitlesTrack_;
34721      }
34722
34723      this.subtitlesTrack_ = _track;
34724
34725      // if we were unpaused but waiting for a sourceUpdater, start
34726      // buffering now
34727      if (this.state === 'INIT' && this.couldBeginLoading_()) {
34728        this.init_();
34729      }
34730
34731      return this.subtitlesTrack_;
34732    }
34733
34734    /**
34735     * Remove any data in the source buffer between start and end times
34736     * @param {Number} start - the start time of the region to remove from the buffer
34737     * @param {Number} end - the end time of the region to remove from the buffer
34738     */
34739  }, {
34740    key: 'remove',
34741    value: function remove(start, end) {
34742      (0, _videojsContribMediaSourcesEs5RemoveCuesFromTrackJs2['default'])(start, end, this.subtitlesTrack_);
34743    }
34744
34745    /**
34746     * fill the buffer with segements unless the sourceBuffers are
34747     * currently updating
34748     *
34749     * Note: this function should only ever be called by monitorBuffer_
34750     * and never directly
34751     *
34752     * @private
34753     */
34754  }, {
34755    key: 'fillBuffer_',
34756    value: function fillBuffer_() {
34757      var _this = this;
34758
34759      if (!this.syncPoint_) {
34760        this.syncPoint_ = this.syncController_.getSyncPoint(this.playlist_, this.duration_(), this.currentTimeline_, this.currentTime_());
34761      }
34762
34763      // see if we need to begin loading immediately
34764      var segmentInfo = this.checkBuffer_(this.buffered_(), this.playlist_, this.mediaIndex, this.hasPlayed_(), this.currentTime_(), this.syncPoint_);
34765
34766      segmentInfo = this.skipEmptySegments_(segmentInfo);
34767
34768      if (!segmentInfo) {
34769        return;
34770      }
34771
34772      if (this.syncController_.timestampOffsetForTimeline(segmentInfo.timeline) === null) {
34773        // We don't have the timestamp offset that we need to sync subtitles.
34774        // Rerun on a timestamp offset or user interaction.
34775        var checkTimestampOffset = function checkTimestampOffset() {
34776          _this.state = 'READY';
34777          if (!_this.paused()) {
34778            // if not paused, queue a buffer check as soon as possible
34779            _this.monitorBuffer_();
34780          }
34781        };
34782
34783        this.syncController_.one('timestampoffset', checkTimestampOffset);
34784        this.state = 'WAITING_ON_TIMELINE';
34785        return;
34786      }
34787
34788      this.loadSegment_(segmentInfo);
34789    }
34790
34791    /**
34792     * Prevents the segment loader from requesting segments we know contain no subtitles
34793     * by walking forward until we find the next segment that we don't know whether it is
34794     * empty or not.
34795     *
34796     * @param {Object} segmentInfo
34797     *        a segment info object that describes the current segment
34798     * @return {Object}
34799     *         a segment info object that describes the current segment
34800     */
34801  }, {
34802    key: 'skipEmptySegments_',
34803    value: function skipEmptySegments_(segmentInfo) {
34804      while (segmentInfo && segmentInfo.segment.empty) {
34805        segmentInfo = this.generateSegmentInfo_(segmentInfo.playlist, segmentInfo.mediaIndex + 1, segmentInfo.startOfSegment + segmentInfo.duration, segmentInfo.isSyncRequest);
34806      }
34807      return segmentInfo;
34808    }
34809
34810    /**
34811     * append a decrypted segement to the SourceBuffer through a SourceUpdater
34812     *
34813     * @private
34814     */
34815  }, {
34816    key: 'handleSegment_',
34817    value: function handleSegment_() {
34818      var _this2 = this;
34819
34820      if (!this.pendingSegment_ || !this.subtitlesTrack_) {
34821        this.state = 'READY';
34822        return;
34823      }
34824
34825      this.state = 'APPENDING';
34826
34827      var segmentInfo = this.pendingSegment_;
34828      var segment = segmentInfo.segment;
34829
34830      // Make sure that vttjs has loaded, otherwise, wait till it finished loading
34831      if (typeof _globalWindow2['default'].WebVTT !== 'function' && this.subtitlesTrack_ && this.subtitlesTrack_.tech_) {
34832        var _ret = (function () {
34833
34834          var loadHandler = function loadHandler() {
34835            _this2.handleSegment_();
34836          };
34837
34838          _this2.state = 'WAITING_ON_VTTJS';
34839          _this2.subtitlesTrack_.tech_.one('vttjsloaded', loadHandler);
34840          _this2.subtitlesTrack_.tech_.one('vttjserror', function () {
34841            _this2.subtitlesTrack_.tech_.off('vttjsloaded', loadHandler);
34842            _this2.error({
34843              message: 'Error loading vtt.js'
34844            });
34845            _this2.state = 'READY';
34846            _this2.pause();
34847            _this2.trigger('error');
34848          });
34849
34850          return {
34851            v: undefined
34852          };
34853        })();
34854
34855        if (typeof _ret === 'object') return _ret.v;
34856      }
34857
34858      segment.requested = true;
34859
34860      try {
34861        this.parseVTTCues_(segmentInfo);
34862      } catch (e) {
34863        this.error({
34864          message: e.message
34865        });
34866        this.state = 'READY';
34867        this.pause();
34868        return this.trigger('error');
34869      }
34870
34871      this.updateTimeMapping_(segmentInfo, this.syncController_.timelines[segmentInfo.timeline], this.playlist_);
34872
34873      if (segmentInfo.isSyncRequest) {
34874        this.trigger('syncinfoupdate');
34875        this.pendingSegment_ = null;
34876        this.state = 'READY';
34877        return;
34878      }
34879
34880      segmentInfo.byteLength = segmentInfo.bytes.byteLength;
34881
34882      this.mediaSecondsLoaded += segment.duration;
34883
34884      if (segmentInfo.cues.length) {
34885        // remove any overlapping cues to prevent doubling
34886        this.remove(segmentInfo.cues[0].endTime, segmentInfo.cues[segmentInfo.cues.length - 1].endTime);
34887      }
34888
34889      segmentInfo.cues.forEach(function (cue) {
34890        _this2.subtitlesTrack_.addCue(cue);
34891      });
34892
34893      this.handleUpdateEnd_();
34894    }
34895
34896    /**
34897     * Uses the WebVTT parser to parse the segment response
34898     *
34899     * @param {Object} segmentInfo
34900     *        a segment info object that describes the current segment
34901     * @private
34902     */
34903  }, {
34904    key: 'parseVTTCues_',
34905    value: function parseVTTCues_(segmentInfo) {
34906      var decoder = undefined;
34907      var decodeBytesToString = false;
34908
34909      if (typeof _globalWindow2['default'].TextDecoder === 'function') {
34910        decoder = new _globalWindow2['default'].TextDecoder('utf8');
34911      } else {
34912        decoder = _globalWindow2['default'].WebVTT.StringDecoder();
34913        decodeBytesToString = true;
34914      }
34915
34916      var parser = new _globalWindow2['default'].WebVTT.Parser(_globalWindow2['default'], _globalWindow2['default'].vttjs, decoder);
34917
34918      segmentInfo.cues = [];
34919      segmentInfo.timestampmap = { MPEGTS: 0, LOCAL: 0 };
34920
34921      parser.oncue = segmentInfo.cues.push.bind(segmentInfo.cues);
34922      parser.ontimestampmap = function (map) {
34923        return segmentInfo.timestampmap = map;
34924      };
34925      parser.onparsingerror = function (error) {
34926        _videoJs2['default'].log.warn('Error encountered when parsing cues: ' + error.message);
34927      };
34928
34929      if (segmentInfo.segment.map) {
34930        var mapData = segmentInfo.segment.map.bytes;
34931
34932        if (decodeBytesToString) {
34933          mapData = uintToString(mapData);
34934        }
34935
34936        parser.parse(mapData);
34937      }
34938
34939      var segmentData = segmentInfo.bytes;
34940
34941      if (decodeBytesToString) {
34942        segmentData = uintToString(segmentData);
34943      }
34944
34945      parser.parse(segmentData);
34946      parser.flush();
34947    }
34948
34949    /**
34950     * Updates the start and end times of any cues parsed by the WebVTT parser using
34951     * the information parsed from the X-TIMESTAMP-MAP header and a TS to media time mapping
34952     * from the SyncController
34953     *
34954     * @param {Object} segmentInfo
34955     *        a segment info object that describes the current segment
34956     * @param {Object} mappingObj
34957     *        object containing a mapping from TS to media time
34958     * @param {Object} playlist
34959     *        the playlist object containing the segment
34960     * @private
34961     */
34962  }, {
34963    key: 'updateTimeMapping_',
34964    value: function updateTimeMapping_(segmentInfo, mappingObj, playlist) {
34965      var segment = segmentInfo.segment;
34966
34967      if (!mappingObj) {
34968        // If the sync controller does not have a mapping of TS to Media Time for the
34969        // timeline, then we don't have enough information to update the cue
34970        // start/end times
34971        return;
34972      }
34973
34974      if (!segmentInfo.cues.length) {
34975        // If there are no cues, we also do not have enough information to figure out
34976        // segment timing. Mark that the segment contains no cues so we don't re-request
34977        // an empty segment.
34978        segment.empty = true;
34979        return;
34980      }
34981
34982      var timestampmap = segmentInfo.timestampmap;
34983      var diff = timestampmap.MPEGTS / 90000 - timestampmap.LOCAL + mappingObj.mapping;
34984
34985      segmentInfo.cues.forEach(function (cue) {
34986        // First convert cue time to TS time using the timestamp-map provided within the vtt
34987        cue.startTime += diff;
34988        cue.endTime += diff;
34989      });
34990
34991      if (!playlist.syncInfo) {
34992        var firstStart = segmentInfo.cues[0].startTime;
34993        var lastStart = segmentInfo.cues[segmentInfo.cues.length - 1].startTime;
34994
34995        playlist.syncInfo = {
34996          mediaSequence: playlist.mediaSequence + segmentInfo.mediaIndex,
34997          time: Math.min(firstStart, lastStart - segment.duration)
34998        };
34999      }
35000    }
35001  }]);
35002
35003  return VTTSegmentLoader;
35004})(_segmentLoader2['default']);
35005
35006exports['default'] = VTTSegmentLoader;
35007module.exports = exports['default'];
35008}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
35009},{"./bin-utils":2,"./segment-loader":16,"global/window":32,"videojs-contrib-media-sources/es5/remove-cues-from-track.js":72}],21:[function(require,module,exports){
35010(function (global){
35011/**
35012 * @file xhr.js
35013 */
35014
35015/**
35016 * A wrapper for videojs.xhr that tracks bandwidth.
35017 *
35018 * @param {Object} options options for the XHR
35019 * @param {Function} callback the callback to call when done
35020 * @return {Request} the xhr request that is going to be made
35021 */
35022'use strict';
35023
35024Object.defineProperty(exports, '__esModule', {
35025  value: true
35026});
35027
35028function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
35029
35030var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
35031
35032var _videoJs2 = _interopRequireDefault(_videoJs);
35033
35034var xhrFactory = function xhrFactory() {
35035  var xhr = function XhrFunction(options, callback) {
35036    // Add a default timeout for all hls requests
35037    options = (0, _videoJs.mergeOptions)({
35038      timeout: 45e3
35039    }, options);
35040
35041    // Allow an optional user-specified function to modify the option
35042    // object before we construct the xhr request
35043    var beforeRequest = XhrFunction.beforeRequest || _videoJs2['default'].Hls.xhr.beforeRequest;
35044
35045    if (beforeRequest && typeof beforeRequest === 'function') {
35046      var newOptions = beforeRequest(options);
35047
35048      if (newOptions) {
35049        options = newOptions;
35050      }
35051    }
35052
35053    var request = (0, _videoJs.xhr)(options, function (error, response) {
35054      var reqResponse = request.response;
35055
35056      if (!error && reqResponse) {
35057        request.responseTime = Date.now();
35058        request.roundTripTime = request.responseTime - request.requestTime;
35059        request.bytesReceived = reqResponse.byteLength || reqResponse.length;
35060        if (!request.bandwidth) {
35061          request.bandwidth = Math.floor(request.bytesReceived / request.roundTripTime * 8 * 1000);
35062        }
35063      }
35064
35065      // videojs.xhr now uses a specific code on the error
35066      // object to signal that a request has timed out instead
35067      // of setting a boolean on the request object
35068      if (error && error.code === 'ETIMEDOUT') {
35069        request.timedout = true;
35070      }
35071
35072      // videojs.xhr no longer considers status codes outside of 200 and 0
35073      // (for file uris) to be errors, but the old XHR did, so emulate that
35074      // behavior. Status 206 may be used in response to byterange requests.
35075      if (!error && !request.aborted && response.statusCode !== 200 && response.statusCode !== 206 && response.statusCode !== 0) {
35076        error = new Error('XHR Failed with a response of: ' + (request && (reqResponse || request.responseText)));
35077      }
35078
35079      callback(error, request);
35080    });
35081    var originalAbort = request.abort;
35082
35083    request.abort = function () {
35084      request.aborted = true;
35085      return originalAbort.apply(request, arguments);
35086    };
35087    request.uri = options.uri;
35088    request.requestTime = Date.now();
35089    return request;
35090  };
35091
35092  return xhr;
35093};
35094
35095exports['default'] = xhrFactory;
35096module.exports = exports['default'];
35097}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
35098},{}],22:[function(require,module,exports){
35099/**
35100 * @file aes.js
35101 *
35102 * This file contains an adaptation of the AES decryption algorithm
35103 * from the Standford Javascript Cryptography Library. That work is
35104 * covered by the following copyright and permissions notice:
35105 *
35106 * Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.
35107 * All rights reserved.
35108 *
35109 * Redistribution and use in source and binary forms, with or without
35110 * modification, are permitted provided that the following conditions are
35111 * met:
35112 *
35113 * 1. Redistributions of source code must retain the above copyright
35114 *    notice, this list of conditions and the following disclaimer.
35115 *
35116 * 2. Redistributions in binary form must reproduce the above
35117 *    copyright notice, this list of conditions and the following
35118 *    disclaimer in the documentation and/or other materials provided
35119 *    with the distribution.
35120 *
35121 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
35122 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35123 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35124 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
35125 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35126 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35127 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35128 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
35129 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
35130 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
35131 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35132 *
35133 * The views and conclusions contained in the software and documentation
35134 * are those of the authors and should not be interpreted as representing
35135 * official policies, either expressed or implied, of the authors.
35136 */
35137
35138/**
35139 * Expand the S-box tables.
35140 *
35141 * @private
35142 */
35143'use strict';
35144
35145Object.defineProperty(exports, '__esModule', {
35146  value: true
35147});
35148
35149var _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; }; })();
35150
35151function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
35152
35153var precompute = function precompute() {
35154  var tables = [[[], [], [], [], []], [[], [], [], [], []]];
35155  var encTable = tables[0];
35156  var decTable = tables[1];
35157  var sbox = encTable[4];
35158  var sboxInv = decTable[4];
35159  var i = undefined;
35160  var x = undefined;
35161  var xInv = undefined;
35162  var d = [];
35163  var th = [];
35164  var x2 = undefined;
35165  var x4 = undefined;
35166  var x8 = undefined;
35167  var s = undefined;
35168  var tEnc = undefined;
35169  var tDec = undefined;
35170
35171  // Compute double and third tables
35172  for (i = 0; i < 256; i++) {
35173    th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i;
35174  }
35175
35176  for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
35177    // Compute sbox
35178    s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4;
35179    s = s >> 8 ^ s & 255 ^ 99;
35180    sbox[x] = s;
35181    sboxInv[s] = x;
35182
35183    // Compute MixColumns
35184    x8 = d[x4 = d[x2 = d[x]]];
35185    tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;
35186    tEnc = d[s] * 0x101 ^ s * 0x1010100;
35187
35188    for (i = 0; i < 4; i++) {
35189      encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8;
35190      decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8;
35191    }
35192  }
35193
35194  // Compactify. Considerable speedup on Firefox.
35195  for (i = 0; i < 5; i++) {
35196    encTable[i] = encTable[i].slice(0);
35197    decTable[i] = decTable[i].slice(0);
35198  }
35199  return tables;
35200};
35201var aesTables = null;
35202
35203/**
35204 * Schedule out an AES key for both encryption and decryption. This
35205 * is a low-level class. Use a cipher mode to do bulk encryption.
35206 *
35207 * @class AES
35208 * @param key {Array} The key as an array of 4, 6 or 8 words.
35209 */
35210
35211var AES = (function () {
35212  function AES(key) {
35213    _classCallCheck(this, AES);
35214
35215    /**
35216     * The expanded S-box and inverse S-box tables. These will be computed
35217     * on the client so that we don't have to send them down the wire.
35218     *
35219     * There are two tables, _tables[0] is for encryption and
35220     * _tables[1] is for decryption.
35221     *
35222     * The first 4 sub-tables are the expanded S-box with MixColumns. The
35223     * last (_tables[01][4]) is the S-box itself.
35224     *
35225     * @private
35226     */
35227    // if we have yet to precompute the S-box tables
35228    // do so now
35229    if (!aesTables) {
35230      aesTables = precompute();
35231    }
35232    // then make a copy of that object for use
35233    this._tables = [[aesTables[0][0].slice(), aesTables[0][1].slice(), aesTables[0][2].slice(), aesTables[0][3].slice(), aesTables[0][4].slice()], [aesTables[1][0].slice(), aesTables[1][1].slice(), aesTables[1][2].slice(), aesTables[1][3].slice(), aesTables[1][4].slice()]];
35234    var i = undefined;
35235    var j = undefined;
35236    var tmp = undefined;
35237    var encKey = undefined;
35238    var decKey = undefined;
35239    var sbox = this._tables[0][4];
35240    var decTable = this._tables[1];
35241    var keyLen = key.length;
35242    var rcon = 1;
35243
35244    if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
35245      throw new Error('Invalid aes key size');
35246    }
35247
35248    encKey = key.slice(0);
35249    decKey = [];
35250    this._key = [encKey, decKey];
35251
35252    // schedule encryption keys
35253    for (i = keyLen; i < 4 * keyLen + 28; i++) {
35254      tmp = encKey[i - 1];
35255
35256      // apply sbox
35257      if (i % keyLen === 0 || keyLen === 8 && i % keyLen === 4) {
35258        tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255];
35259
35260        // shift rows and add rcon
35261        if (i % keyLen === 0) {
35262          tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24;
35263          rcon = rcon << 1 ^ (rcon >> 7) * 283;
35264        }
35265      }
35266
35267      encKey[i] = encKey[i - keyLen] ^ tmp;
35268    }
35269
35270    // schedule decryption keys
35271    for (j = 0; i; j++, i--) {
35272      tmp = encKey[j & 3 ? i : i - 4];
35273      if (i <= 4 || j < 4) {
35274        decKey[j] = tmp;
35275      } else {
35276        decKey[j] = decTable[0][sbox[tmp >>> 24]] ^ decTable[1][sbox[tmp >> 16 & 255]] ^ decTable[2][sbox[tmp >> 8 & 255]] ^ decTable[3][sbox[tmp & 255]];
35277      }
35278    }
35279  }
35280
35281  /**
35282   * Decrypt 16 bytes, specified as four 32-bit words.
35283   *
35284   * @param {Number} encrypted0 the first word to decrypt
35285   * @param {Number} encrypted1 the second word to decrypt
35286   * @param {Number} encrypted2 the third word to decrypt
35287   * @param {Number} encrypted3 the fourth word to decrypt
35288   * @param {Int32Array} out the array to write the decrypted words
35289   * into
35290   * @param {Number} offset the offset into the output array to start
35291   * writing results
35292   * @return {Array} The plaintext.
35293   */
35294
35295  _createClass(AES, [{
35296    key: 'decrypt',
35297    value: function decrypt(encrypted0, encrypted1, encrypted2, encrypted3, out, offset) {
35298      var key = this._key[1];
35299      // state variables a,b,c,d are loaded with pre-whitened data
35300      var a = encrypted0 ^ key[0];
35301      var b = encrypted3 ^ key[1];
35302      var c = encrypted2 ^ key[2];
35303      var d = encrypted1 ^ key[3];
35304      var a2 = undefined;
35305      var b2 = undefined;
35306      var c2 = undefined;
35307
35308      // key.length === 2 ?
35309      var nInnerRounds = key.length / 4 - 2;
35310      var i = undefined;
35311      var kIndex = 4;
35312      var table = this._tables[1];
35313
35314      // load up the tables
35315      var table0 = table[0];
35316      var table1 = table[1];
35317      var table2 = table[2];
35318      var table3 = table[3];
35319      var sbox = table[4];
35320
35321      // Inner rounds. Cribbed from OpenSSL.
35322      for (i = 0; i < nInnerRounds; i++) {
35323        a2 = table0[a >>> 24] ^ table1[b >> 16 & 255] ^ table2[c >> 8 & 255] ^ table3[d & 255] ^ key[kIndex];
35324        b2 = table0[b >>> 24] ^ table1[c >> 16 & 255] ^ table2[d >> 8 & 255] ^ table3[a & 255] ^ key[kIndex + 1];
35325        c2 = table0[c >>> 24] ^ table1[d >> 16 & 255] ^ table2[a >> 8 & 255] ^ table3[b & 255] ^ key[kIndex + 2];
35326        d = table0[d >>> 24] ^ table1[a >> 16 & 255] ^ table2[b >> 8 & 255] ^ table3[c & 255] ^ key[kIndex + 3];
35327        kIndex += 4;
35328        a = a2;b = b2;c = c2;
35329      }
35330
35331      // Last round.
35332      for (i = 0; i < 4; i++) {
35333        out[(3 & -i) + offset] = sbox[a >>> 24] << 24 ^ sbox[b >> 16 & 255] << 16 ^ sbox[c >> 8 & 255] << 8 ^ sbox[d & 255] ^ key[kIndex++];
35334        a2 = a;a = b;b = c;c = d;d = a2;
35335      }
35336    }
35337  }]);
35338
35339  return AES;
35340})();
35341
35342exports['default'] = AES;
35343module.exports = exports['default'];
35344},{}],23:[function(require,module,exports){
35345/**
35346 * @file async-stream.js
35347 */
35348'use strict';
35349
35350Object.defineProperty(exports, '__esModule', {
35351  value: true
35352});
35353
35354var _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; }; })();
35355
35356var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
35357
35358function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
35359
35360function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
35361
35362function _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; }
35363
35364var _stream = require('./stream');
35365
35366var _stream2 = _interopRequireDefault(_stream);
35367
35368/**
35369 * A wrapper around the Stream class to use setTiemout
35370 * and run stream "jobs" Asynchronously
35371 *
35372 * @class AsyncStream
35373 * @extends Stream
35374 */
35375
35376var AsyncStream = (function (_Stream) {
35377  _inherits(AsyncStream, _Stream);
35378
35379  function AsyncStream() {
35380    _classCallCheck(this, AsyncStream);
35381
35382    _get(Object.getPrototypeOf(AsyncStream.prototype), 'constructor', this).call(this, _stream2['default']);
35383    this.jobs = [];
35384    this.delay = 1;
35385    this.timeout_ = null;
35386  }
35387
35388  /**
35389   * process an async job
35390   *
35391   * @private
35392   */
35393
35394  _createClass(AsyncStream, [{
35395    key: 'processJob_',
35396    value: function processJob_() {
35397      this.jobs.shift()();
35398      if (this.jobs.length) {
35399        this.timeout_ = setTimeout(this.processJob_.bind(this), this.delay);
35400      } else {
35401        this.timeout_ = null;
35402      }
35403    }
35404
35405    /**
35406     * push a job into the stream
35407     *
35408     * @param {Function} job the job to push into the stream
35409     */
35410  }, {
35411    key: 'push',
35412    value: function push(job) {
35413      this.jobs.push(job);
35414      if (!this.timeout_) {
35415        this.timeout_ = setTimeout(this.processJob_.bind(this), this.delay);
35416      }
35417    }
35418  }]);
35419
35420  return AsyncStream;
35421})(_stream2['default']);
35422
35423exports['default'] = AsyncStream;
35424module.exports = exports['default'];
35425},{"./stream":26}],24:[function(require,module,exports){
35426/**
35427 * @file decrypter.js
35428 *
35429 * An asynchronous implementation of AES-128 CBC decryption with
35430 * PKCS#7 padding.
35431 */
35432
35433'use strict';
35434
35435Object.defineProperty(exports, '__esModule', {
35436  value: true
35437});
35438
35439var _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; }; })();
35440
35441function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
35442
35443function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
35444
35445var _aes = require('./aes');
35446
35447var _aes2 = _interopRequireDefault(_aes);
35448
35449var _asyncStream = require('./async-stream');
35450
35451var _asyncStream2 = _interopRequireDefault(_asyncStream);
35452
35453var _pkcs7 = require('pkcs7');
35454
35455/**
35456 * Convert network-order (big-endian) bytes into their little-endian
35457 * representation.
35458 */
35459var ntoh = function ntoh(word) {
35460  return word << 24 | (word & 0xff00) << 8 | (word & 0xff0000) >> 8 | word >>> 24;
35461};
35462
35463/**
35464 * Decrypt bytes using AES-128 with CBC and PKCS#7 padding.
35465 *
35466 * @param {Uint8Array} encrypted the encrypted bytes
35467 * @param {Uint32Array} key the bytes of the decryption key
35468 * @param {Uint32Array} initVector the initialization vector (IV) to
35469 * use for the first round of CBC.
35470 * @return {Uint8Array} the decrypted bytes
35471 *
35472 * @see http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
35473 * @see http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29
35474 * @see https://tools.ietf.org/html/rfc2315
35475 */
35476var decrypt = function decrypt(encrypted, key, initVector) {
35477  // word-level access to the encrypted bytes
35478  var encrypted32 = new Int32Array(encrypted.buffer, encrypted.byteOffset, encrypted.byteLength >> 2);
35479
35480  var decipher = new _aes2['default'](Array.prototype.slice.call(key));
35481
35482  // byte and word-level access for the decrypted output
35483  var decrypted = new Uint8Array(encrypted.byteLength);
35484  var decrypted32 = new Int32Array(decrypted.buffer);
35485
35486  // temporary variables for working with the IV, encrypted, and
35487  // decrypted data
35488  var init0 = undefined;
35489  var init1 = undefined;
35490  var init2 = undefined;
35491  var init3 = undefined;
35492  var encrypted0 = undefined;
35493  var encrypted1 = undefined;
35494  var encrypted2 = undefined;
35495  var encrypted3 = undefined;
35496
35497  // iteration variable
35498  var wordIx = undefined;
35499
35500  // pull out the words of the IV to ensure we don't modify the
35501  // passed-in reference and easier access
35502  init0 = initVector[0];
35503  init1 = initVector[1];
35504  init2 = initVector[2];
35505  init3 = initVector[3];
35506
35507  // decrypt four word sequences, applying cipher-block chaining (CBC)
35508  // to each decrypted block
35509  for (wordIx = 0; wordIx < encrypted32.length; wordIx += 4) {
35510    // convert big-endian (network order) words into little-endian
35511    // (javascript order)
35512    encrypted0 = ntoh(encrypted32[wordIx]);
35513    encrypted1 = ntoh(encrypted32[wordIx + 1]);
35514    encrypted2 = ntoh(encrypted32[wordIx + 2]);
35515    encrypted3 = ntoh(encrypted32[wordIx + 3]);
35516
35517    // decrypt the block
35518    decipher.decrypt(encrypted0, encrypted1, encrypted2, encrypted3, decrypted32, wordIx);
35519
35520    // XOR with the IV, and restore network byte-order to obtain the
35521    // plaintext
35522    decrypted32[wordIx] = ntoh(decrypted32[wordIx] ^ init0);
35523    decrypted32[wordIx + 1] = ntoh(decrypted32[wordIx + 1] ^ init1);
35524    decrypted32[wordIx + 2] = ntoh(decrypted32[wordIx + 2] ^ init2);
35525    decrypted32[wordIx + 3] = ntoh(decrypted32[wordIx + 3] ^ init3);
35526
35527    // setup the IV for the next round
35528    init0 = encrypted0;
35529    init1 = encrypted1;
35530    init2 = encrypted2;
35531    init3 = encrypted3;
35532  }
35533
35534  return decrypted;
35535};
35536
35537exports.decrypt = decrypt;
35538/**
35539 * The `Decrypter` class that manages decryption of AES
35540 * data through `AsyncStream` objects and the `decrypt`
35541 * function
35542 *
35543 * @param {Uint8Array} encrypted the encrypted bytes
35544 * @param {Uint32Array} key the bytes of the decryption key
35545 * @param {Uint32Array} initVector the initialization vector (IV) to
35546 * @param {Function} done the function to run when done
35547 * @class Decrypter
35548 */
35549
35550var Decrypter = (function () {
35551  function Decrypter(encrypted, key, initVector, done) {
35552    _classCallCheck(this, Decrypter);
35553
35554    var step = Decrypter.STEP;
35555    var encrypted32 = new Int32Array(encrypted.buffer);
35556    var decrypted = new Uint8Array(encrypted.byteLength);
35557    var i = 0;
35558
35559    this.asyncStream_ = new _asyncStream2['default']();
35560
35561    // split up the encryption job and do the individual chunks asynchronously
35562    this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted));
35563    for (i = step; i < encrypted32.length; i += step) {
35564      initVector = new Uint32Array([ntoh(encrypted32[i - 4]), ntoh(encrypted32[i - 3]), ntoh(encrypted32[i - 2]), ntoh(encrypted32[i - 1])]);
35565      this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted));
35566    }
35567    // invoke the done() callback when everything is finished
35568    this.asyncStream_.push(function () {
35569      // remove pkcs#7 padding from the decrypted bytes
35570      done(null, (0, _pkcs7.unpad)(decrypted));
35571    });
35572  }
35573
35574  /**
35575   * a getter for step the maximum number of bytes to process at one time
35576   *
35577   * @return {Number} the value of step 32000
35578   */
35579
35580  _createClass(Decrypter, [{
35581    key: 'decryptChunk_',
35582
35583    /**
35584     * @private
35585     */
35586    value: function decryptChunk_(encrypted, key, initVector, decrypted) {
35587      return function () {
35588        var bytes = decrypt(encrypted, key, initVector);
35589
35590        decrypted.set(bytes, encrypted.byteOffset);
35591      };
35592    }
35593  }], [{
35594    key: 'STEP',
35595    get: function get() {
35596      // 4 * 8000;
35597      return 32000;
35598    }
35599  }]);
35600
35601  return Decrypter;
35602})();
35603
35604exports.Decrypter = Decrypter;
35605exports['default'] = {
35606  Decrypter: Decrypter,
35607  decrypt: decrypt
35608};
35609},{"./aes":22,"./async-stream":23,"pkcs7":28}],25:[function(require,module,exports){
35610/**
35611 * @file index.js
35612 *
35613 * Index module to easily import the primary components of AES-128
35614 * decryption. Like this:
35615 *
35616 * ```js
35617 * import {Decrypter, decrypt, AsyncStream} from 'aes-decrypter';
35618 * ```
35619 */
35620'use strict';
35621
35622Object.defineProperty(exports, '__esModule', {
35623  value: true
35624});
35625
35626function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
35627
35628var _decrypter = require('./decrypter');
35629
35630var _asyncStream = require('./async-stream');
35631
35632var _asyncStream2 = _interopRequireDefault(_asyncStream);
35633
35634exports['default'] = {
35635  decrypt: _decrypter.decrypt,
35636  Decrypter: _decrypter.Decrypter,
35637  AsyncStream: _asyncStream2['default']
35638};
35639module.exports = exports['default'];
35640},{"./async-stream":23,"./decrypter":24}],26:[function(require,module,exports){
35641/**
35642 * @file stream.js
35643 */
35644/**
35645 * A lightweight readable stream implemention that handles event dispatching.
35646 *
35647 * @class Stream
35648 */
35649'use strict';
35650
35651Object.defineProperty(exports, '__esModule', {
35652  value: true
35653});
35654
35655var _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; }; })();
35656
35657function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
35658
35659var Stream = (function () {
35660  function Stream() {
35661    _classCallCheck(this, Stream);
35662
35663    this.listeners = {};
35664  }
35665
35666  /**
35667   * Add a listener for a specified event type.
35668   *
35669   * @param {String} type the event name
35670   * @param {Function} listener the callback to be invoked when an event of
35671   * the specified type occurs
35672   */
35673
35674  _createClass(Stream, [{
35675    key: 'on',
35676    value: function on(type, listener) {
35677      if (!this.listeners[type]) {
35678        this.listeners[type] = [];
35679      }
35680      this.listeners[type].push(listener);
35681    }
35682
35683    /**
35684     * Remove a listener for a specified event type.
35685     *
35686     * @param {String} type the event name
35687     * @param {Function} listener  a function previously registered for this
35688     * type of event through `on`
35689     * @return {Boolean} if we could turn it off or not
35690     */
35691  }, {
35692    key: 'off',
35693    value: function off(type, listener) {
35694      var index = undefined;
35695
35696      if (!this.listeners[type]) {
35697        return false;
35698      }
35699      index = this.listeners[type].indexOf(listener);
35700      this.listeners[type].splice(index, 1);
35701      return index > -1;
35702    }
35703
35704    /**
35705     * Trigger an event of the specified type on this stream. Any additional
35706     * arguments to this function are passed as parameters to event listeners.
35707     *
35708     * @param {String} type the event name
35709     */
35710  }, {
35711    key: 'trigger',
35712    value: function trigger(type) {
35713      var callbacks = undefined;
35714      var i = undefined;
35715      var length = undefined;
35716      var args = undefined;
35717
35718      callbacks = this.listeners[type];
35719      if (!callbacks) {
35720        return;
35721      }
35722      // Slicing the arguments on every invocation of this method
35723      // can add a significant amount of overhead. Avoid the
35724      // intermediate object creation for the common case of a
35725      // single callback argument
35726      if (arguments.length === 2) {
35727        length = callbacks.length;
35728        for (i = 0; i < length; ++i) {
35729          callbacks[i].call(this, arguments[1]);
35730        }
35731      } else {
35732        args = Array.prototype.slice.call(arguments, 1);
35733        length = callbacks.length;
35734        for (i = 0; i < length; ++i) {
35735          callbacks[i].apply(this, args);
35736        }
35737      }
35738    }
35739
35740    /**
35741     * Destroys the stream and cleans up.
35742     */
35743  }, {
35744    key: 'dispose',
35745    value: function dispose() {
35746      this.listeners = {};
35747    }
35748
35749    /**
35750     * Forwards all `data` events on this stream to the destination stream. The
35751     * destination stream should provide a method `push` to receive the data
35752     * events as they arrive.
35753     *
35754     * @param {Stream} destination the stream that will receive all `data` events
35755     * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
35756     */
35757  }, {
35758    key: 'pipe',
35759    value: function pipe(destination) {
35760      this.on('data', function (data) {
35761        destination.push(data);
35762      });
35763    }
35764  }]);
35765
35766  return Stream;
35767})();
35768
35769exports['default'] = Stream;
35770module.exports = exports['default'];
35771},{}],27:[function(require,module,exports){
35772/*
35773 * pkcs7.pad
35774 * https://github.com/brightcove/pkcs7
35775 *
35776 * Copyright (c) 2014 Brightcove
35777 * Licensed under the apache2 license.
35778 */
35779
35780'use strict';
35781
35782var PADDING;
35783
35784/**
35785 * Returns a new Uint8Array that is padded with PKCS#7 padding.
35786 * @param plaintext {Uint8Array} the input bytes before encryption
35787 * @return {Uint8Array} the padded bytes
35788 * @see http://tools.ietf.org/html/rfc5652
35789 */
35790module.exports = function pad(plaintext) {
35791  var padding = PADDING[(plaintext.byteLength % 16) || 0],
35792      result = new Uint8Array(plaintext.byteLength + padding.length);
35793  result.set(plaintext);
35794  result.set(padding, plaintext.byteLength);
35795  return result;
35796};
35797
35798// pre-define the padding values
35799PADDING = [
35800  [16, 16, 16, 16,
35801   16, 16, 16, 16,
35802   16, 16, 16, 16,
35803   16, 16, 16, 16],
35804
35805  [15, 15, 15, 15,
35806   15, 15, 15, 15,
35807   15, 15, 15, 15,
35808   15, 15, 15],
35809
35810  [14, 14, 14, 14,
35811   14, 14, 14, 14,
35812   14, 14, 14, 14,
35813   14, 14],
35814
35815  [13, 13, 13, 13,
35816   13, 13, 13, 13,
35817   13, 13, 13, 13,
35818   13],
35819
35820  [12, 12, 12, 12,
35821   12, 12, 12, 12,
35822   12, 12, 12, 12],
35823
35824  [11, 11, 11, 11,
35825   11, 11, 11, 11,
35826   11, 11, 11],
35827
35828  [10, 10, 10, 10,
35829   10, 10, 10, 10,
35830   10, 10],
35831
35832  [9, 9, 9, 9,
35833   9, 9, 9, 9,
35834   9],
35835
35836  [8, 8, 8, 8,
35837   8, 8, 8, 8],
35838
35839  [7, 7, 7, 7,
35840   7, 7, 7],
35841
35842  [6, 6, 6, 6,
35843   6, 6],
35844
35845  [5, 5, 5, 5,
35846   5],
35847
35848  [4, 4, 4, 4],
35849
35850  [3, 3, 3],
35851
35852  [2, 2],
35853
35854  [1]
35855];
35856
35857},{}],28:[function(require,module,exports){
35858/*
35859 * pkcs7
35860 * https://github.com/brightcove/pkcs7
35861 *
35862 * Copyright (c) 2014 Brightcove
35863 * Licensed under the apache2 license.
35864 */
35865
35866'use strict';
35867
35868exports.pad = require('./pad.js');
35869exports.unpad = require('./unpad.js');
35870
35871},{"./pad.js":27,"./unpad.js":29}],29:[function(require,module,exports){
35872/*
35873 * pkcs7.unpad
35874 * https://github.com/brightcove/pkcs7
35875 *
35876 * Copyright (c) 2014 Brightcove
35877 * Licensed under the apache2 license.
35878 */
35879
35880'use strict';
35881
35882/**
35883 * Returns the subarray of a Uint8Array without PKCS#7 padding.
35884 * @param padded {Uint8Array} unencrypted bytes that have been padded
35885 * @return {Uint8Array} the unpadded bytes
35886 * @see http://tools.ietf.org/html/rfc5652
35887 */
35888module.exports = function unpad(padded) {
35889  return padded.subarray(0, padded.byteLength - padded[padded.byteLength - 1]);
35890};
35891
35892},{}],30:[function(require,module,exports){
35893
35894},{}],31:[function(require,module,exports){
35895(function (global){
35896var topLevel = typeof global !== 'undefined' ? global :
35897    typeof window !== 'undefined' ? window : {}
35898var minDoc = require('min-document');
35899
35900var doccy;
35901
35902if (typeof document !== 'undefined') {
35903    doccy = document;
35904} else {
35905    doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
35906
35907    if (!doccy) {
35908        doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
35909    }
35910}
35911
35912module.exports = doccy;
35913
35914}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
35915},{"min-document":30}],32:[function(require,module,exports){
35916(function (global){
35917var win;
35918
35919if (typeof window !== "undefined") {
35920    win = window;
35921} else if (typeof global !== "undefined") {
35922    win = global;
35923} else if (typeof self !== "undefined"){
35924    win = self;
35925} else {
35926    win = {};
35927}
35928
35929module.exports = win;
35930
35931}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
35932},{}],33:[function(require,module,exports){
35933'use strict';
35934
35935var _lineStream = require('./line-stream');
35936
35937var _lineStream2 = _interopRequireDefault(_lineStream);
35938
35939var _parseStream = require('./parse-stream');
35940
35941var _parseStream2 = _interopRequireDefault(_parseStream);
35942
35943var _parser = require('./parser');
35944
35945var _parser2 = _interopRequireDefault(_parser);
35946
35947function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
35948
35949module.exports = {
35950  LineStream: _lineStream2['default'],
35951  ParseStream: _parseStream2['default'],
35952  Parser: _parser2['default']
35953}; /**
35954    * @file m3u8/index.js
35955    *
35956    * Utilities for parsing M3U8 files. If the entire manifest is available,
35957    * `Parser` will create an object representation with enough detail for managing
35958    * playback. `ParseStream` and `LineStream` are lower-level parsing primitives
35959    * that do not assume the entirety of the manifest is ready and expose a
35960    * ReadableStream-like interface.
35961    */
35962},{"./line-stream":34,"./parse-stream":35,"./parser":36}],34:[function(require,module,exports){
35963'use strict';
35964
35965Object.defineProperty(exports, "__esModule", {
35966  value: true
35967});
35968
35969var _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; }; }();
35970
35971var _stream = require('./stream');
35972
35973var _stream2 = _interopRequireDefault(_stream);
35974
35975function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
35976
35977function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
35978
35979function _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; }
35980
35981function _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; } /**
35982                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file m3u8/line-stream.js
35983                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
35984
35985
35986/**
35987 * A stream that buffers string input and generates a `data` event for each
35988 * line.
35989 *
35990 * @class LineStream
35991 * @extends Stream
35992 */
35993var LineStream = function (_Stream) {
35994  _inherits(LineStream, _Stream);
35995
35996  function LineStream() {
35997    _classCallCheck(this, LineStream);
35998
35999    var _this = _possibleConstructorReturn(this, (LineStream.__proto__ || Object.getPrototypeOf(LineStream)).call(this));
36000
36001    _this.buffer = '';
36002    return _this;
36003  }
36004
36005  /**
36006   * Add new data to be parsed.
36007   *
36008   * @param {String} data the text to process
36009   */
36010
36011
36012  _createClass(LineStream, [{
36013    key: 'push',
36014    value: function push(data) {
36015      var nextNewline = void 0;
36016
36017      this.buffer += data;
36018      nextNewline = this.buffer.indexOf('\n');
36019
36020      for (; nextNewline > -1; nextNewline = this.buffer.indexOf('\n')) {
36021        this.trigger('data', this.buffer.substring(0, nextNewline));
36022        this.buffer = this.buffer.substring(nextNewline + 1);
36023      }
36024    }
36025  }]);
36026
36027  return LineStream;
36028}(_stream2['default']);
36029
36030exports['default'] = LineStream;
36031},{"./stream":37}],35:[function(require,module,exports){
36032'use strict';
36033
36034Object.defineProperty(exports, "__esModule", {
36035  value: true
36036});
36037
36038var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
36039
36040var _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; }; }();
36041
36042var _stream = require('./stream');
36043
36044var _stream2 = _interopRequireDefault(_stream);
36045
36046function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
36047
36048function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
36049
36050function _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; }
36051
36052function _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; } /**
36053                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file m3u8/parse-stream.js
36054                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
36055
36056
36057/**
36058 * "forgiving" attribute list psuedo-grammar:
36059 * attributes -> keyvalue (',' keyvalue)*
36060 * keyvalue   -> key '=' value
36061 * key        -> [^=]*
36062 * value      -> '"' [^"]* '"' | [^,]*
36063 */
36064var attributeSeparator = function attributeSeparator() {
36065  var key = '[^=]*';
36066  var value = '"[^"]*"|[^,]*';
36067  var keyvalue = '(?:' + key + ')=(?:' + value + ')';
36068
36069  return new RegExp('(?:^|,)(' + keyvalue + ')');
36070};
36071
36072/**
36073 * Parse attributes from a line given the seperator
36074 *
36075 * @param {String} attributes the attibute line to parse
36076 */
36077var parseAttributes = function parseAttributes(attributes) {
36078  // split the string using attributes as the separator
36079  var attrs = attributes.split(attributeSeparator());
36080  var result = {};
36081  var i = attrs.length;
36082  var attr = void 0;
36083
36084  while (i--) {
36085    // filter out unmatched portions of the string
36086    if (attrs[i] === '') {
36087      continue;
36088    }
36089
36090    // split the key and value
36091    attr = /([^=]*)=(.*)/.exec(attrs[i]).slice(1);
36092    // trim whitespace and remove optional quotes around the value
36093    attr[0] = attr[0].replace(/^\s+|\s+$/g, '');
36094    attr[1] = attr[1].replace(/^\s+|\s+$/g, '');
36095    attr[1] = attr[1].replace(/^['"](.*)['"]$/g, '$1');
36096    result[attr[0]] = attr[1];
36097  }
36098  return result;
36099};
36100
36101/**
36102 * A line-level M3U8 parser event stream. It expects to receive input one
36103 * line at a time and performs a context-free parse of its contents. A stream
36104 * interpretation of a manifest can be useful if the manifest is expected to
36105 * be too large to fit comfortably into memory or the entirety of the input
36106 * is not immediately available. Otherwise, it's probably much easier to work
36107 * with a regular `Parser` object.
36108 *
36109 * Produces `data` events with an object that captures the parser's
36110 * interpretation of the input. That object has a property `tag` that is one
36111 * of `uri`, `comment`, or `tag`. URIs only have a single additional
36112 * property, `line`, which captures the entirety of the input without
36113 * interpretation. Comments similarly have a single additional property
36114 * `text` which is the input without the leading `#`.
36115 *
36116 * Tags always have a property `tagType` which is the lower-cased version of
36117 * the M3U8 directive without the `#EXT` or `#EXT-X-` prefix. For instance,
36118 * `#EXT-X-MEDIA-SEQUENCE` becomes `media-sequence` when parsed. Unrecognized
36119 * tags are given the tag type `unknown` and a single additional property
36120 * `data` with the remainder of the input.
36121 *
36122 * @class ParseStream
36123 * @extends Stream
36124 */
36125
36126var ParseStream = function (_Stream) {
36127  _inherits(ParseStream, _Stream);
36128
36129  function ParseStream() {
36130    _classCallCheck(this, ParseStream);
36131
36132    return _possibleConstructorReturn(this, (ParseStream.__proto__ || Object.getPrototypeOf(ParseStream)).call(this));
36133  }
36134
36135  /**
36136   * Parses an additional line of input.
36137   *
36138   * @param {String} line a single line of an M3U8 file to parse
36139   */
36140
36141
36142  _createClass(ParseStream, [{
36143    key: 'push',
36144    value: function push(line) {
36145      var match = void 0;
36146      var event = void 0;
36147
36148      // strip whitespace
36149      line = line.replace(/^[\u0000\s]+|[\u0000\s]+$/g, '');
36150      if (line.length === 0) {
36151        // ignore empty lines
36152        return;
36153      }
36154
36155      // URIs
36156      if (line[0] !== '#') {
36157        this.trigger('data', {
36158          type: 'uri',
36159          uri: line
36160        });
36161        return;
36162      }
36163
36164      // Comments
36165      if (line.indexOf('#EXT') !== 0) {
36166        this.trigger('data', {
36167          type: 'comment',
36168          text: line.slice(1)
36169        });
36170        return;
36171      }
36172
36173      // strip off any carriage returns here so the regex matching
36174      // doesn't have to account for them.
36175      line = line.replace('\r', '');
36176
36177      // Tags
36178      match = /^#EXTM3U/.exec(line);
36179      if (match) {
36180        this.trigger('data', {
36181          type: 'tag',
36182          tagType: 'm3u'
36183        });
36184        return;
36185      }
36186      match = /^#EXTINF:?([0-9\.]*)?,?(.*)?$/.exec(line);
36187      if (match) {
36188        event = {
36189          type: 'tag',
36190          tagType: 'inf'
36191        };
36192        if (match[1]) {
36193          event.duration = parseFloat(match[1]);
36194        }
36195        if (match[2]) {
36196          event.title = match[2];
36197        }
36198        this.trigger('data', event);
36199        return;
36200      }
36201      match = /^#EXT-X-TARGETDURATION:?([0-9.]*)?/.exec(line);
36202      if (match) {
36203        event = {
36204          type: 'tag',
36205          tagType: 'targetduration'
36206        };
36207        if (match[1]) {
36208          event.duration = parseInt(match[1], 10);
36209        }
36210        this.trigger('data', event);
36211        return;
36212      }
36213      match = /^#ZEN-TOTAL-DURATION:?([0-9.]*)?/.exec(line);
36214      if (match) {
36215        event = {
36216          type: 'tag',
36217          tagType: 'totalduration'
36218        };
36219        if (match[1]) {
36220          event.duration = parseInt(match[1], 10);
36221        }
36222        this.trigger('data', event);
36223        return;
36224      }
36225      match = /^#EXT-X-VERSION:?([0-9.]*)?/.exec(line);
36226      if (match) {
36227        event = {
36228          type: 'tag',
36229          tagType: 'version'
36230        };
36231        if (match[1]) {
36232          event.version = parseInt(match[1], 10);
36233        }
36234        this.trigger('data', event);
36235        return;
36236      }
36237      match = /^#EXT-X-MEDIA-SEQUENCE:?(\-?[0-9.]*)?/.exec(line);
36238      if (match) {
36239        event = {
36240          type: 'tag',
36241          tagType: 'media-sequence'
36242        };
36243        if (match[1]) {
36244          event.number = parseInt(match[1], 10);
36245        }
36246        this.trigger('data', event);
36247        return;
36248      }
36249      match = /^#EXT-X-DISCONTINUITY-SEQUENCE:?(\-?[0-9.]*)?/.exec(line);
36250      if (match) {
36251        event = {
36252          type: 'tag',
36253          tagType: 'discontinuity-sequence'
36254        };
36255        if (match[1]) {
36256          event.number = parseInt(match[1], 10);
36257        }
36258        this.trigger('data', event);
36259        return;
36260      }
36261      match = /^#EXT-X-PLAYLIST-TYPE:?(.*)?$/.exec(line);
36262      if (match) {
36263        event = {
36264          type: 'tag',
36265          tagType: 'playlist-type'
36266        };
36267        if (match[1]) {
36268          event.playlistType = match[1];
36269        }
36270        this.trigger('data', event);
36271        return;
36272      }
36273      match = /^#EXT-X-BYTERANGE:?([0-9.]*)?@?([0-9.]*)?/.exec(line);
36274      if (match) {
36275        event = {
36276          type: 'tag',
36277          tagType: 'byterange'
36278        };
36279        if (match[1]) {
36280          event.length = parseInt(match[1], 10);
36281        }
36282        if (match[2]) {
36283          event.offset = parseInt(match[2], 10);
36284        }
36285        this.trigger('data', event);
36286        return;
36287      }
36288      match = /^#EXT-X-ALLOW-CACHE:?(YES|NO)?/.exec(line);
36289      if (match) {
36290        event = {
36291          type: 'tag',
36292          tagType: 'allow-cache'
36293        };
36294        if (match[1]) {
36295          event.allowed = !/NO/.test(match[1]);
36296        }
36297        this.trigger('data', event);
36298        return;
36299      }
36300      match = /^#EXT-X-MAP:?(.*)$/.exec(line);
36301      if (match) {
36302        event = {
36303          type: 'tag',
36304          tagType: 'map'
36305        };
36306
36307        if (match[1]) {
36308          var attributes = parseAttributes(match[1]);
36309
36310          if (attributes.URI) {
36311            event.uri = attributes.URI;
36312          }
36313          if (attributes.BYTERANGE) {
36314            var _attributes$BYTERANGE = attributes.BYTERANGE.split('@'),
36315                _attributes$BYTERANGE2 = _slicedToArray(_attributes$BYTERANGE, 2),
36316                length = _attributes$BYTERANGE2[0],
36317                offset = _attributes$BYTERANGE2[1];
36318
36319            event.byterange = {};
36320            if (length) {
36321              event.byterange.length = parseInt(length, 10);
36322            }
36323            if (offset) {
36324              event.byterange.offset = parseInt(offset, 10);
36325            }
36326          }
36327        }
36328
36329        this.trigger('data', event);
36330        return;
36331      }
36332      match = /^#EXT-X-STREAM-INF:?(.*)$/.exec(line);
36333      if (match) {
36334        event = {
36335          type: 'tag',
36336          tagType: 'stream-inf'
36337        };
36338        if (match[1]) {
36339          event.attributes = parseAttributes(match[1]);
36340
36341          if (event.attributes.RESOLUTION) {
36342            var split = event.attributes.RESOLUTION.split('x');
36343            var resolution = {};
36344
36345            if (split[0]) {
36346              resolution.width = parseInt(split[0], 10);
36347            }
36348            if (split[1]) {
36349              resolution.height = parseInt(split[1], 10);
36350            }
36351            event.attributes.RESOLUTION = resolution;
36352          }
36353          if (event.attributes.BANDWIDTH) {
36354            event.attributes.BANDWIDTH = parseInt(event.attributes.BANDWIDTH, 10);
36355          }
36356          if (event.attributes['PROGRAM-ID']) {
36357            event.attributes['PROGRAM-ID'] = parseInt(event.attributes['PROGRAM-ID'], 10);
36358          }
36359        }
36360        this.trigger('data', event);
36361        return;
36362      }
36363      match = /^#EXT-X-MEDIA:?(.*)$/.exec(line);
36364      if (match) {
36365        event = {
36366          type: 'tag',
36367          tagType: 'media'
36368        };
36369        if (match[1]) {
36370          event.attributes = parseAttributes(match[1]);
36371        }
36372        this.trigger('data', event);
36373        return;
36374      }
36375      match = /^#EXT-X-ENDLIST/.exec(line);
36376      if (match) {
36377        this.trigger('data', {
36378          type: 'tag',
36379          tagType: 'endlist'
36380        });
36381        return;
36382      }
36383      match = /^#EXT-X-DISCONTINUITY/.exec(line);
36384      if (match) {
36385        this.trigger('data', {
36386          type: 'tag',
36387          tagType: 'discontinuity'
36388        });
36389        return;
36390      }
36391      match = /^#EXT-X-PROGRAM-DATE-TIME:?(.*)$/.exec(line);
36392      if (match) {
36393        event = {
36394          type: 'tag',
36395          tagType: 'program-date-time'
36396        };
36397        if (match[1]) {
36398          event.dateTimeString = match[1];
36399          event.dateTimeObject = new Date(match[1]);
36400        }
36401        this.trigger('data', event);
36402        return;
36403      }
36404      match = /^#EXT-X-KEY:?(.*)$/.exec(line);
36405      if (match) {
36406        event = {
36407          type: 'tag',
36408          tagType: 'key'
36409        };
36410        if (match[1]) {
36411          event.attributes = parseAttributes(match[1]);
36412          // parse the IV string into a Uint32Array
36413          if (event.attributes.IV) {
36414            if (event.attributes.IV.substring(0, 2).toLowerCase() === '0x') {
36415              event.attributes.IV = event.attributes.IV.substring(2);
36416            }
36417
36418            event.attributes.IV = event.attributes.IV.match(/.{8}/g);
36419            event.attributes.IV[0] = parseInt(event.attributes.IV[0], 16);
36420            event.attributes.IV[1] = parseInt(event.attributes.IV[1], 16);
36421            event.attributes.IV[2] = parseInt(event.attributes.IV[2], 16);
36422            event.attributes.IV[3] = parseInt(event.attributes.IV[3], 16);
36423            event.attributes.IV = new Uint32Array(event.attributes.IV);
36424          }
36425        }
36426        this.trigger('data', event);
36427        return;
36428      }
36429      match = /^#EXT-X-CUE-OUT-CONT:?(.*)?$/.exec(line);
36430      if (match) {
36431        event = {
36432          type: 'tag',
36433          tagType: 'cue-out-cont'
36434        };
36435        if (match[1]) {
36436          event.data = match[1];
36437        } else {
36438          event.data = '';
36439        }
36440        this.trigger('data', event);
36441        return;
36442      }
36443      match = /^#EXT-X-CUE-OUT:?(.*)?$/.exec(line);
36444      if (match) {
36445        event = {
36446          type: 'tag',
36447          tagType: 'cue-out'
36448        };
36449        if (match[1]) {
36450          event.data = match[1];
36451        } else {
36452          event.data = '';
36453        }
36454        this.trigger('data', event);
36455        return;
36456      }
36457      match = /^#EXT-X-CUE-IN:?(.*)?$/.exec(line);
36458      if (match) {
36459        event = {
36460          type: 'tag',
36461          tagType: 'cue-in'
36462        };
36463        if (match[1]) {
36464          event.data = match[1];
36465        } else {
36466          event.data = '';
36467        }
36468        this.trigger('data', event);
36469        return;
36470      }
36471
36472      // unknown tag type
36473      this.trigger('data', {
36474        type: 'tag',
36475        data: line.slice(4)
36476      });
36477    }
36478  }]);
36479
36480  return ParseStream;
36481}(_stream2['default']);
36482
36483exports['default'] = ParseStream;
36484},{"./stream":37}],36:[function(require,module,exports){
36485'use strict';
36486
36487Object.defineProperty(exports, "__esModule", {
36488  value: true
36489});
36490
36491var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
36492
36493var _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; }; }();
36494
36495var _stream = require('./stream');
36496
36497var _stream2 = _interopRequireDefault(_stream);
36498
36499var _lineStream = require('./line-stream');
36500
36501var _lineStream2 = _interopRequireDefault(_lineStream);
36502
36503var _parseStream = require('./parse-stream');
36504
36505var _parseStream2 = _interopRequireDefault(_parseStream);
36506
36507function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
36508
36509function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
36510
36511function _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; }
36512
36513function _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; } /**
36514                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file m3u8/parser.js
36515                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
36516
36517
36518/**
36519 * A parser for M3U8 files. The current interpretation of the input is
36520 * exposed as a property `manifest` on parser objects. It's just two lines to
36521 * create and parse a manifest once you have the contents available as a string:
36522 *
36523 * ```js
36524 * var parser = new m3u8.Parser();
36525 * parser.push(xhr.responseText);
36526 * ```
36527 *
36528 * New input can later be applied to update the manifest object by calling
36529 * `push` again.
36530 *
36531 * The parser attempts to create a usable manifest object even if the
36532 * underlying input is somewhat nonsensical. It emits `info` and `warning`
36533 * events during the parse if it encounters input that seems invalid or
36534 * requires some property of the manifest object to be defaulted.
36535 *
36536 * @class Parser
36537 * @extends Stream
36538 */
36539var Parser = function (_Stream) {
36540  _inherits(Parser, _Stream);
36541
36542  function Parser() {
36543    _classCallCheck(this, Parser);
36544
36545    var _this = _possibleConstructorReturn(this, (Parser.__proto__ || Object.getPrototypeOf(Parser)).call(this));
36546
36547    _this.lineStream = new _lineStream2['default']();
36548    _this.parseStream = new _parseStream2['default']();
36549    _this.lineStream.pipe(_this.parseStream);
36550    /* eslint-disable consistent-this */
36551    var self = _this;
36552    /* eslint-enable consistent-this */
36553    var uris = [];
36554    var currentUri = {};
36555    // if specified, the active EXT-X-MAP definition
36556    var currentMap = void 0;
36557    // if specified, the active decryption key
36558    var _key = void 0;
36559    var noop = function noop() {};
36560    var defaultMediaGroups = {
36561      'AUDIO': {},
36562      'VIDEO': {},
36563      'CLOSED-CAPTIONS': {},
36564      'SUBTITLES': {}
36565    };
36566    // group segments into numbered timelines delineated by discontinuities
36567    var currentTimeline = 0;
36568
36569    // the manifest is empty until the parse stream begins delivering data
36570    _this.manifest = {
36571      allowCache: true,
36572      discontinuityStarts: [],
36573      segments: []
36574    };
36575
36576    // update the manifest with the m3u8 entry from the parse stream
36577    _this.parseStream.on('data', function (entry) {
36578      var mediaGroup = void 0;
36579      var rendition = void 0;
36580
36581      ({
36582        tag: function tag() {
36583          // switch based on the tag type
36584          (({
36585            'allow-cache': function allowCache() {
36586              this.manifest.allowCache = entry.allowed;
36587              if (!('allowed' in entry)) {
36588                this.trigger('info', {
36589                  message: 'defaulting allowCache to YES'
36590                });
36591                this.manifest.allowCache = true;
36592              }
36593            },
36594            byterange: function byterange() {
36595              var byterange = {};
36596
36597              if ('length' in entry) {
36598                currentUri.byterange = byterange;
36599                byterange.length = entry.length;
36600
36601                if (!('offset' in entry)) {
36602                  this.trigger('info', {
36603                    message: 'defaulting offset to zero'
36604                  });
36605                  entry.offset = 0;
36606                }
36607              }
36608              if ('offset' in entry) {
36609                currentUri.byterange = byterange;
36610                byterange.offset = entry.offset;
36611              }
36612            },
36613            endlist: function endlist() {
36614              this.manifest.endList = true;
36615            },
36616            inf: function inf() {
36617              if (!('mediaSequence' in this.manifest)) {
36618                this.manifest.mediaSequence = 0;
36619                this.trigger('info', {
36620                  message: 'defaulting media sequence to zero'
36621                });
36622              }
36623              if (!('discontinuitySequence' in this.manifest)) {
36624                this.manifest.discontinuitySequence = 0;
36625                this.trigger('info', {
36626                  message: 'defaulting discontinuity sequence to zero'
36627                });
36628              }
36629              if (entry.duration > 0) {
36630                currentUri.duration = entry.duration;
36631              }
36632
36633              if (entry.duration === 0) {
36634                currentUri.duration = 0.01;
36635                this.trigger('info', {
36636                  message: 'updating zero segment duration to a small value'
36637                });
36638              }
36639
36640              this.manifest.segments = uris;
36641            },
36642            key: function key() {
36643              if (!entry.attributes) {
36644                this.trigger('warn', {
36645                  message: 'ignoring key declaration without attribute list'
36646                });
36647                return;
36648              }
36649              // clear the active encryption key
36650              if (entry.attributes.METHOD === 'NONE') {
36651                _key = null;
36652                return;
36653              }
36654              if (!entry.attributes.URI) {
36655                this.trigger('warn', {
36656                  message: 'ignoring key declaration without URI'
36657                });
36658                return;
36659              }
36660              if (!entry.attributes.METHOD) {
36661                this.trigger('warn', {
36662                  message: 'defaulting key method to AES-128'
36663                });
36664              }
36665
36666              // setup an encryption key for upcoming segments
36667              _key = {
36668                method: entry.attributes.METHOD || 'AES-128',
36669                uri: entry.attributes.URI
36670              };
36671
36672              if (typeof entry.attributes.IV !== 'undefined') {
36673                _key.iv = entry.attributes.IV;
36674              }
36675            },
36676            'media-sequence': function mediaSequence() {
36677              if (!isFinite(entry.number)) {
36678                this.trigger('warn', {
36679                  message: 'ignoring invalid media sequence: ' + entry.number
36680                });
36681                return;
36682              }
36683              this.manifest.mediaSequence = entry.number;
36684            },
36685            'discontinuity-sequence': function discontinuitySequence() {
36686              if (!isFinite(entry.number)) {
36687                this.trigger('warn', {
36688                  message: 'ignoring invalid discontinuity sequence: ' + entry.number
36689                });
36690                return;
36691              }
36692              this.manifest.discontinuitySequence = entry.number;
36693              currentTimeline = entry.number;
36694            },
36695            'playlist-type': function playlistType() {
36696              if (!/VOD|EVENT/.test(entry.playlistType)) {
36697                this.trigger('warn', {
36698                  message: 'ignoring unknown playlist type: ' + entry.playlist
36699                });
36700                return;
36701              }
36702              this.manifest.playlistType = entry.playlistType;
36703            },
36704            map: function map() {
36705              currentMap = {};
36706              if (entry.uri) {
36707                currentMap.uri = entry.uri;
36708              }
36709              if (entry.byterange) {
36710                currentMap.byterange = entry.byterange;
36711              }
36712            },
36713            'stream-inf': function streamInf() {
36714              this.manifest.playlists = uris;
36715              this.manifest.mediaGroups = this.manifest.mediaGroups || defaultMediaGroups;
36716
36717              if (!entry.attributes) {
36718                this.trigger('warn', {
36719                  message: 'ignoring empty stream-inf attributes'
36720                });
36721                return;
36722              }
36723
36724              if (!currentUri.attributes) {
36725                currentUri.attributes = {};
36726              }
36727              _extends(currentUri.attributes, entry.attributes);
36728            },
36729            media: function media() {
36730              this.manifest.mediaGroups = this.manifest.mediaGroups || defaultMediaGroups;
36731
36732              if (!(entry.attributes && entry.attributes.TYPE && entry.attributes['GROUP-ID'] && entry.attributes.NAME)) {
36733                this.trigger('warn', {
36734                  message: 'ignoring incomplete or missing media group'
36735                });
36736                return;
36737              }
36738
36739              // find the media group, creating defaults as necessary
36740              var mediaGroupType = this.manifest.mediaGroups[entry.attributes.TYPE];
36741
36742              mediaGroupType[entry.attributes['GROUP-ID']] = mediaGroupType[entry.attributes['GROUP-ID']] || {};
36743              mediaGroup = mediaGroupType[entry.attributes['GROUP-ID']];
36744
36745              // collect the rendition metadata
36746              rendition = {
36747                'default': /yes/i.test(entry.attributes.DEFAULT)
36748              };
36749              if (rendition['default']) {
36750                rendition.autoselect = true;
36751              } else {
36752                rendition.autoselect = /yes/i.test(entry.attributes.AUTOSELECT);
36753              }
36754              if (entry.attributes.LANGUAGE) {
36755                rendition.language = entry.attributes.LANGUAGE;
36756              }
36757              if (entry.attributes.URI) {
36758                rendition.uri = entry.attributes.URI;
36759              }
36760              if (entry.attributes['INSTREAM-ID']) {
36761                rendition.instreamId = entry.attributes['INSTREAM-ID'];
36762              }
36763              if (entry.attributes.CHARACTERISTICS) {
36764                rendition.characteristics = entry.attributes.CHARACTERISTICS;
36765              }
36766              if (entry.attributes.FORCED) {
36767                rendition.forced = /yes/i.test(entry.attributes.FORCED);
36768              }
36769
36770              // insert the new rendition
36771              mediaGroup[entry.attributes.NAME] = rendition;
36772            },
36773            discontinuity: function discontinuity() {
36774              currentTimeline += 1;
36775              currentUri.discontinuity = true;
36776              this.manifest.discontinuityStarts.push(uris.length);
36777            },
36778            'program-date-time': function programDateTime() {
36779              this.manifest.dateTimeString = entry.dateTimeString;
36780              this.manifest.dateTimeObject = entry.dateTimeObject;
36781            },
36782            targetduration: function targetduration() {
36783              if (!isFinite(entry.duration) || entry.duration < 0) {
36784                this.trigger('warn', {
36785                  message: 'ignoring invalid target duration: ' + entry.duration
36786                });
36787                return;
36788              }
36789              this.manifest.targetDuration = entry.duration;
36790            },
36791            totalduration: function totalduration() {
36792              if (!isFinite(entry.duration) || entry.duration < 0) {
36793                this.trigger('warn', {
36794                  message: 'ignoring invalid total duration: ' + entry.duration
36795                });
36796                return;
36797              }
36798              this.manifest.totalDuration = entry.duration;
36799            },
36800            'cue-out': function cueOut() {
36801              currentUri.cueOut = entry.data;
36802            },
36803            'cue-out-cont': function cueOutCont() {
36804              currentUri.cueOutCont = entry.data;
36805            },
36806            'cue-in': function cueIn() {
36807              currentUri.cueIn = entry.data;
36808            }
36809          })[entry.tagType] || noop).call(self);
36810        },
36811        uri: function uri() {
36812          currentUri.uri = entry.uri;
36813          uris.push(currentUri);
36814
36815          // if no explicit duration was declared, use the target duration
36816          if (this.manifest.targetDuration && !('duration' in currentUri)) {
36817            this.trigger('warn', {
36818              message: 'defaulting segment duration to the target duration'
36819            });
36820            currentUri.duration = this.manifest.targetDuration;
36821          }
36822          // annotate with encryption information, if necessary
36823          if (_key) {
36824            currentUri.key = _key;
36825          }
36826          currentUri.timeline = currentTimeline;
36827          // annotate with initialization segment information, if necessary
36828          if (currentMap) {
36829            currentUri.map = currentMap;
36830          }
36831
36832          // prepare for the next URI
36833          currentUri = {};
36834        },
36835        comment: function comment() {
36836          // comments are not important for playback
36837        }
36838      })[entry.type].call(self);
36839    });
36840
36841    return _this;
36842  }
36843
36844  /**
36845   * Parse the input string and update the manifest object.
36846   *
36847   * @param {String} chunk a potentially incomplete portion of the manifest
36848   */
36849
36850
36851  _createClass(Parser, [{
36852    key: 'push',
36853    value: function push(chunk) {
36854      this.lineStream.push(chunk);
36855    }
36856
36857    /**
36858     * Flush any remaining input. This can be handy if the last line of an M3U8
36859     * manifest did not contain a trailing newline but the file has been
36860     * completely received.
36861     */
36862
36863  }, {
36864    key: 'end',
36865    value: function end() {
36866      // flush any buffered input
36867      this.lineStream.push('\n');
36868    }
36869  }]);
36870
36871  return Parser;
36872}(_stream2['default']);
36873
36874exports['default'] = Parser;
36875},{"./line-stream":34,"./parse-stream":35,"./stream":37}],37:[function(require,module,exports){
36876'use strict';
36877
36878Object.defineProperty(exports, "__esModule", {
36879  value: true
36880});
36881
36882var _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; }; }();
36883
36884function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
36885
36886/**
36887 * @file stream.js
36888 */
36889/**
36890 * A lightweight readable stream implemention that handles event dispatching.
36891 *
36892 * @class Stream
36893 */
36894var Stream = function () {
36895  function Stream() {
36896    _classCallCheck(this, Stream);
36897
36898    this.listeners = {};
36899  }
36900
36901  /**
36902   * Add a listener for a specified event type.
36903   *
36904   * @param {String} type the event name
36905   * @param {Function} listener the callback to be invoked when an event of
36906   * the specified type occurs
36907   */
36908
36909
36910  _createClass(Stream, [{
36911    key: 'on',
36912    value: function on(type, listener) {
36913      if (!this.listeners[type]) {
36914        this.listeners[type] = [];
36915      }
36916      this.listeners[type].push(listener);
36917    }
36918
36919    /**
36920     * Remove a listener for a specified event type.
36921     *
36922     * @param {String} type the event name
36923     * @param {Function} listener  a function previously registered for this
36924     * type of event through `on`
36925     * @return {Boolean} if we could turn it off or not
36926     */
36927
36928  }, {
36929    key: 'off',
36930    value: function off(type, listener) {
36931      if (!this.listeners[type]) {
36932        return false;
36933      }
36934
36935      var index = this.listeners[type].indexOf(listener);
36936
36937      this.listeners[type].splice(index, 1);
36938      return index > -1;
36939    }
36940
36941    /**
36942     * Trigger an event of the specified type on this stream. Any additional
36943     * arguments to this function are passed as parameters to event listeners.
36944     *
36945     * @param {String} type the event name
36946     */
36947
36948  }, {
36949    key: 'trigger',
36950    value: function trigger(type) {
36951      var callbacks = this.listeners[type];
36952      var i = void 0;
36953      var length = void 0;
36954      var args = void 0;
36955
36956      if (!callbacks) {
36957        return;
36958      }
36959      // Slicing the arguments on every invocation of this method
36960      // can add a significant amount of overhead. Avoid the
36961      // intermediate object creation for the common case of a
36962      // single callback argument
36963      if (arguments.length === 2) {
36964        length = callbacks.length;
36965        for (i = 0; i < length; ++i) {
36966          callbacks[i].call(this, arguments[1]);
36967        }
36968      } else {
36969        args = Array.prototype.slice.call(arguments, 1);
36970        length = callbacks.length;
36971        for (i = 0; i < length; ++i) {
36972          callbacks[i].apply(this, args);
36973        }
36974      }
36975    }
36976
36977    /**
36978     * Destroys the stream and cleans up.
36979     */
36980
36981  }, {
36982    key: 'dispose',
36983    value: function dispose() {
36984      this.listeners = {};
36985    }
36986    /**
36987     * Forwards all `data` events on this stream to the destination stream. The
36988     * destination stream should provide a method `push` to receive the data
36989     * events as they arrive.
36990     *
36991     * @param {Stream} destination the stream that will receive all `data` events
36992     * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
36993     */
36994
36995  }, {
36996    key: 'pipe',
36997    value: function pipe(destination) {
36998      this.on('data', function (data) {
36999        destination.push(data);
37000      });
37001    }
37002  }]);
37003
37004  return Stream;
37005}();
37006
37007exports['default'] = Stream;
37008},{}],38:[function(require,module,exports){
37009/**
37010 * mux.js
37011 *
37012 * Copyright (c) 2016 Brightcove
37013 * All rights reserved.
37014 *
37015 * A stream-based aac to mp4 converter. This utility can be used to
37016 * deliver mp4s to a SourceBuffer on platforms that support native
37017 * Media Source Extensions.
37018 */
37019'use strict';
37020var Stream = require('../utils/stream.js');
37021
37022// Constants
37023var AacStream;
37024
37025/**
37026 * Splits an incoming stream of binary data into ADTS and ID3 Frames.
37027 */
37028
37029AacStream = function() {
37030  var
37031    everything = new Uint8Array(),
37032    timeStamp = 0;
37033
37034  AacStream.prototype.init.call(this);
37035
37036  this.setTimestamp = function(timestamp) {
37037    timeStamp = timestamp;
37038  };
37039
37040  this.parseId3TagSize = function(header, byteIndex) {
37041    var
37042      returnSize = (header[byteIndex + 6] << 21) |
37043                   (header[byteIndex + 7] << 14) |
37044                   (header[byteIndex + 8] << 7) |
37045                   (header[byteIndex + 9]),
37046      flags = header[byteIndex + 5],
37047      footerPresent = (flags & 16) >> 4;
37048
37049    if (footerPresent) {
37050      return returnSize + 20;
37051    }
37052    return returnSize + 10;
37053  };
37054
37055  this.parseAdtsSize = function(header, byteIndex) {
37056    var
37057      lowThree = (header[byteIndex + 5] & 0xE0) >> 5,
37058      middle = header[byteIndex + 4] << 3,
37059      highTwo = header[byteIndex + 3] & 0x3 << 11;
37060
37061    return (highTwo | middle) | lowThree;
37062  };
37063
37064  this.push = function(bytes) {
37065    var
37066      frameSize = 0,
37067      byteIndex = 0,
37068      bytesLeft,
37069      chunk,
37070      packet,
37071      tempLength;
37072
37073    // If there are bytes remaining from the last segment, prepend them to the
37074    // bytes that were pushed in
37075    if (everything.length) {
37076      tempLength = everything.length;
37077      everything = new Uint8Array(bytes.byteLength + tempLength);
37078      everything.set(everything.subarray(0, tempLength));
37079      everything.set(bytes, tempLength);
37080    } else {
37081      everything = bytes;
37082    }
37083
37084    while (everything.length - byteIndex >= 3) {
37085      if ((everything[byteIndex] === 'I'.charCodeAt(0)) &&
37086          (everything[byteIndex + 1] === 'D'.charCodeAt(0)) &&
37087          (everything[byteIndex + 2] === '3'.charCodeAt(0))) {
37088
37089        // Exit early because we don't have enough to parse
37090        // the ID3 tag header
37091        if (everything.length - byteIndex < 10) {
37092          break;
37093        }
37094
37095        // check framesize
37096        frameSize = this.parseId3TagSize(everything, byteIndex);
37097
37098        // Exit early if we don't have enough in the buffer
37099        // to emit a full packet
37100        if (frameSize > everything.length) {
37101          break;
37102        }
37103        chunk = {
37104          type: 'timed-metadata',
37105          data: everything.subarray(byteIndex, byteIndex + frameSize)
37106        };
37107        this.trigger('data', chunk);
37108        byteIndex += frameSize;
37109        continue;
37110      } else if ((everything[byteIndex] & 0xff === 0xff) &&
37111                 ((everything[byteIndex + 1] & 0xf0) === 0xf0)) {
37112
37113        // Exit early because we don't have enough to parse
37114        // the ADTS frame header
37115        if (everything.length - byteIndex < 7) {
37116          break;
37117        }
37118
37119        frameSize = this.parseAdtsSize(everything, byteIndex);
37120
37121        // Exit early if we don't have enough in the buffer
37122        // to emit a full packet
37123        if (frameSize > everything.length) {
37124          break;
37125        }
37126
37127        packet = {
37128          type: 'audio',
37129          data: everything.subarray(byteIndex, byteIndex + frameSize),
37130          pts: timeStamp,
37131          dts: timeStamp
37132        };
37133        this.trigger('data', packet);
37134        byteIndex += frameSize;
37135        continue;
37136      }
37137      byteIndex++;
37138    }
37139    bytesLeft = everything.length - byteIndex;
37140
37141    if (bytesLeft > 0) {
37142      everything = everything.subarray(byteIndex);
37143    } else {
37144      everything = new Uint8Array();
37145    }
37146  };
37147};
37148
37149AacStream.prototype = new Stream();
37150
37151module.exports = AacStream;
37152
37153},{"../utils/stream.js":62}],39:[function(require,module,exports){
37154/**
37155 * mux.js
37156 *
37157 * Copyright (c) 2016 Brightcove
37158 * All rights reserved.
37159 *
37160 * Utilities to detect basic properties and metadata about Aac data.
37161 */
37162'use strict';
37163
37164var ADTS_SAMPLING_FREQUENCIES = [
37165  96000,
37166  88200,
37167  64000,
37168  48000,
37169  44100,
37170  32000,
37171  24000,
37172  22050,
37173  16000,
37174  12000,
37175  11025,
37176  8000,
37177  7350
37178];
37179
37180var parseSyncSafeInteger = function(data) {
37181  return (data[0] << 21) |
37182          (data[1] << 14) |
37183          (data[2] << 7) |
37184          (data[3]);
37185};
37186
37187// return a percent-encoded representation of the specified byte range
37188// @see http://en.wikipedia.org/wiki/Percent-encoding
37189var percentEncode = function(bytes, start, end) {
37190  var i, result = '';
37191  for (i = start; i < end; i++) {
37192    result += '%' + ('00' + bytes[i].toString(16)).slice(-2);
37193  }
37194  return result;
37195};
37196
37197// return the string representation of the specified byte range,
37198// interpreted as ISO-8859-1.
37199var parseIso88591 = function(bytes, start, end) {
37200  return unescape(percentEncode(bytes, start, end)); // jshint ignore:line
37201};
37202
37203var parseId3TagSize = function(header, byteIndex) {
37204  var
37205    returnSize = (header[byteIndex + 6] << 21) |
37206                 (header[byteIndex + 7] << 14) |
37207                 (header[byteIndex + 8] << 7) |
37208                 (header[byteIndex + 9]),
37209    flags = header[byteIndex + 5],
37210    footerPresent = (flags & 16) >> 4;
37211
37212  if (footerPresent) {
37213    return returnSize + 20;
37214  }
37215  return returnSize + 10;
37216};
37217
37218var parseAdtsSize = function(header, byteIndex) {
37219  var
37220    lowThree = (header[byteIndex + 5] & 0xE0) >> 5,
37221    middle = header[byteIndex + 4] << 3,
37222    highTwo = header[byteIndex + 3] & 0x3 << 11;
37223
37224  return (highTwo | middle) | lowThree;
37225};
37226
37227var parseType = function(header, byteIndex) {
37228  if ((header[byteIndex] === 'I'.charCodeAt(0)) &&
37229      (header[byteIndex + 1] === 'D'.charCodeAt(0)) &&
37230      (header[byteIndex + 2] === '3'.charCodeAt(0))) {
37231    return 'timed-metadata';
37232  } else if ((header[byteIndex] & 0xff === 0xff) &&
37233             ((header[byteIndex + 1] & 0xf0) === 0xf0)) {
37234    return 'audio';
37235  }
37236  return null;
37237};
37238
37239var parseSampleRate = function(packet) {
37240  var i = 0;
37241
37242  while (i + 5 < packet.length) {
37243    if (packet[i] !== 0xFF || (packet[i + 1] & 0xF6) !== 0xF0) {
37244      // If a valid header was not found,  jump one forward and attempt to
37245      // find a valid ADTS header starting at the next byte
37246      i++;
37247      continue;
37248    }
37249    return ADTS_SAMPLING_FREQUENCIES[(packet[i + 2] & 0x3c) >>> 2];
37250  }
37251
37252  return null;
37253};
37254
37255var parseAacTimestamp = function(packet) {
37256  var frameStart, frameSize, frame, frameHeader;
37257
37258  // find the start of the first frame and the end of the tag
37259  frameStart = 10;
37260  if (packet[5] & 0x40) {
37261    // advance the frame start past the extended header
37262    frameStart += 4; // header size field
37263    frameStart += parseSyncSafeInteger(packet.subarray(10, 14));
37264  }
37265
37266  // parse one or more ID3 frames
37267  // http://id3.org/id3v2.3.0#ID3v2_frame_overview
37268  do {
37269    // determine the number of bytes in this frame
37270    frameSize = parseSyncSafeInteger(packet.subarray(frameStart + 4, frameStart + 8));
37271    if (frameSize < 1) {
37272      return null;
37273    }
37274    frameHeader = String.fromCharCode(packet[frameStart],
37275                                      packet[frameStart + 1],
37276                                      packet[frameStart + 2],
37277                                      packet[frameStart + 3]);
37278
37279    if (frameHeader === 'PRIV') {
37280      frame = packet.subarray(frameStart + 10, frameStart + frameSize + 10);
37281
37282      for (var i = 0; i < frame.byteLength; i++) {
37283        if (frame[i] === 0) {
37284          var owner = parseIso88591(frame, 0, i);
37285          if (owner === 'com.apple.streaming.transportStreamTimestamp') {
37286            var d = frame.subarray(i + 1);
37287            var size = ((d[3] & 0x01)  << 30) |
37288                       (d[4]  << 22) |
37289                       (d[5] << 14) |
37290                       (d[6] << 6) |
37291                       (d[7] >>> 2);
37292            size *= 4;
37293            size += d[7] & 0x03;
37294
37295            return size;
37296          }
37297          break;
37298        }
37299      }
37300    }
37301
37302    frameStart += 10; // advance past the frame header
37303    frameStart += frameSize; // advance past the frame body
37304  } while (frameStart < packet.byteLength);
37305  return null;
37306};
37307
37308module.exports = {
37309  parseId3TagSize: parseId3TagSize,
37310  parseAdtsSize: parseAdtsSize,
37311  parseType: parseType,
37312  parseSampleRate: parseSampleRate,
37313  parseAacTimestamp: parseAacTimestamp
37314};
37315
37316},{}],40:[function(require,module,exports){
37317'use strict';
37318
37319var Stream = require('../utils/stream.js');
37320
37321var AdtsStream;
37322
37323var
37324  ADTS_SAMPLING_FREQUENCIES = [
37325    96000,
37326    88200,
37327    64000,
37328    48000,
37329    44100,
37330    32000,
37331    24000,
37332    22050,
37333    16000,
37334    12000,
37335    11025,
37336    8000,
37337    7350
37338  ];
37339
37340/*
37341 * Accepts a ElementaryStream and emits data events with parsed
37342 * AAC Audio Frames of the individual packets. Input audio in ADTS
37343 * format is unpacked and re-emitted as AAC frames.
37344 *
37345 * @see http://wiki.multimedia.cx/index.php?title=ADTS
37346 * @see http://wiki.multimedia.cx/?title=Understanding_AAC
37347 */
37348AdtsStream = function() {
37349  var buffer;
37350
37351  AdtsStream.prototype.init.call(this);
37352
37353  this.push = function(packet) {
37354    var
37355      i = 0,
37356      frameNum = 0,
37357      frameLength,
37358      protectionSkipBytes,
37359      frameEnd,
37360      oldBuffer,
37361      sampleCount,
37362      adtsFrameDuration;
37363
37364    if (packet.type !== 'audio') {
37365      // ignore non-audio data
37366      return;
37367    }
37368
37369    // Prepend any data in the buffer to the input data so that we can parse
37370    // aac frames the cross a PES packet boundary
37371    if (buffer) {
37372      oldBuffer = buffer;
37373      buffer = new Uint8Array(oldBuffer.byteLength + packet.data.byteLength);
37374      buffer.set(oldBuffer);
37375      buffer.set(packet.data, oldBuffer.byteLength);
37376    } else {
37377      buffer = packet.data;
37378    }
37379
37380    // unpack any ADTS frames which have been fully received
37381    // for details on the ADTS header, see http://wiki.multimedia.cx/index.php?title=ADTS
37382    while (i + 5 < buffer.length) {
37383
37384      // Loook for the start of an ADTS header..
37385      if (buffer[i] !== 0xFF || (buffer[i + 1] & 0xF6) !== 0xF0) {
37386        // If a valid header was not found,  jump one forward and attempt to
37387        // find a valid ADTS header starting at the next byte
37388        i++;
37389        continue;
37390      }
37391
37392      // The protection skip bit tells us if we have 2 bytes of CRC data at the
37393      // end of the ADTS header
37394      protectionSkipBytes = (~buffer[i + 1] & 0x01) * 2;
37395
37396      // Frame length is a 13 bit integer starting 16 bits from the
37397      // end of the sync sequence
37398      frameLength = ((buffer[i + 3] & 0x03) << 11) |
37399        (buffer[i + 4] << 3) |
37400        ((buffer[i + 5] & 0xe0) >> 5);
37401
37402      sampleCount = ((buffer[i + 6] & 0x03) + 1) * 1024;
37403      adtsFrameDuration = (sampleCount * 90000) /
37404        ADTS_SAMPLING_FREQUENCIES[(buffer[i + 2] & 0x3c) >>> 2];
37405
37406      frameEnd = i + frameLength;
37407
37408      // If we don't have enough data to actually finish this ADTS frame, return
37409      // and wait for more data
37410      if (buffer.byteLength < frameEnd) {
37411        return;
37412      }
37413
37414      // Otherwise, deliver the complete AAC frame
37415      this.trigger('data', {
37416        pts: packet.pts + (frameNum * adtsFrameDuration),
37417        dts: packet.dts + (frameNum * adtsFrameDuration),
37418        sampleCount: sampleCount,
37419        audioobjecttype: ((buffer[i + 2] >>> 6) & 0x03) + 1,
37420        channelcount: ((buffer[i + 2] & 1) << 2) |
37421          ((buffer[i + 3] & 0xc0) >>> 6),
37422        samplerate: ADTS_SAMPLING_FREQUENCIES[(buffer[i + 2] & 0x3c) >>> 2],
37423        samplingfrequencyindex: (buffer[i + 2] & 0x3c) >>> 2,
37424        // assume ISO/IEC 14496-12 AudioSampleEntry default of 16
37425        samplesize: 16,
37426        data: buffer.subarray(i + 7 + protectionSkipBytes, frameEnd)
37427      });
37428
37429      // If the buffer is empty, clear it and return
37430      if (buffer.byteLength === frameEnd) {
37431        buffer = undefined;
37432        return;
37433      }
37434
37435      frameNum++;
37436
37437      // Remove the finished frame from the buffer and start the process again
37438      buffer = buffer.subarray(frameEnd);
37439    }
37440  };
37441  this.flush = function() {
37442    this.trigger('done');
37443  };
37444};
37445
37446AdtsStream.prototype = new Stream();
37447
37448module.exports = AdtsStream;
37449
37450},{"../utils/stream.js":62}],41:[function(require,module,exports){
37451'use strict';
37452
37453var Stream = require('../utils/stream.js');
37454var ExpGolomb = require('../utils/exp-golomb.js');
37455
37456var H264Stream, NalByteStream;
37457var PROFILES_WITH_OPTIONAL_SPS_DATA;
37458
37459/**
37460 * Accepts a NAL unit byte stream and unpacks the embedded NAL units.
37461 */
37462NalByteStream = function() {
37463  var
37464    syncPoint = 0,
37465    i,
37466    buffer;
37467  NalByteStream.prototype.init.call(this);
37468
37469  this.push = function(data) {
37470    var swapBuffer;
37471
37472    if (!buffer) {
37473      buffer = data.data;
37474    } else {
37475      swapBuffer = new Uint8Array(buffer.byteLength + data.data.byteLength);
37476      swapBuffer.set(buffer);
37477      swapBuffer.set(data.data, buffer.byteLength);
37478      buffer = swapBuffer;
37479    }
37480
37481    // Rec. ITU-T H.264, Annex B
37482    // scan for NAL unit boundaries
37483
37484    // a match looks like this:
37485    // 0 0 1 .. NAL .. 0 0 1
37486    // ^ sync point        ^ i
37487    // or this:
37488    // 0 0 1 .. NAL .. 0 0 0
37489    // ^ sync point        ^ i
37490
37491    // advance the sync point to a NAL start, if necessary
37492    for (; syncPoint < buffer.byteLength - 3; syncPoint++) {
37493      if (buffer[syncPoint + 2] === 1) {
37494        // the sync point is properly aligned
37495        i = syncPoint + 5;
37496        break;
37497      }
37498    }
37499
37500    while (i < buffer.byteLength) {
37501      // look at the current byte to determine if we've hit the end of
37502      // a NAL unit boundary
37503      switch (buffer[i]) {
37504      case 0:
37505        // skip past non-sync sequences
37506        if (buffer[i - 1] !== 0) {
37507          i += 2;
37508          break;
37509        } else if (buffer[i - 2] !== 0) {
37510          i++;
37511          break;
37512        }
37513
37514        // deliver the NAL unit if it isn't empty
37515        if (syncPoint + 3 !== i - 2) {
37516          this.trigger('data', buffer.subarray(syncPoint + 3, i - 2));
37517        }
37518
37519        // drop trailing zeroes
37520        do {
37521          i++;
37522        } while (buffer[i] !== 1 && i < buffer.length);
37523        syncPoint = i - 2;
37524        i += 3;
37525        break;
37526      case 1:
37527        // skip past non-sync sequences
37528        if (buffer[i - 1] !== 0 ||
37529            buffer[i - 2] !== 0) {
37530          i += 3;
37531          break;
37532        }
37533
37534        // deliver the NAL unit
37535        this.trigger('data', buffer.subarray(syncPoint + 3, i - 2));
37536        syncPoint = i - 2;
37537        i += 3;
37538        break;
37539      default:
37540        // the current byte isn't a one or zero, so it cannot be part
37541        // of a sync sequence
37542        i += 3;
37543        break;
37544      }
37545    }
37546    // filter out the NAL units that were delivered
37547    buffer = buffer.subarray(syncPoint);
37548    i -= syncPoint;
37549    syncPoint = 0;
37550  };
37551
37552  this.flush = function() {
37553    // deliver the last buffered NAL unit
37554    if (buffer && buffer.byteLength > 3) {
37555      this.trigger('data', buffer.subarray(syncPoint + 3));
37556    }
37557    // reset the stream state
37558    buffer = null;
37559    syncPoint = 0;
37560    this.trigger('done');
37561  };
37562};
37563NalByteStream.prototype = new Stream();
37564
37565// values of profile_idc that indicate additional fields are included in the SPS
37566// see Recommendation ITU-T H.264 (4/2013),
37567// 7.3.2.1.1 Sequence parameter set data syntax
37568PROFILES_WITH_OPTIONAL_SPS_DATA = {
37569  100: true,
37570  110: true,
37571  122: true,
37572  244: true,
37573  44: true,
37574  83: true,
37575  86: true,
37576  118: true,
37577  128: true,
37578  138: true,
37579  139: true,
37580  134: true
37581};
37582
37583/**
37584 * Accepts input from a ElementaryStream and produces H.264 NAL unit data
37585 * events.
37586 */
37587H264Stream = function() {
37588  var
37589    nalByteStream = new NalByteStream(),
37590    self,
37591    trackId,
37592    currentPts,
37593    currentDts,
37594
37595    discardEmulationPreventionBytes,
37596    readSequenceParameterSet,
37597    skipScalingList;
37598
37599  H264Stream.prototype.init.call(this);
37600  self = this;
37601
37602  this.push = function(packet) {
37603    if (packet.type !== 'video') {
37604      return;
37605    }
37606    trackId = packet.trackId;
37607    currentPts = packet.pts;
37608    currentDts = packet.dts;
37609
37610    nalByteStream.push(packet);
37611  };
37612
37613  nalByteStream.on('data', function(data) {
37614    var
37615      event = {
37616        trackId: trackId,
37617        pts: currentPts,
37618        dts: currentDts,
37619        data: data
37620      };
37621
37622    switch (data[0] & 0x1f) {
37623    case 0x05:
37624      event.nalUnitType = 'slice_layer_without_partitioning_rbsp_idr';
37625      break;
37626    case 0x06:
37627      event.nalUnitType = 'sei_rbsp';
37628      event.escapedRBSP = discardEmulationPreventionBytes(data.subarray(1));
37629      break;
37630    case 0x07:
37631      event.nalUnitType = 'seq_parameter_set_rbsp';
37632      event.escapedRBSP = discardEmulationPreventionBytes(data.subarray(1));
37633      event.config = readSequenceParameterSet(event.escapedRBSP);
37634      break;
37635    case 0x08:
37636      event.nalUnitType = 'pic_parameter_set_rbsp';
37637      break;
37638    case 0x09:
37639      event.nalUnitType = 'access_unit_delimiter_rbsp';
37640      break;
37641
37642    default:
37643      break;
37644    }
37645    self.trigger('data', event);
37646  });
37647  nalByteStream.on('done', function() {
37648    self.trigger('done');
37649  });
37650
37651  this.flush = function() {
37652    nalByteStream.flush();
37653  };
37654
37655  /**
37656   * Advance the ExpGolomb decoder past a scaling list. The scaling
37657   * list is optionally transmitted as part of a sequence parameter
37658   * set and is not relevant to transmuxing.
37659   * @param count {number} the number of entries in this scaling list
37660   * @param expGolombDecoder {object} an ExpGolomb pointed to the
37661   * start of a scaling list
37662   * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
37663   */
37664  skipScalingList = function(count, expGolombDecoder) {
37665    var
37666      lastScale = 8,
37667      nextScale = 8,
37668      j,
37669      deltaScale;
37670
37671    for (j = 0; j < count; j++) {
37672      if (nextScale !== 0) {
37673        deltaScale = expGolombDecoder.readExpGolomb();
37674        nextScale = (lastScale + deltaScale + 256) % 256;
37675      }
37676
37677      lastScale = (nextScale === 0) ? lastScale : nextScale;
37678    }
37679  };
37680
37681  /**
37682   * Expunge any "Emulation Prevention" bytes from a "Raw Byte
37683   * Sequence Payload"
37684   * @param data {Uint8Array} the bytes of a RBSP from a NAL
37685   * unit
37686   * @return {Uint8Array} the RBSP without any Emulation
37687   * Prevention Bytes
37688   */
37689  discardEmulationPreventionBytes = function(data) {
37690    var
37691      length = data.byteLength,
37692      emulationPreventionBytesPositions = [],
37693      i = 1,
37694      newLength, newData;
37695
37696    // Find all `Emulation Prevention Bytes`
37697    while (i < length - 2) {
37698      if (data[i] === 0 && data[i + 1] === 0 && data[i + 2] === 0x03) {
37699        emulationPreventionBytesPositions.push(i + 2);
37700        i += 2;
37701      } else {
37702        i++;
37703      }
37704    }
37705
37706    // If no Emulation Prevention Bytes were found just return the original
37707    // array
37708    if (emulationPreventionBytesPositions.length === 0) {
37709      return data;
37710    }
37711
37712    // Create a new array to hold the NAL unit data
37713    newLength = length - emulationPreventionBytesPositions.length;
37714    newData = new Uint8Array(newLength);
37715    var sourceIndex = 0;
37716
37717    for (i = 0; i < newLength; sourceIndex++, i++) {
37718      if (sourceIndex === emulationPreventionBytesPositions[0]) {
37719        // Skip this byte
37720        sourceIndex++;
37721        // Remove this position index
37722        emulationPreventionBytesPositions.shift();
37723      }
37724      newData[i] = data[sourceIndex];
37725    }
37726
37727    return newData;
37728  };
37729
37730  /**
37731   * Read a sequence parameter set and return some interesting video
37732   * properties. A sequence parameter set is the H264 metadata that
37733   * describes the properties of upcoming video frames.
37734   * @param data {Uint8Array} the bytes of a sequence parameter set
37735   * @return {object} an object with configuration parsed from the
37736   * sequence parameter set, including the dimensions of the
37737   * associated video frames.
37738   */
37739  readSequenceParameterSet = function(data) {
37740    var
37741      frameCropLeftOffset = 0,
37742      frameCropRightOffset = 0,
37743      frameCropTopOffset = 0,
37744      frameCropBottomOffset = 0,
37745      sarScale = 1,
37746      expGolombDecoder, profileIdc, levelIdc, profileCompatibility,
37747      chromaFormatIdc, picOrderCntType,
37748      numRefFramesInPicOrderCntCycle, picWidthInMbsMinus1,
37749      picHeightInMapUnitsMinus1,
37750      frameMbsOnlyFlag,
37751      scalingListCount,
37752      sarRatio,
37753      aspectRatioIdc,
37754      i;
37755
37756    expGolombDecoder = new ExpGolomb(data);
37757    profileIdc = expGolombDecoder.readUnsignedByte(); // profile_idc
37758    profileCompatibility = expGolombDecoder.readUnsignedByte(); // constraint_set[0-5]_flag
37759    levelIdc = expGolombDecoder.readUnsignedByte(); // level_idc u(8)
37760    expGolombDecoder.skipUnsignedExpGolomb(); // seq_parameter_set_id
37761
37762    // some profiles have more optional data we don't need
37763    if (PROFILES_WITH_OPTIONAL_SPS_DATA[profileIdc]) {
37764      chromaFormatIdc = expGolombDecoder.readUnsignedExpGolomb();
37765      if (chromaFormatIdc === 3) {
37766        expGolombDecoder.skipBits(1); // separate_colour_plane_flag
37767      }
37768      expGolombDecoder.skipUnsignedExpGolomb(); // bit_depth_luma_minus8
37769      expGolombDecoder.skipUnsignedExpGolomb(); // bit_depth_chroma_minus8
37770      expGolombDecoder.skipBits(1); // qpprime_y_zero_transform_bypass_flag
37771      if (expGolombDecoder.readBoolean()) { // seq_scaling_matrix_present_flag
37772        scalingListCount = (chromaFormatIdc !== 3) ? 8 : 12;
37773        for (i = 0; i < scalingListCount; i++) {
37774          if (expGolombDecoder.readBoolean()) { // seq_scaling_list_present_flag[ i ]
37775            if (i < 6) {
37776              skipScalingList(16, expGolombDecoder);
37777            } else {
37778              skipScalingList(64, expGolombDecoder);
37779            }
37780          }
37781        }
37782      }
37783    }
37784
37785    expGolombDecoder.skipUnsignedExpGolomb(); // log2_max_frame_num_minus4
37786    picOrderCntType = expGolombDecoder.readUnsignedExpGolomb();
37787
37788    if (picOrderCntType === 0) {
37789      expGolombDecoder.readUnsignedExpGolomb(); // log2_max_pic_order_cnt_lsb_minus4
37790    } else if (picOrderCntType === 1) {
37791      expGolombDecoder.skipBits(1); // delta_pic_order_always_zero_flag
37792      expGolombDecoder.skipExpGolomb(); // offset_for_non_ref_pic
37793      expGolombDecoder.skipExpGolomb(); // offset_for_top_to_bottom_field
37794      numRefFramesInPicOrderCntCycle = expGolombDecoder.readUnsignedExpGolomb();
37795      for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
37796        expGolombDecoder.skipExpGolomb(); // offset_for_ref_frame[ i ]
37797      }
37798    }
37799
37800    expGolombDecoder.skipUnsignedExpGolomb(); // max_num_ref_frames
37801    expGolombDecoder.skipBits(1); // gaps_in_frame_num_value_allowed_flag
37802
37803    picWidthInMbsMinus1 = expGolombDecoder.readUnsignedExpGolomb();
37804    picHeightInMapUnitsMinus1 = expGolombDecoder.readUnsignedExpGolomb();
37805
37806    frameMbsOnlyFlag = expGolombDecoder.readBits(1);
37807    if (frameMbsOnlyFlag === 0) {
37808      expGolombDecoder.skipBits(1); // mb_adaptive_frame_field_flag
37809    }
37810
37811    expGolombDecoder.skipBits(1); // direct_8x8_inference_flag
37812    if (expGolombDecoder.readBoolean()) { // frame_cropping_flag
37813      frameCropLeftOffset = expGolombDecoder.readUnsignedExpGolomb();
37814      frameCropRightOffset = expGolombDecoder.readUnsignedExpGolomb();
37815      frameCropTopOffset = expGolombDecoder.readUnsignedExpGolomb();
37816      frameCropBottomOffset = expGolombDecoder.readUnsignedExpGolomb();
37817    }
37818    if (expGolombDecoder.readBoolean()) {
37819      // vui_parameters_present_flag
37820      if (expGolombDecoder.readBoolean()) {
37821        // aspect_ratio_info_present_flag
37822        aspectRatioIdc = expGolombDecoder.readUnsignedByte();
37823        switch (aspectRatioIdc) {
37824          case 1: sarRatio = [1, 1]; break;
37825          case 2: sarRatio = [12, 11]; break;
37826          case 3: sarRatio = [10, 11]; break;
37827          case 4: sarRatio = [16, 11]; break;
37828          case 5: sarRatio = [40, 33]; break;
37829          case 6: sarRatio = [24, 11]; break;
37830          case 7: sarRatio = [20, 11]; break;
37831          case 8: sarRatio = [32, 11]; break;
37832          case 9: sarRatio = [80, 33]; break;
37833          case 10: sarRatio = [18, 11]; break;
37834          case 11: sarRatio = [15, 11]; break;
37835          case 12: sarRatio = [64, 33]; break;
37836          case 13: sarRatio = [160, 99]; break;
37837          case 14: sarRatio = [4, 3]; break;
37838          case 15: sarRatio = [3, 2]; break;
37839          case 16: sarRatio = [2, 1]; break;
37840          case 255: {
37841            sarRatio = [expGolombDecoder.readUnsignedByte() << 8 |
37842                        expGolombDecoder.readUnsignedByte(),
37843                        expGolombDecoder.readUnsignedByte() << 8 |
37844                        expGolombDecoder.readUnsignedByte() ];
37845            break;
37846          }
37847        }
37848        if (sarRatio) {
37849          sarScale = sarRatio[0] / sarRatio[1];
37850        }
37851      }
37852    }
37853    return {
37854      profileIdc: profileIdc,
37855      levelIdc: levelIdc,
37856      profileCompatibility: profileCompatibility,
37857      width: Math.ceil((((picWidthInMbsMinus1 + 1) * 16) - frameCropLeftOffset * 2 - frameCropRightOffset * 2) * sarScale),
37858      height: ((2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16) - (frameCropTopOffset * 2) - (frameCropBottomOffset * 2)
37859    };
37860  };
37861
37862};
37863H264Stream.prototype = new Stream();
37864
37865module.exports = {
37866  H264Stream: H264Stream,
37867  NalByteStream: NalByteStream
37868};
37869
37870},{"../utils/exp-golomb.js":61,"../utils/stream.js":62}],42:[function(require,module,exports){
37871var highPrefix = [33, 16, 5, 32, 164, 27];
37872var lowPrefix = [33, 65, 108, 84, 1, 2, 4, 8, 168, 2, 4, 8, 17, 191, 252];
37873var zeroFill = function(count) {
37874  var a = [];
37875  while (count--) {
37876    a.push(0);
37877  }
37878  return a;
37879};
37880
37881var makeTable = function(metaTable) {
37882  return Object.keys(metaTable).reduce(function(obj, key) {
37883    obj[key] = new Uint8Array(metaTable[key].reduce(function(arr, part) {
37884      return arr.concat(part);
37885    }, []));
37886    return obj;
37887  }, {});
37888};
37889
37890// Frames-of-silence to use for filling in missing AAC frames
37891var coneOfSilence = {
37892  96000: [highPrefix, [227, 64], zeroFill(154), [56]],
37893  88200: [highPrefix, [231], zeroFill(170), [56]],
37894  64000: [highPrefix, [248, 192], zeroFill(240), [56]],
37895  48000: [highPrefix, [255, 192], zeroFill(268), [55, 148, 128], zeroFill(54), [112]],
37896  44100: [highPrefix, [255, 192], zeroFill(268), [55, 163, 128], zeroFill(84), [112]],
37897  32000: [highPrefix, [255, 192], zeroFill(268), [55, 234], zeroFill(226), [112]],
37898  24000: [highPrefix, [255, 192], zeroFill(268), [55, 255, 128], zeroFill(268), [111, 112], zeroFill(126), [224]],
37899  16000: [highPrefix, [255, 192], zeroFill(268), [55, 255, 128], zeroFill(268), [111, 255], zeroFill(269), [223, 108], zeroFill(195), [1, 192]],
37900  12000: [lowPrefix, zeroFill(268), [3, 127, 248], zeroFill(268), [6, 255, 240], zeroFill(268), [13, 255, 224], zeroFill(268), [27, 253, 128], zeroFill(259), [56]],
37901  11025: [lowPrefix, zeroFill(268), [3, 127, 248], zeroFill(268), [6, 255, 240], zeroFill(268), [13, 255, 224], zeroFill(268), [27, 255, 192], zeroFill(268), [55, 175, 128], zeroFill(108), [112]],
37902  8000: [lowPrefix, zeroFill(268), [3, 121, 16], zeroFill(47), [7]]
37903};
37904
37905module.exports = makeTable(coneOfSilence);
37906
37907},{}],43:[function(require,module,exports){
37908'use strict';
37909
37910var Stream = require('../utils/stream.js');
37911
37912/**
37913 * The final stage of the transmuxer that emits the flv tags
37914 * for audio, video, and metadata. Also tranlates in time and
37915 * outputs caption data and id3 cues.
37916 */
37917var CoalesceStream = function(options) {
37918  // Number of Tracks per output segment
37919  // If greater than 1, we combine multiple
37920  // tracks into a single segment
37921  this.numberOfTracks = 0;
37922  this.metadataStream = options.metadataStream;
37923
37924  this.videoTags = [];
37925  this.audioTags = [];
37926  this.videoTrack = null;
37927  this.audioTrack = null;
37928  this.pendingCaptions = [];
37929  this.pendingMetadata = [];
37930  this.pendingTracks = 0;
37931  this.processedTracks = 0;
37932
37933  CoalesceStream.prototype.init.call(this);
37934
37935  // Take output from multiple
37936  this.push = function(output) {
37937    // buffer incoming captions until the associated video segment
37938    // finishes
37939    if (output.text) {
37940      return this.pendingCaptions.push(output);
37941    }
37942    // buffer incoming id3 tags until the final flush
37943    if (output.frames) {
37944      return this.pendingMetadata.push(output);
37945    }
37946
37947    if (output.track.type === 'video') {
37948      this.videoTrack = output.track;
37949      this.videoTags = output.tags;
37950      this.pendingTracks++;
37951    }
37952    if (output.track.type === 'audio') {
37953      this.audioTrack = output.track;
37954      this.audioTags = output.tags;
37955      this.pendingTracks++;
37956    }
37957  };
37958};
37959
37960CoalesceStream.prototype = new Stream();
37961CoalesceStream.prototype.flush = function(flushSource) {
37962  var
37963    id3,
37964    caption,
37965    i,
37966    timelineStartPts,
37967    event = {
37968      tags: {},
37969      captions: [],
37970      captionStreams: {},
37971      metadata: []
37972    };
37973
37974  if (this.pendingTracks < this.numberOfTracks) {
37975    if (flushSource !== 'VideoSegmentStream' &&
37976        flushSource !== 'AudioSegmentStream') {
37977      // Return because we haven't received a flush from a data-generating
37978      // portion of the segment (meaning that we have only recieved meta-data
37979      // or captions.)
37980      return;
37981    } else if (this.pendingTracks === 0) {
37982      // In the case where we receive a flush without any data having been
37983      // received we consider it an emitted track for the purposes of coalescing
37984      // `done` events.
37985      // We do this for the case where there is an audio and video track in the
37986      // segment but no audio data. (seen in several playlists with alternate
37987      // audio tracks and no audio present in the main TS segments.)
37988      this.processedTracks++;
37989
37990      if (this.processedTracks < this.numberOfTracks) {
37991        return;
37992      }
37993    }
37994  }
37995
37996  this.processedTracks += this.pendingTracks;
37997  this.pendingTracks = 0;
37998
37999  if (this.processedTracks < this.numberOfTracks) {
38000    return;
38001  }
38002
38003  if (this.videoTrack) {
38004    timelineStartPts = this.videoTrack.timelineStartInfo.pts;
38005  } else if (this.audioTrack) {
38006    timelineStartPts = this.audioTrack.timelineStartInfo.pts;
38007  }
38008
38009  event.tags.videoTags = this.videoTags;
38010  event.tags.audioTags = this.audioTags;
38011
38012  // Translate caption PTS times into second offsets into the
38013  // video timeline for the segment, and add track info
38014  for (i = 0; i < this.pendingCaptions.length; i++) {
38015    caption = this.pendingCaptions[i];
38016    caption.startTime = caption.startPts - timelineStartPts;
38017    caption.startTime /= 90e3;
38018    caption.endTime = caption.endPts - timelineStartPts;
38019    caption.endTime /= 90e3;
38020    event.captionStreams[caption.stream] = true;
38021    event.captions.push(caption);
38022  }
38023
38024  // Translate ID3 frame PTS times into second offsets into the
38025  // video timeline for the segment
38026  for (i = 0; i < this.pendingMetadata.length; i++) {
38027    id3 = this.pendingMetadata[i];
38028    id3.cueTime = id3.pts - timelineStartPts;
38029    id3.cueTime /= 90e3;
38030    event.metadata.push(id3);
38031  }
38032  // We add this to every single emitted segment even though we only need
38033  // it for the first
38034  event.metadata.dispatchType = this.metadataStream.dispatchType;
38035
38036  // Reset stream state
38037  this.videoTrack = null;
38038  this.audioTrack = null;
38039  this.videoTags = [];
38040  this.audioTags = [];
38041  this.pendingCaptions.length = 0;
38042  this.pendingMetadata.length = 0;
38043  this.pendingTracks = 0;
38044  this.processedTracks = 0;
38045
38046  // Emit the final segment
38047  this.trigger('data', event);
38048
38049  this.trigger('done');
38050};
38051
38052module.exports = CoalesceStream;
38053
38054},{"../utils/stream.js":62}],44:[function(require,module,exports){
38055'use strict';
38056
38057var FlvTag = require('./flv-tag.js');
38058
38059// For information on the FLV format, see
38060// http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf.
38061// Technically, this function returns the header and a metadata FLV tag
38062// if duration is greater than zero
38063// duration in seconds
38064// @return {object} the bytes of the FLV header as a Uint8Array
38065var getFlvHeader = function(duration, audio, video) { // :ByteArray {
38066  var
38067    headBytes = new Uint8Array(3 + 1 + 1 + 4),
38068    head = new DataView(headBytes.buffer),
38069    metadata,
38070    result,
38071    metadataLength;
38072
38073  // default arguments
38074  duration = duration || 0;
38075  audio = audio === undefined ? true : audio;
38076  video = video === undefined ? true : video;
38077
38078  // signature
38079  head.setUint8(0, 0x46); // 'F'
38080  head.setUint8(1, 0x4c); // 'L'
38081  head.setUint8(2, 0x56); // 'V'
38082
38083  // version
38084  head.setUint8(3, 0x01);
38085
38086  // flags
38087  head.setUint8(4, (audio ? 0x04 : 0x00) | (video ? 0x01 : 0x00));
38088
38089  // data offset, should be 9 for FLV v1
38090  head.setUint32(5, headBytes.byteLength);
38091
38092  // init the first FLV tag
38093  if (duration <= 0) {
38094    // no duration available so just write the first field of the first
38095    // FLV tag
38096    result = new Uint8Array(headBytes.byteLength + 4);
38097    result.set(headBytes);
38098    result.set([0, 0, 0, 0], headBytes.byteLength);
38099    return result;
38100  }
38101
38102  // write out the duration metadata tag
38103  metadata = new FlvTag(FlvTag.METADATA_TAG);
38104  metadata.pts = metadata.dts = 0;
38105  metadata.writeMetaDataDouble('duration', duration);
38106  metadataLength = metadata.finalize().length;
38107  result = new Uint8Array(headBytes.byteLength + metadataLength);
38108  result.set(headBytes);
38109  result.set(head.byteLength, metadataLength);
38110
38111  return result;
38112};
38113
38114module.exports = getFlvHeader;
38115
38116},{"./flv-tag.js":45}],45:[function(require,module,exports){
38117/**
38118 * An object that stores the bytes of an FLV tag and methods for
38119 * querying and manipulating that data.
38120 * @see http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf
38121 */
38122'use strict';
38123
38124var FlvTag;
38125
38126// (type:uint, extraData:Boolean = false) extends ByteArray
38127FlvTag = function(type, extraData) {
38128  var
38129    // Counter if this is a metadata tag, nal start marker if this is a video
38130    // tag. unused if this is an audio tag
38131    adHoc = 0, // :uint
38132
38133    // The default size is 16kb but this is not enough to hold iframe
38134    // data and the resizing algorithm costs a bit so we create a larger
38135    // starting buffer for video tags
38136    bufferStartSize = 16384,
38137
38138    // checks whether the FLV tag has enough capacity to accept the proposed
38139    // write and re-allocates the internal buffers if necessary
38140    prepareWrite = function(flv, count) {
38141      var
38142        bytes,
38143        minLength = flv.position + count;
38144      if (minLength < flv.bytes.byteLength) {
38145        // there's enough capacity so do nothing
38146        return;
38147      }
38148
38149      // allocate a new buffer and copy over the data that will not be modified
38150      bytes = new Uint8Array(minLength * 2);
38151      bytes.set(flv.bytes.subarray(0, flv.position), 0);
38152      flv.bytes = bytes;
38153      flv.view = new DataView(flv.bytes.buffer);
38154    },
38155
38156    // commonly used metadata properties
38157    widthBytes = FlvTag.widthBytes || new Uint8Array('width'.length),
38158    heightBytes = FlvTag.heightBytes || new Uint8Array('height'.length),
38159    videocodecidBytes = FlvTag.videocodecidBytes || new Uint8Array('videocodecid'.length),
38160    i;
38161
38162  if (!FlvTag.widthBytes) {
38163    // calculating the bytes of common metadata names ahead of time makes the
38164    // corresponding writes faster because we don't have to loop over the
38165    // characters
38166    // re-test with test/perf.html if you're planning on changing this
38167    for (i = 0; i < 'width'.length; i++) {
38168      widthBytes[i] = 'width'.charCodeAt(i);
38169    }
38170    for (i = 0; i < 'height'.length; i++) {
38171      heightBytes[i] = 'height'.charCodeAt(i);
38172    }
38173    for (i = 0; i < 'videocodecid'.length; i++) {
38174      videocodecidBytes[i] = 'videocodecid'.charCodeAt(i);
38175    }
38176
38177    FlvTag.widthBytes = widthBytes;
38178    FlvTag.heightBytes = heightBytes;
38179    FlvTag.videocodecidBytes = videocodecidBytes;
38180  }
38181
38182  this.keyFrame = false; // :Boolean
38183
38184  switch (type) {
38185  case FlvTag.VIDEO_TAG:
38186    this.length = 16;
38187    // Start the buffer at 256k
38188    bufferStartSize *= 6;
38189    break;
38190  case FlvTag.AUDIO_TAG:
38191    this.length = 13;
38192    this.keyFrame = true;
38193    break;
38194  case FlvTag.METADATA_TAG:
38195    this.length = 29;
38196    this.keyFrame = true;
38197    break;
38198  default:
38199    throw new Error('Unknown FLV tag type');
38200  }
38201
38202  this.bytes = new Uint8Array(bufferStartSize);
38203  this.view = new DataView(this.bytes.buffer);
38204  this.bytes[0] = type;
38205  this.position = this.length;
38206  this.keyFrame = extraData; // Defaults to false
38207
38208  // presentation timestamp
38209  this.pts = 0;
38210  // decoder timestamp
38211  this.dts = 0;
38212
38213  // ByteArray#writeBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0)
38214  this.writeBytes = function(bytes, offset, length) {
38215    var
38216      start = offset || 0,
38217      end;
38218    length = length || bytes.byteLength;
38219    end = start + length;
38220
38221    prepareWrite(this, length);
38222    this.bytes.set(bytes.subarray(start, end), this.position);
38223
38224    this.position += length;
38225    this.length = Math.max(this.length, this.position);
38226  };
38227
38228  // ByteArray#writeByte(value:int):void
38229  this.writeByte = function(byte) {
38230    prepareWrite(this, 1);
38231    this.bytes[this.position] = byte;
38232    this.position++;
38233    this.length = Math.max(this.length, this.position);
38234  };
38235
38236  // ByteArray#writeShort(value:int):void
38237  this.writeShort = function(short) {
38238    prepareWrite(this, 2);
38239    this.view.setUint16(this.position, short);
38240    this.position += 2;
38241    this.length = Math.max(this.length, this.position);
38242  };
38243
38244  // Negative index into array
38245  // (pos:uint):int
38246  this.negIndex = function(pos) {
38247    return this.bytes[this.length - pos];
38248  };
38249
38250  // The functions below ONLY work when this[0] == VIDEO_TAG.
38251  // We are not going to check for that because we dont want the overhead
38252  // (nal:ByteArray = null):int
38253  this.nalUnitSize = function() {
38254    if (adHoc === 0) {
38255      return 0;
38256    }
38257
38258    return this.length - (adHoc + 4);
38259  };
38260
38261  this.startNalUnit = function() {
38262    // remember position and add 4 bytes
38263    if (adHoc > 0) {
38264      throw new Error('Attempted to create new NAL wihout closing the old one');
38265    }
38266
38267    // reserve 4 bytes for nal unit size
38268    adHoc = this.length;
38269    this.length += 4;
38270    this.position = this.length;
38271  };
38272
38273  // (nal:ByteArray = null):void
38274  this.endNalUnit = function(nalContainer) {
38275    var
38276      nalStart, // :uint
38277      nalLength; // :uint
38278
38279    // Rewind to the marker and write the size
38280    if (this.length === adHoc + 4) {
38281      // we started a nal unit, but didnt write one, so roll back the 4 byte size value
38282      this.length -= 4;
38283    } else if (adHoc > 0) {
38284      nalStart = adHoc + 4;
38285      nalLength = this.length - nalStart;
38286
38287      this.position = adHoc;
38288      this.view.setUint32(this.position, nalLength);
38289      this.position = this.length;
38290
38291      if (nalContainer) {
38292        // Add the tag to the NAL unit
38293        nalContainer.push(this.bytes.subarray(nalStart, nalStart + nalLength));
38294      }
38295    }
38296
38297    adHoc = 0;
38298  };
38299
38300  /**
38301   * Write out a 64-bit floating point valued metadata property. This method is
38302   * called frequently during a typical parse and needs to be fast.
38303   */
38304  // (key:String, val:Number):void
38305  this.writeMetaDataDouble = function(key, val) {
38306    var i;
38307    prepareWrite(this, 2 + key.length + 9);
38308
38309    // write size of property name
38310    this.view.setUint16(this.position, key.length);
38311    this.position += 2;
38312
38313    // this next part looks terrible but it improves parser throughput by
38314    // 10kB/s in my testing
38315
38316    // write property name
38317    if (key === 'width') {
38318      this.bytes.set(widthBytes, this.position);
38319      this.position += 5;
38320    } else if (key === 'height') {
38321      this.bytes.set(heightBytes, this.position);
38322      this.position += 6;
38323    } else if (key === 'videocodecid') {
38324      this.bytes.set(videocodecidBytes, this.position);
38325      this.position += 12;
38326    } else {
38327      for (i = 0; i < key.length; i++) {
38328        this.bytes[this.position] = key.charCodeAt(i);
38329        this.position++;
38330      }
38331    }
38332
38333    // skip null byte
38334    this.position++;
38335
38336    // write property value
38337    this.view.setFloat64(this.position, val);
38338    this.position += 8;
38339
38340    // update flv tag length
38341    this.length = Math.max(this.length, this.position);
38342    ++adHoc;
38343  };
38344
38345  // (key:String, val:Boolean):void
38346  this.writeMetaDataBoolean = function(key, val) {
38347    var i;
38348    prepareWrite(this, 2);
38349    this.view.setUint16(this.position, key.length);
38350    this.position += 2;
38351    for (i = 0; i < key.length; i++) {
38352      // if key.charCodeAt(i) >= 255, handle error
38353      prepareWrite(this, 1);
38354      this.bytes[this.position] = key.charCodeAt(i);
38355      this.position++;
38356    }
38357    prepareWrite(this, 2);
38358    this.view.setUint8(this.position, 0x01);
38359    this.position++;
38360    this.view.setUint8(this.position, val ? 0x01 : 0x00);
38361    this.position++;
38362    this.length = Math.max(this.length, this.position);
38363    ++adHoc;
38364  };
38365
38366  // ():ByteArray
38367  this.finalize = function() {
38368    var
38369      dtsDelta, // :int
38370      len; // :int
38371
38372    switch (this.bytes[0]) {
38373      // Video Data
38374    case FlvTag.VIDEO_TAG:
38375       // We only support AVC, 1 = key frame (for AVC, a seekable
38376       // frame), 2 = inter frame (for AVC, a non-seekable frame)
38377      this.bytes[11] = ((this.keyFrame || extraData) ? 0x10 : 0x20) | 0x07;
38378      this.bytes[12] = extraData ?  0x00 : 0x01;
38379
38380      dtsDelta = this.pts - this.dts;
38381      this.bytes[13] = (dtsDelta & 0x00FF0000) >>> 16;
38382      this.bytes[14] = (dtsDelta & 0x0000FF00) >>>  8;
38383      this.bytes[15] = (dtsDelta & 0x000000FF) >>>  0;
38384      break;
38385
38386    case FlvTag.AUDIO_TAG:
38387      this.bytes[11] = 0xAF; // 44 kHz, 16-bit stereo
38388      this.bytes[12] = extraData ? 0x00 : 0x01;
38389      break;
38390
38391    case FlvTag.METADATA_TAG:
38392      this.position = 11;
38393      this.view.setUint8(this.position, 0x02); // String type
38394      this.position++;
38395      this.view.setUint16(this.position, 0x0A); // 10 Bytes
38396      this.position += 2;
38397      // set "onMetaData"
38398      this.bytes.set([0x6f, 0x6e, 0x4d, 0x65,
38399                      0x74, 0x61, 0x44, 0x61,
38400                      0x74, 0x61], this.position);
38401      this.position += 10;
38402      this.bytes[this.position] = 0x08; // Array type
38403      this.position++;
38404      this.view.setUint32(this.position, adHoc);
38405      this.position = this.length;
38406      this.bytes.set([0, 0, 9], this.position);
38407      this.position += 3; // End Data Tag
38408      this.length = this.position;
38409      break;
38410    }
38411
38412    len = this.length - 11;
38413
38414    // write the DataSize field
38415    this.bytes[ 1] = (len & 0x00FF0000) >>> 16;
38416    this.bytes[ 2] = (len & 0x0000FF00) >>>  8;
38417    this.bytes[ 3] = (len & 0x000000FF) >>>  0;
38418    // write the Timestamp
38419    this.bytes[ 4] = (this.dts & 0x00FF0000) >>> 16;
38420    this.bytes[ 5] = (this.dts & 0x0000FF00) >>>  8;
38421    this.bytes[ 6] = (this.dts & 0x000000FF) >>>  0;
38422    this.bytes[ 7] = (this.dts & 0xFF000000) >>> 24;
38423    // write the StreamID
38424    this.bytes[ 8] = 0;
38425    this.bytes[ 9] = 0;
38426    this.bytes[10] = 0;
38427
38428    // Sometimes we're at the end of the view and have one slot to write a
38429    // uint32, so, prepareWrite of count 4, since, view is uint8
38430    prepareWrite(this, 4);
38431    this.view.setUint32(this.length, this.length);
38432    this.length += 4;
38433    this.position += 4;
38434
38435    // trim down the byte buffer to what is actually being used
38436    this.bytes = this.bytes.subarray(0, this.length);
38437    this.frameTime = FlvTag.frameTime(this.bytes);
38438    // if bytes.bytelength isn't equal to this.length, handle error
38439    return this;
38440  };
38441};
38442
38443FlvTag.AUDIO_TAG = 0x08; // == 8, :uint
38444FlvTag.VIDEO_TAG = 0x09; // == 9, :uint
38445FlvTag.METADATA_TAG = 0x12; // == 18, :uint
38446
38447// (tag:ByteArray):Boolean {
38448FlvTag.isAudioFrame = function(tag) {
38449  return FlvTag.AUDIO_TAG === tag[0];
38450};
38451
38452// (tag:ByteArray):Boolean {
38453FlvTag.isVideoFrame = function(tag) {
38454  return FlvTag.VIDEO_TAG === tag[0];
38455};
38456
38457// (tag:ByteArray):Boolean {
38458FlvTag.isMetaData = function(tag) {
38459  return FlvTag.METADATA_TAG === tag[0];
38460};
38461
38462// (tag:ByteArray):Boolean {
38463FlvTag.isKeyFrame = function(tag) {
38464  if (FlvTag.isVideoFrame(tag)) {
38465    return tag[11] === 0x17;
38466  }
38467
38468  if (FlvTag.isAudioFrame(tag)) {
38469    return true;
38470  }
38471
38472  if (FlvTag.isMetaData(tag)) {
38473    return true;
38474  }
38475
38476  return false;
38477};
38478
38479// (tag:ByteArray):uint {
38480FlvTag.frameTime = function(tag) {
38481  var pts = tag[ 4] << 16; // :uint
38482  pts |= tag[ 5] <<  8;
38483  pts |= tag[ 6] <<  0;
38484  pts |= tag[ 7] << 24;
38485  return pts;
38486};
38487
38488module.exports = FlvTag;
38489
38490},{}],46:[function(require,module,exports){
38491module.exports = {
38492  tag: require('./flv-tag'),
38493  Transmuxer: require('./transmuxer'),
38494  getFlvHeader: require('./flv-header')
38495};
38496
38497},{"./flv-header":44,"./flv-tag":45,"./transmuxer":48}],47:[function(require,module,exports){
38498'use strict';
38499
38500var TagList = function() {
38501  var self = this;
38502
38503  this.list = [];
38504
38505  this.push = function(tag) {
38506    this.list.push({
38507      bytes: tag.bytes,
38508      dts: tag.dts,
38509      pts: tag.pts,
38510      keyFrame: tag.keyFrame,
38511      metaDataTag: tag.metaDataTag
38512    });
38513  };
38514
38515  Object.defineProperty(this, 'length', {
38516    get: function() {
38517      return self.list.length;
38518    }
38519  });
38520};
38521
38522module.exports = TagList;
38523
38524},{}],48:[function(require,module,exports){
38525'use strict';
38526
38527var Stream = require('../utils/stream.js');
38528var FlvTag = require('./flv-tag.js');
38529var m2ts = require('../m2ts/m2ts.js');
38530var AdtsStream = require('../codecs/adts.js');
38531var H264Stream = require('../codecs/h264').H264Stream;
38532var CoalesceStream = require('./coalesce-stream.js');
38533var TagList = require('./tag-list.js');
38534
38535var
38536  Transmuxer,
38537  VideoSegmentStream,
38538  AudioSegmentStream,
38539  collectTimelineInfo,
38540  metaDataTag,
38541  extraDataTag;
38542
38543/**
38544 * Store information about the start and end of the tracka and the
38545 * duration for each frame/sample we process in order to calculate
38546 * the baseMediaDecodeTime
38547 */
38548collectTimelineInfo = function(track, data) {
38549  if (typeof data.pts === 'number') {
38550    if (track.timelineStartInfo.pts === undefined) {
38551      track.timelineStartInfo.pts = data.pts;
38552    } else {
38553      track.timelineStartInfo.pts =
38554        Math.min(track.timelineStartInfo.pts, data.pts);
38555    }
38556  }
38557
38558  if (typeof data.dts === 'number') {
38559    if (track.timelineStartInfo.dts === undefined) {
38560      track.timelineStartInfo.dts = data.dts;
38561    } else {
38562      track.timelineStartInfo.dts =
38563        Math.min(track.timelineStartInfo.dts, data.dts);
38564    }
38565  }
38566};
38567
38568metaDataTag = function(track, pts) {
38569  var
38570    tag = new FlvTag(FlvTag.METADATA_TAG); // :FlvTag
38571
38572  tag.dts = pts;
38573  tag.pts = pts;
38574
38575  tag.writeMetaDataDouble('videocodecid', 7);
38576  tag.writeMetaDataDouble('width', track.width);
38577  tag.writeMetaDataDouble('height', track.height);
38578
38579  return tag;
38580};
38581
38582extraDataTag = function(track, pts) {
38583  var
38584    i,
38585    tag = new FlvTag(FlvTag.VIDEO_TAG, true);
38586
38587  tag.dts = pts;
38588  tag.pts = pts;
38589
38590  tag.writeByte(0x01);// version
38591  tag.writeByte(track.profileIdc);// profile
38592  tag.writeByte(track.profileCompatibility);// compatibility
38593  tag.writeByte(track.levelIdc);// level
38594  tag.writeByte(0xFC | 0x03); // reserved (6 bits), NULA length size - 1 (2 bits)
38595  tag.writeByte(0xE0 | 0x01); // reserved (3 bits), num of SPS (5 bits)
38596  tag.writeShort(track.sps[0].length); // data of SPS
38597  tag.writeBytes(track.sps[0]); // SPS
38598
38599  tag.writeByte(track.pps.length); // num of PPS (will there ever be more that 1 PPS?)
38600  for (i = 0; i < track.pps.length; ++i) {
38601    tag.writeShort(track.pps[i].length); // 2 bytes for length of PPS
38602    tag.writeBytes(track.pps[i]); // data of PPS
38603  }
38604
38605  return tag;
38606};
38607
38608/**
38609 * Constructs a single-track, media segment from AAC data
38610 * events. The output of this stream can be fed to flash.
38611 */
38612AudioSegmentStream = function(track) {
38613  var
38614    adtsFrames = [],
38615    videoKeyFrames = [],
38616    oldExtraData;
38617
38618  AudioSegmentStream.prototype.init.call(this);
38619
38620  this.push = function(data) {
38621    collectTimelineInfo(track, data);
38622
38623    if (track) {
38624      track.audioobjecttype = data.audioobjecttype;
38625      track.channelcount = data.channelcount;
38626      track.samplerate = data.samplerate;
38627      track.samplingfrequencyindex = data.samplingfrequencyindex;
38628      track.samplesize = data.samplesize;
38629      track.extraData = (track.audioobjecttype << 11) |
38630                        (track.samplingfrequencyindex << 7) |
38631                        (track.channelcount << 3);
38632    }
38633
38634    data.pts = Math.round(data.pts / 90);
38635    data.dts = Math.round(data.dts / 90);
38636
38637    // buffer audio data until end() is called
38638    adtsFrames.push(data);
38639  };
38640
38641  this.flush = function() {
38642    var currentFrame, adtsFrame, lastMetaPts, tags = new TagList();
38643    // return early if no audio data has been observed
38644    if (adtsFrames.length === 0) {
38645      this.trigger('done', 'AudioSegmentStream');
38646      return;
38647    }
38648
38649    lastMetaPts = -Infinity;
38650
38651    while (adtsFrames.length) {
38652      currentFrame = adtsFrames.shift();
38653
38654      // write out a metadata frame at every video key frame
38655      if (videoKeyFrames.length && currentFrame.pts >= videoKeyFrames[0]) {
38656        lastMetaPts = videoKeyFrames.shift();
38657        this.writeMetaDataTags(tags, lastMetaPts);
38658      }
38659
38660      // also write out metadata tags every 1 second so that the decoder
38661      // is re-initialized quickly after seeking into a different
38662      // audio configuration.
38663      if (track.extraData !== oldExtraData || currentFrame.pts - lastMetaPts >= 1000) {
38664        this.writeMetaDataTags(tags, currentFrame.pts);
38665        oldExtraData = track.extraData;
38666        lastMetaPts = currentFrame.pts;
38667      }
38668
38669      adtsFrame = new FlvTag(FlvTag.AUDIO_TAG);
38670      adtsFrame.pts = currentFrame.pts;
38671      adtsFrame.dts = currentFrame.dts;
38672
38673      adtsFrame.writeBytes(currentFrame.data);
38674
38675      tags.push(adtsFrame.finalize());
38676    }
38677
38678    videoKeyFrames.length = 0;
38679    oldExtraData = null;
38680    this.trigger('data', {track: track, tags: tags.list});
38681
38682    this.trigger('done', 'AudioSegmentStream');
38683  };
38684
38685  this.writeMetaDataTags = function(tags, pts) {
38686    var adtsFrame;
38687
38688    adtsFrame = new FlvTag(FlvTag.METADATA_TAG);
38689    // For audio, DTS is always the same as PTS. We want to set the DTS
38690    // however so we can compare with video DTS to determine approximate
38691    // packet order
38692    adtsFrame.pts = pts;
38693    adtsFrame.dts = pts;
38694
38695    // AAC is always 10
38696    adtsFrame.writeMetaDataDouble('audiocodecid', 10);
38697    adtsFrame.writeMetaDataBoolean('stereo', track.channelcount === 2);
38698    adtsFrame.writeMetaDataDouble('audiosamplerate', track.samplerate);
38699    // Is AAC always 16 bit?
38700    adtsFrame.writeMetaDataDouble('audiosamplesize', 16);
38701
38702    tags.push(adtsFrame.finalize());
38703
38704    adtsFrame = new FlvTag(FlvTag.AUDIO_TAG, true);
38705    // For audio, DTS is always the same as PTS. We want to set the DTS
38706    // however so we can compare with video DTS to determine approximate
38707    // packet order
38708    adtsFrame.pts = pts;
38709    adtsFrame.dts = pts;
38710
38711    adtsFrame.view.setUint16(adtsFrame.position, track.extraData);
38712    adtsFrame.position += 2;
38713    adtsFrame.length = Math.max(adtsFrame.length, adtsFrame.position);
38714
38715    tags.push(adtsFrame.finalize());
38716  };
38717
38718  this.onVideoKeyFrame = function(pts) {
38719    videoKeyFrames.push(pts);
38720  };
38721};
38722AudioSegmentStream.prototype = new Stream();
38723
38724/**
38725 * Store FlvTags for the h264 stream
38726 * @param track {object} track metadata configuration
38727 */
38728VideoSegmentStream = function(track) {
38729  var
38730    nalUnits = [],
38731    config,
38732    h264Frame;
38733  VideoSegmentStream.prototype.init.call(this);
38734
38735  this.finishFrame = function(tags, frame) {
38736    if (!frame) {
38737      return;
38738    }
38739    // Check if keyframe and the length of tags.
38740    // This makes sure we write metadata on the first frame of a segment.
38741    if (config && track && track.newMetadata &&
38742        (frame.keyFrame || tags.length === 0)) {
38743      // Push extra data on every IDR frame in case we did a stream change + seek
38744      var metaTag = metaDataTag(config, frame.dts).finalize();
38745      var extraTag = extraDataTag(track, frame.dts).finalize();
38746
38747      metaTag.metaDataTag = extraTag.metaDataTag = true;
38748
38749      tags.push(metaTag);
38750      tags.push(extraTag);
38751      track.newMetadata = false;
38752
38753      this.trigger('keyframe', frame.dts);
38754    }
38755
38756    frame.endNalUnit();
38757    tags.push(frame.finalize());
38758    h264Frame = null;
38759  };
38760
38761  this.push = function(data) {
38762    collectTimelineInfo(track, data);
38763
38764    data.pts = Math.round(data.pts / 90);
38765    data.dts = Math.round(data.dts / 90);
38766
38767    // buffer video until flush() is called
38768    nalUnits.push(data);
38769  };
38770
38771  this.flush = function() {
38772    var
38773      currentNal,
38774      tags = new TagList();
38775
38776    // Throw away nalUnits at the start of the byte stream until we find
38777    // the first AUD
38778    while (nalUnits.length) {
38779      if (nalUnits[0].nalUnitType === 'access_unit_delimiter_rbsp') {
38780        break;
38781      }
38782      nalUnits.shift();
38783    }
38784
38785    // return early if no video data has been observed
38786    if (nalUnits.length === 0) {
38787      this.trigger('done', 'VideoSegmentStream');
38788      return;
38789    }
38790
38791    while (nalUnits.length) {
38792      currentNal = nalUnits.shift();
38793
38794      // record the track config
38795      if (currentNal.nalUnitType === 'seq_parameter_set_rbsp') {
38796        track.newMetadata = true;
38797        config = currentNal.config;
38798        track.width = config.width;
38799        track.height = config.height;
38800        track.sps = [currentNal.data];
38801        track.profileIdc = config.profileIdc;
38802        track.levelIdc = config.levelIdc;
38803        track.profileCompatibility = config.profileCompatibility;
38804        h264Frame.endNalUnit();
38805      } else if (currentNal.nalUnitType === 'pic_parameter_set_rbsp') {
38806        track.newMetadata = true;
38807        track.pps = [currentNal.data];
38808        h264Frame.endNalUnit();
38809      } else if (currentNal.nalUnitType === 'access_unit_delimiter_rbsp') {
38810        if (h264Frame) {
38811          this.finishFrame(tags, h264Frame);
38812        }
38813        h264Frame = new FlvTag(FlvTag.VIDEO_TAG);
38814        h264Frame.pts = currentNal.pts;
38815        h264Frame.dts = currentNal.dts;
38816      } else {
38817        if (currentNal.nalUnitType === 'slice_layer_without_partitioning_rbsp_idr') {
38818          // the current sample is a key frame
38819          h264Frame.keyFrame = true;
38820        }
38821        h264Frame.endNalUnit();
38822      }
38823      h264Frame.startNalUnit();
38824      h264Frame.writeBytes(currentNal.data);
38825    }
38826    if (h264Frame) {
38827      this.finishFrame(tags, h264Frame);
38828    }
38829
38830    this.trigger('data', {track: track, tags: tags.list});
38831
38832    // Continue with the flush process now
38833    this.trigger('done', 'VideoSegmentStream');
38834  };
38835};
38836
38837VideoSegmentStream.prototype = new Stream();
38838
38839/**
38840 * An object that incrementally transmuxes MPEG2 Trasport Stream
38841 * chunks into an FLV.
38842 */
38843Transmuxer = function(options) {
38844  var
38845    self = this,
38846
38847    packetStream, parseStream, elementaryStream,
38848    videoTimestampRolloverStream, audioTimestampRolloverStream,
38849    timedMetadataTimestampRolloverStream,
38850    adtsStream, h264Stream,
38851    videoSegmentStream, audioSegmentStream, captionStream,
38852    coalesceStream;
38853
38854  Transmuxer.prototype.init.call(this);
38855
38856  options = options || {};
38857
38858  // expose the metadata stream
38859  this.metadataStream = new m2ts.MetadataStream();
38860
38861  options.metadataStream = this.metadataStream;
38862
38863  // set up the parsing pipeline
38864  packetStream = new m2ts.TransportPacketStream();
38865  parseStream = new m2ts.TransportParseStream();
38866  elementaryStream = new m2ts.ElementaryStream();
38867  videoTimestampRolloverStream = new m2ts.TimestampRolloverStream('video');
38868  audioTimestampRolloverStream = new m2ts.TimestampRolloverStream('audio');
38869  timedMetadataTimestampRolloverStream = new m2ts.TimestampRolloverStream('timed-metadata');
38870
38871  adtsStream = new AdtsStream();
38872  h264Stream = new H264Stream();
38873  coalesceStream = new CoalesceStream(options);
38874
38875  // disassemble MPEG2-TS packets into elementary streams
38876  packetStream
38877    .pipe(parseStream)
38878    .pipe(elementaryStream);
38879
38880  // !!THIS ORDER IS IMPORTANT!!
38881  // demux the streams
38882  elementaryStream
38883    .pipe(videoTimestampRolloverStream)
38884    .pipe(h264Stream);
38885  elementaryStream
38886    .pipe(audioTimestampRolloverStream)
38887    .pipe(adtsStream);
38888
38889  elementaryStream
38890    .pipe(timedMetadataTimestampRolloverStream)
38891    .pipe(this.metadataStream)
38892    .pipe(coalesceStream);
38893  // if CEA-708 parsing is available, hook up a caption stream
38894  captionStream = new m2ts.CaptionStream();
38895  h264Stream.pipe(captionStream)
38896    .pipe(coalesceStream);
38897
38898  // hook up the segment streams once track metadata is delivered
38899  elementaryStream.on('data', function(data) {
38900    var i, videoTrack, audioTrack;
38901
38902    if (data.type === 'metadata') {
38903      i = data.tracks.length;
38904
38905      // scan the tracks listed in the metadata
38906      while (i--) {
38907        if (data.tracks[i].type === 'video') {
38908          videoTrack = data.tracks[i];
38909        } else if (data.tracks[i].type === 'audio') {
38910          audioTrack = data.tracks[i];
38911        }
38912      }
38913
38914      // hook up the video segment stream to the first track with h264 data
38915      if (videoTrack && !videoSegmentStream) {
38916        coalesceStream.numberOfTracks++;
38917        videoSegmentStream = new VideoSegmentStream(videoTrack);
38918
38919        // Set up the final part of the video pipeline
38920        h264Stream
38921          .pipe(videoSegmentStream)
38922          .pipe(coalesceStream);
38923      }
38924
38925      if (audioTrack && !audioSegmentStream) {
38926        // hook up the audio segment stream to the first track with aac data
38927        coalesceStream.numberOfTracks++;
38928        audioSegmentStream = new AudioSegmentStream(audioTrack);
38929
38930        // Set up the final part of the audio pipeline
38931        adtsStream
38932          .pipe(audioSegmentStream)
38933          .pipe(coalesceStream);
38934
38935        if (videoSegmentStream) {
38936          videoSegmentStream.on('keyframe', audioSegmentStream.onVideoKeyFrame);
38937        }
38938      }
38939    }
38940  });
38941
38942  // feed incoming data to the front of the parsing pipeline
38943  this.push = function(data) {
38944    packetStream.push(data);
38945  };
38946
38947  // flush any buffered data
38948  this.flush = function() {
38949    // Start at the top of the pipeline and flush all pending work
38950    packetStream.flush();
38951  };
38952
38953  // Caption data has to be reset when seeking outside buffered range
38954  this.resetCaptions = function() {
38955    captionStream.reset();
38956  };
38957
38958  // Re-emit any data coming from the coalesce stream to the outside world
38959  coalesceStream.on('data', function(event) {
38960    self.trigger('data', event);
38961  });
38962
38963  // Let the consumer know we have finished flushing the entire pipeline
38964  coalesceStream.on('done', function() {
38965    self.trigger('done');
38966  });
38967};
38968Transmuxer.prototype = new Stream();
38969
38970// forward compatibility
38971module.exports = Transmuxer;
38972
38973},{"../codecs/adts.js":40,"../codecs/h264":41,"../m2ts/m2ts.js":50,"../utils/stream.js":62,"./coalesce-stream.js":43,"./flv-tag.js":45,"./tag-list.js":47}],49:[function(require,module,exports){
38974/**
38975 * mux.js
38976 *
38977 * Copyright (c) 2015 Brightcove
38978 * All rights reserved.
38979 *
38980 * Reads in-band caption information from a video elementary
38981 * stream. Captions must follow the CEA-708 standard for injection
38982 * into an MPEG-2 transport streams.
38983 * @see https://en.wikipedia.org/wiki/CEA-708
38984 * @see https://www.gpo.gov/fdsys/pkg/CFR-2007-title47-vol1/pdf/CFR-2007-title47-vol1-sec15-119.pdf
38985 */
38986
38987'use strict';
38988
38989// -----------------
38990// Link To Transport
38991// -----------------
38992
38993// Supplemental enhancement information (SEI) NAL units have a
38994// payload type field to indicate how they are to be
38995// interpreted. CEAS-708 caption content is always transmitted with
38996// payload type 0x04.
38997var USER_DATA_REGISTERED_ITU_T_T35 = 4,
38998    RBSP_TRAILING_BITS = 128,
38999    Stream = require('../utils/stream');
39000
39001/**
39002  * Parse a supplemental enhancement information (SEI) NAL unit.
39003  * Stops parsing once a message of type ITU T T35 has been found.
39004  *
39005  * @param bytes {Uint8Array} the bytes of a SEI NAL unit
39006  * @return {object} the parsed SEI payload
39007  * @see Rec. ITU-T H.264, 7.3.2.3.1
39008  */
39009var parseSei = function(bytes) {
39010  var
39011    i = 0,
39012    result = {
39013      payloadType: -1,
39014      payloadSize: 0
39015    },
39016    payloadType = 0,
39017    payloadSize = 0;
39018
39019  // go through the sei_rbsp parsing each each individual sei_message
39020  while (i < bytes.byteLength) {
39021    // stop once we have hit the end of the sei_rbsp
39022    if (bytes[i] === RBSP_TRAILING_BITS) {
39023      break;
39024    }
39025
39026    // Parse payload type
39027    while (bytes[i] === 0xFF) {
39028      payloadType += 255;
39029      i++;
39030    }
39031    payloadType += bytes[i++];
39032
39033    // Parse payload size
39034    while (bytes[i] === 0xFF) {
39035      payloadSize += 255;
39036      i++;
39037    }
39038    payloadSize += bytes[i++];
39039
39040    // this sei_message is a 608/708 caption so save it and break
39041    // there can only ever be one caption message in a frame's sei
39042    if (!result.payload && payloadType === USER_DATA_REGISTERED_ITU_T_T35) {
39043      result.payloadType = payloadType;
39044      result.payloadSize = payloadSize;
39045      result.payload = bytes.subarray(i, i + payloadSize);
39046      break;
39047    }
39048
39049    // skip the payload and parse the next message
39050    i += payloadSize;
39051    payloadType = 0;
39052    payloadSize = 0;
39053  }
39054
39055  return result;
39056};
39057
39058// see ANSI/SCTE 128-1 (2013), section 8.1
39059var parseUserData = function(sei) {
39060  // itu_t_t35_contry_code must be 181 (United States) for
39061  // captions
39062  if (sei.payload[0] !== 181) {
39063    return null;
39064  }
39065
39066  // itu_t_t35_provider_code should be 49 (ATSC) for captions
39067  if (((sei.payload[1] << 8) | sei.payload[2]) !== 49) {
39068    return null;
39069  }
39070
39071  // the user_identifier should be "GA94" to indicate ATSC1 data
39072  if (String.fromCharCode(sei.payload[3],
39073                          sei.payload[4],
39074                          sei.payload[5],
39075                          sei.payload[6]) !== 'GA94') {
39076    return null;
39077  }
39078
39079  // finally, user_data_type_code should be 0x03 for caption data
39080  if (sei.payload[7] !== 0x03) {
39081    return null;
39082  }
39083
39084  // return the user_data_type_structure and strip the trailing
39085  // marker bits
39086  return sei.payload.subarray(8, sei.payload.length - 1);
39087};
39088
39089// see CEA-708-D, section 4.4
39090var parseCaptionPackets = function(pts, userData) {
39091  var results = [], i, count, offset, data;
39092
39093  // if this is just filler, return immediately
39094  if (!(userData[0] & 0x40)) {
39095    return results;
39096  }
39097
39098  // parse out the cc_data_1 and cc_data_2 fields
39099  count = userData[0] & 0x1f;
39100  for (i = 0; i < count; i++) {
39101    offset = i * 3;
39102    data = {
39103      type: userData[offset + 2] & 0x03,
39104      pts: pts
39105    };
39106
39107    // capture cc data when cc_valid is 1
39108    if (userData[offset + 2] & 0x04) {
39109      data.ccData = (userData[offset + 3] << 8) | userData[offset + 4];
39110      results.push(data);
39111    }
39112  }
39113  return results;
39114};
39115
39116var 
39116packetDropper = {
39117  push: function() {}
vendor: 3,474 bytes, lines 39117-39232
39117
39118};
39119
39120var CaptionStream = function() {
39121
39122  CaptionStream.prototype.init.call(this);
39123
39124  this.captionPackets_ = [];
39125
39126  this.ccStreams_ = [
39127    new Cea608Stream(0, 0), // eslint-disable-line no-use-before-define
39128    new Cea608Stream(0, 1), // eslint-disable-line no-use-before-define
39129    new Cea608Stream(1, 0), // eslint-disable-line no-use-before-define
39130    new Cea608Stream(1, 1) // eslint-disable-line no-use-before-define
39131  ];
39132
39133  this.reset();
39134
39135  // forward data and done events from CCs to this CaptionStream
39136  this.ccStreams_.forEach(function(cc) {
39137    cc.on('data', this.trigger.bind(this, 'data'));
39138    cc.on('done', this.trigger.bind(this, 'done'));
39139  }, this);
39140
39141};
39142
39143CaptionStream.prototype = new Stream();
39144CaptionStream.prototype.push = function(event) {
39145  var sei, userData;
39146
39147  // only examine SEI NALs
39148  if (event.nalUnitType !== 'sei_rbsp') {
39149    return;
39150  }
39151
39152  // parse the sei
39153  sei = parseSei(event.escapedRBSP);
39154
39155  // ignore everything but user_data_registered_itu_t_t35
39156  if (sei.payloadType !== USER_DATA_REGISTERED_ITU_T_T35) {
39157    return;
39158  }
39159
39160  // parse out the user data payload
39161  userData = parseUserData(sei);
39162
39163  // ignore unrecognized userData
39164  if (!userData) {
39165    return;
39166  }
39167
39168  // Sometimes, the same segment # will be downloaded twice. To stop the
39169  // caption data from being processed twice, we track the latest dts we've
39170  // received and ignore everything with a dts before that. However, since
39171  // data for a specific dts can be split across 2 packets on either side of
39172  // a segment boundary, we need to make sure we *don't* ignore the second
39173  // dts packet we receive that has dts === this.latestDts_. And thus, the
39174  // ignoreNextEqualDts_ flag was born.
39175  if (event.dts < this.latestDts_) {
39176    // We've started getting older data, so set the flag.
39177    this.ignoreNextEqualDts_ = true;
39178    return;
39179  } else if ((event.dts === this.latestDts_) && (this.ignoreNextEqualDts_)) {
39180    // We've received the last duplicate packet, time to start processing again
39181    this.ignoreNextEqualDts_ = false;
39182    return;
39183  }
39184
39185  // parse out CC data packets and save them for later
39186  this.captionPackets_ = this.captionPackets_.concat(parseCaptionPackets(event.pts, userData));
39187  this.latestDts_ = event.dts;
39188};
39189
39190CaptionStream.prototype.flush = function() {
39191  // make sure we actually parsed captions before proceeding
39192  if (!this.captionPackets_.length) {
39193    this.ccStreams_.forEach(function(cc) {
39194      cc.flush();
39195    }, this);
39196    return;
39197  }
39198
39199  // In Chrome, the Array#sort function is not stable so add a
39200  // presortIndex that we can use to ensure we get a stable-sort
39201  this.captionPackets_.forEach(function(elem, idx) {
39202    elem.presortIndex = idx;
39203  });
39204
39205  // sort caption byte-pairs based on their PTS values
39206  this.captionPackets_.sort(function(a, b) {
39207    if (a.pts === b.pts) {
39208      return a.presortIndex - b.presortIndex;
39209    }
39210    return a.pts - b.pts;
39211  });
39212
39213  this.captionPackets_.forEach(function(packet) {
39214    if (packet.type < 2) {
39215      // Dispatch packet to the right Cea608Stream
39216      this.dispatchCea608Packet(packet);
39217    }
39218    // this is where an 'else' would go for a dispatching packets
39219    // to a theoretical Cea708Stream that handles SERVICEn data
39220  }, this);
39221
39222  this.captionPackets_.length = 0;
39223  this.ccStreams_.forEach(function(cc) {
39224    cc.flush();
39225  }, this);
39226  return;
39227};
39228
39229CaptionStream.prototype.reset = function() {
39230  this.latestDts_ = null;
39231  this.ignoreNextEqualDts_ = false;
39232  this.activeCea608Channel_ = 
39232null;
39233  // Since we don't know which channel is active until we get a control
39234  // code that sets it, we start off with CEA608 handlers that just drop
39235  // all the packets.
39236  this.activeCea608Streams_ = [
39237    packetDropper,
39238    packetDropper
39239  ];
39240  this.ccStreams_.forEach(function(ccStream) {
39241    ccStream.reset();
39242  });
39243};
39244
39245CaptionStream.prototype.dispatchCea608Packet = function(packet) {
39246  if (this.setsChannel1Active(packet) && this.activeCea608Channel_ !== 1) {
39247    this.activeCea608Channel_ = 1;
39248    this.activeCea608Streams_ = [this.ccStreams_[0], this.ccStreams_[2]]; // CC1, CC3
39249  } else if (this.setsChannel2Active(packet) && this.activeCea608Channel_ !== 2) {
39250    this.activeCea608Channel_ = 2;
39251    this.activeCea608Streams_ = [this.ccStreams_[1], this.ccStreams_[3]]; // CC2, CC4
39252  }
39253  // If we haven't set the active streams yet, this next call just returns
39254  // immediately.
39255  this.activeCea608Streams_[packet.type
vendor: 23,920 bytes, lines 39255-39999
39255].push(packet);
39256};
39257
39258CaptionStream.prototype.setsChannel1Active = function(packet) {
39259  return ((packet.ccData & 0x7800) === 0x1000);
39260};
39261CaptionStream.prototype.setsChannel2Active = function(packet) {
39262  return ((packet.ccData & 0x7800) === 0x1800);
39263};
39264
39265// ----------------------
39266// Session to Application
39267// ----------------------
39268
39269var CHARACTER_TRANSLATION = {
39270  0x2a: 0xe1,     // á
39271  0x5c: 0xe9,     // é
39272  0x5e: 0xed,     // í
39273  0x5f: 0xf3,     // ó
39274  0x60: 0xfa,     // ú
39275  0x7b: 0xe7,     // ç
39276  0x7c: 0xf7,     // ÷
39277  0x7d: 0xd1,     // Ñ
39278  0x7e: 0xf1,     // ñ
39279  0x7f: 0x2588,   // █
39280  0x0130: 0xae,   // ®
39281  0x0131: 0xb0,   // °
39282  0x0132: 0xbd,   // ½
39283  0x0133: 0xbf,   // ¿
39284  0x0134: 0x2122, // ™
39285  0x0135: 0xa2,   // ¢
39286  0x0136: 0xa3,   // £
39287  0x0137: 0x266a, // ♪
39288  0x0138: 0xe0,   // à
39289  0x0139: 0xa0,   //
39290  0x013a: 0xe8,   // è
39291  0x013b: 0xe2,   // â
39292  0x013c: 0xea,   // ê
39293  0x013d: 0xee,   // î
39294  0x013e: 0xf4,   // ô
39295  0x013f: 0xfb,   // û
39296  0x0220: 0xc1,   // Á
39297  0x0221: 0xc9,   // É
39298  0x0222: 0xd3,   // Ó
39299  0x0223: 0xda,   // Ú
39300  0x0224: 0xdc,   // Ü
39301  0x0225: 0xfc,   // ü
39302  0x0226: 0x2018, // ‘
39303  0x0227: 0xa1,   // ¡
39304  0x0228: 0x2a,   // *
39305  0x0229: 0x27,   // '
39306  0x022a: 0x2014, // —
39307  0x022b: 0xa9,   // ©
39308  0x022c: 0x2120, // ℠
39309  0x022d: 0x2022, // •
39310  0x022e: 0x201c, // “
39311  0x022f: 0x201d, // ”
39312  0x0230: 0xc0,   // À
39313  0x0231: 0xc2,   // Â
39314  0x0232: 0xc7,   // Ç
39315  0x0233: 0xc8,   // È
39316  0x0234: 0xca,   // Ê
39317  0x0235: 0xcb,   // Ë
39318  0x0236: 0xeb,   // ë
39319  0x0237: 0xce,   // Î
39320  0x0238: 0xcf,   // Ï
39321  0x0239: 0xef,   // ï
39322  0x023a: 0xd4,   // Ô
39323  0x023b: 0xd9,   // Ù
39324  0x023c: 0xf9,   // ù
39325  0x023d: 0xdb,   // Û
39326  0x023e: 0xab,   // «
39327  0x023f: 0xbb,   // »
39328  0x0320: 0xc3,   // Ã
39329  0x0321: 0xe3,   // ã
39330  0x0322: 0xcd,   // Í
39331  0x0323: 0xcc,   // Ì
39332  0x0324: 0xec,   // ì
39333  0x0325: 0xd2,   // Ò
39334  0x0326: 0xf2,   // ò
39335  0x0327: 0xd5,   // Õ
39336  0x0328: 0xf5,   // õ
39337  0x0329: 0x7b,   // {
39338  0x032a: 0x7d,   // }
39339  0x032b: 0x5c,   // \
39340  0x032c: 0x5e,   // ^
39341  0x032d: 0x5f,   // _
39342  0x032e: 0x7c,   // |
39343  0x032f: 0x7e,   // ~
39344  0x0330: 0xc4,   // Ä
39345  0x0331: 0xe4,   // ä
39346  0x0332: 0xd6,   // Ö
39347  0x0333: 0xf6,   // ö
39348  0x0334: 0xdf,   // ß
39349  0x0335: 0xa5,   // ¥
39350  0x0336: 0xa4,   // ¤
39351  0x0337: 0x2502, // │
39352  0x0338: 0xc5,   // Å
39353  0x0339: 0xe5,   // å
39354  0x033a: 0xd8,   // Ø
39355  0x033b: 0xf8,   // ø
39356  0x033c: 0x250c, // ┌
39357  0x033d: 0x2510, // ┐
39358  0x033e: 0x2514, // └
39359  0x033f: 0x2518  // ┘
39360};
39361
39362var getCharFromCode = function(code) {
39363  if (code === null) {
39364    return '';
39365  }
39366  code = CHARACTER_TRANSLATION[code] || code;
39367  return String.fromCharCode(code);
39368};
39369
39370// the index of the last row in a CEA-608 display buffer
39371var BOTTOM_ROW = 14;
39372
39373// This array is used for mapping PACs -> row #, since there's no way of
39374// getting it through bit logic.
39375var ROWS = [0x1100, 0x1120, 0x1200, 0x1220, 0x1500, 0x1520, 0x1600, 0x1620,
39376            0x1700, 0x1720, 0x1000, 0x1300, 0x1320, 0x1400, 0x1420];
39377
39378// CEA-608 captions are rendered onto a 34x15 matrix of character
39379// cells. The "bottom" row is the last element in the outer array.
39380var createDisplayBuffer = function() {
39381  var result = [], i = BOTTOM_ROW + 1;
39382  while (i--) {
39383    result.push('');
39384  }
39385  return result;
39386};
39387
39388var Cea608Stream = function(field, dataChannel) {
39389  Cea608Stream.prototype.init.call(this);
39390
39391  this.field_ = field || 0;
39392  this.dataChannel_ = dataChannel || 0;
39393
39394  this.name_ = 'CC' + (((this.field_ << 1) | this.dataChannel_) + 1);
39395
39396  this.setConstants();
39397  this.reset();
39398
39399  this.push = function(packet) {
39400    var data, swap, char0, char1, text;
39401    // remove the parity bits
39402    data = packet.ccData & 0x7f7f;
39403
39404    // ignore duplicate control codes; the spec demands they're sent twice
39405    if (data === this.lastControlCode_) {
39406      this.lastControlCode_ = null;
39407      return;
39408    }
39409
39410    // Store control codes
39411    if ((data & 0xf000) === 0x1000) {
39412      this.lastControlCode_ = data;
39413    } else if (data !== this.PADDING_) {
39414      this.lastControlCode_ = null;
39415    }
39416
39417    char0 = data >>> 8;
39418    char1 = data & 0xff;
39419
39420    if (data === this.PADDING_) {
39421      return;
39422
39423    } else if (data === this.RESUME_CAPTION_LOADING_) {
39424      this.mode_ = 'popOn';
39425
39426    } else if (data === this.END_OF_CAPTION_) {
39427      this.clearFormatting(packet.pts);
39428      // if a caption was being displayed, it's gone now
39429      this.flushDisplayed(packet.pts);
39430
39431      // flip memory
39432      swap = this.displayed_;
39433      this.displayed_ = this.nonDisplayed_;
39434      this.nonDisplayed_ = swap;
39435
39436      // start measuring the time to display the caption
39437      this.startPts_ = packet.pts;
39438
39439    } else if (data === this.ROLL_UP_2_ROWS_) {
39440      this.topRow_ = BOTTOM_ROW - 1;
39441      this.mode_ = 'rollUp';
39442    } else if (data === this.ROLL_UP_3_ROWS_) {
39443      this.topRow_ = BOTTOM_ROW - 2;
39444      this.mode_ = 'rollUp';
39445    } else if (data === this.ROLL_UP_4_ROWS_) {
39446      this.topRow_ = BOTTOM_ROW - 3;
39447      this.mode_ = 'rollUp';
39448    } else if (data === this.CARRIAGE_RETURN_) {
39449      this.clearFormatting(packet.pts);
39450      this.flushDisplayed(packet.pts);
39451      this.shiftRowsUp_();
39452      this.startPts_ = packet.pts;
39453
39454    } else if (data === this.BACKSPACE_) {
39455      if (this.mode_ === 'popOn') {
39456        this.nonDisplayed_[BOTTOM_ROW] = this.nonDisplayed_[BOTTOM_ROW].slice(0, -1);
39457      } else {
39458        this.displayed_[BOTTOM_ROW] = this.displayed_[BOTTOM_ROW].slice(0, -1);
39459      }
39460    } else if (data === this.ERASE_DISPLAYED_MEMORY_) {
39461      this.flushDisplayed(packet.pts);
39462      this.displayed_ = createDisplayBuffer();
39463    } else if (data === this.ERASE_NON_DISPLAYED_MEMORY_) {
39464      this.nonDisplayed_ = createDisplayBuffer();
39465
39466    } else if (data === this.RESUME_DIRECT_CAPTIONING_) {
39467      this.mode_ = 'paintOn';
39468
39469    // Append special characters to caption text
39470    } else if (this.isSpecialCharacter(char0, char1)) {
39471      // Bitmask char0 so that we can apply character transformations
39472      // regardless of field and data channel.
39473      // Then byte-shift to the left and OR with char1 so we can pass the
39474      // entire character code to `getCharFromCode`.
39475      char0 = (char0 & 0x03) << 8;
39476      text = getCharFromCode(char0 | char1);
39477      this[this.mode_](packet.pts, text);
39478      this.column_++;
39479
39480    // Append extended characters to caption text
39481    } else if (this.isExtCharacter(char0, char1)) {
39482      // Extended characters always follow their "non-extended" equivalents.
39483      // IE if a "è" is desired, you'll always receive "eè"; non-compliant
39484      // decoders are supposed to drop the "è", while compliant decoders
39485      // backspace the "e" and insert "è".
39486
39487      // Delete the previous character
39488      if (this.mode_ === 'popOn') {
39489        this.nonDisplayed_[this.row_] = this.nonDisplayed_[this.row_].slice(0, -1);
39490      } else {
39491        this.displayed_[BOTTOM_ROW] = this.displayed_[BOTTOM_ROW].slice(0, -1);
39492      }
39493
39494      // Bitmask char0 so that we can apply character transformations
39495      // regardless of field and data channel.
39496      // Then byte-shift to the left and OR with char1 so we can pass the
39497      // entire character code to `getCharFromCode`.
39498      char0 = (char0 & 0x03) << 8;
39499      text = getCharFromCode(char0 | char1);
39500      this[this.mode_](packet.pts, text);
39501      this.column_++;
39502
39503    // Process mid-row codes
39504    } else if (this.isMidRowCode(char0, char1)) {
39505      // Attributes are not additive, so clear all formatting
39506      this.clearFormatting(packet.pts);
39507
39508      // According to the standard, mid-row codes
39509      // should be replaced with spaces, so add one now
39510      this[this.mode_](packet.pts, ' ');
39511      this.column_++;
39512
39513      if ((char1 & 0xe) === 0xe) {
39514        this.addFormatting(packet.pts, ['i']);
39515      }
39516
39517      if ((char1 & 0x1) === 0x1) {
39518        this.addFormatting(packet.pts, ['u']);
39519      }
39520
39521    // Detect offset control codes and adjust cursor
39522    } else if (this.isOffsetControlCode(char0, char1)) {
39523      // Cursor position is set by indent PAC (see below) in 4-column
39524      // increments, with an additional offset code of 1-3 to reach any
39525      // of the 32 columns specified by CEA-608. So all we need to do
39526      // here is increment the column cursor by the given offset.
39527      this.column_ += (char1 & 0x03);
39528
39529    // Detect PACs (Preamble Address Codes)
39530    } else if (this.isPAC(char0, char1)) {
39531
39532      // There's no logic for PAC -> row mapping, so we have to just
39533      // find the row code in an array and use its index :(
39534      var row = ROWS.indexOf(data & 0x1f20);
39535
39536      if (row !== this.row_) {
39537        // formatting is only persistent for current row
39538        this.clearFormatting(packet.pts);
39539        this.row_ = row;
39540      }
39541      // All PACs can apply underline, so detect and apply
39542      // (All odd-numbered second bytes set underline)
39543      if ((char1 & 0x1) && (this.formatting_.indexOf('u') === -1)) {
39544          this.addFormatting(packet.pts, ['u']);
39545      }
39546
39547      if ((data & 0x10) === 0x10) {
39548        // We've got an indent level code. Each successive even number
39549        // increments the column cursor by 4, so we can get the desired
39550        // column position by bit-shifting to the right (to get n/2)
39551        // and multiplying by 4.
39552        this.column_ = ((data & 0xe) >> 1) * 4;
39553      }
39554
39555      if (this.isColorPAC(char1)) {
39556        // it's a color code, though we only support white, which
39557        // can be either normal or italicized. white italics can be
39558        // either 0x4e or 0x6e depending on the row, so we just
39559        // bitwise-and with 0xe to see if italics should be turned on
39560        if ((char1 & 0xe) === 0xe) {
39561          this.addFormatting(packet.pts, ['i']);
39562        }
39563      }
39564
39565    // We have a normal character in char0, and possibly one in char1
39566    } else if (this.isNormalChar(char0)) {
39567      if (char1 === 0x00) {
39568        char1 = null;
39569      }
39570      text = getCharFromCode(char0);
39571      text += getCharFromCode(char1);
39572      this[this.mode_](packet.pts, text);
39573      this.column_ += text.length;
39574
39575    } // finish data processing
39576
39577  };
39578};
39579Cea608Stream.prototype = new Stream();
39580// Trigger a cue point that captures the current state of the
39581// display buffer
39582Cea608Stream.prototype.flushDisplayed = function(pts) {
39583  var content = this.displayed_
39584    // remove spaces from the start and end of the string
39585    .map(function(row) {
39586      return row.trim();
39587    })
39588    // combine all text rows to display in one cue
39589    .join('\n')
39590    // and remove blank rows from the start and end, but not the middle
39591    .replace(/^\n+|\n+$/g, '');
39592
39593  if (content.length) {
39594    this.trigger('data', {
39595      startPts: this.startPts_,
39596      endPts: pts,
39597      text: content,
39598      stream: this.name_
39599    });
39600  }
39601};
39602
39603/**
39604 * Zero out the data, used for startup and on seek
39605 */
39606Cea608Stream.prototype.reset = function() {
39607  this.mode_ = 'popOn';
39608  // When in roll-up mode, the index of the last row that will
39609  // actually display captions. If a caption is shifted to a row
39610  // with a lower index than this, it is cleared from the display
39611  // buffer
39612  this.topRow_ = 0;
39613  this.startPts_ = 0;
39614  this.displayed_ = createDisplayBuffer();
39615  this.nonDisplayed_ = createDisplayBuffer();
39616  this.lastControlCode_ = null;
39617
39618  // Track row and column for proper line-breaking and spacing
39619  this.column_ = 0;
39620  this.row_ = BOTTOM_ROW;
39621
39622  // This variable holds currently-applied formatting
39623  this.formatting_ = [];
39624};
39625
39626/**
39627 * Sets up control code and related constants for this instance
39628 */
39629Cea608Stream.prototype.setConstants = function() {
39630  // The following attributes have these uses:
39631  // ext_ :    char0 for mid-row codes, and the base for extended
39632  //           chars (ext_+0, ext_+1, and ext_+2 are char0s for
39633  //           extended codes)
39634  // control_: char0 for control codes, except byte-shifted to the
39635  //           left so that we can do this.control_ | CONTROL_CODE
39636  // offset_:  char0 for tab offset codes
39637  //
39638  // It's also worth noting that control codes, and _only_ control codes,
39639  // differ between field 1 and field2. Field 2 control codes are always
39640  // their field 1 value plus 1. That's why there's the "| field" on the
39641  // control value.
39642  if (this.dataChannel_ === 0) {
39643    this.BASE_     = 0x10;
39644    this.EXT_      = 0x11;
39645    this.CONTROL_  = (0x14 | this.field_) << 8;
39646    this.OFFSET_   = 0x17;
39647  } else if (this.dataChannel_ === 1) {
39648    this.BASE_     = 0x18;
39649    this.EXT_      = 0x19;
39650    this.CONTROL_  = (0x1c | this.field_) << 8;
39651    this.OFFSET_   = 0x1f;
39652  }
39653
39654  // Constants for the LSByte command codes recognized by Cea608Stream. This
39655  // list is not exhaustive. For a more comprehensive listing and semantics see
39656  // http://www.gpo.gov/fdsys/pkg/CFR-2010-title47-vol1/pdf/CFR-2010-title47-vol1-sec15-119.pdf
39657  // Padding
39658  this.PADDING_                    = 0x0000;
39659  // Pop-on Mode
39660  this.RESUME_CAPTION_LOADING_     = this.CONTROL_ | 0x20;
39661  this.END_OF_CAPTION_             = this.CONTROL_ | 0x2f;
39662  // Roll-up Mode
39663  this.ROLL_UP_2_ROWS_             = this.CONTROL_ | 0x25;
39664  this.ROLL_UP_3_ROWS_             = this.CONTROL_ | 0x26;
39665  this.ROLL_UP_4_ROWS_             = this.CONTROL_ | 0x27;
39666  this.CARRIAGE_RETURN_            = this.CONTROL_ | 0x2d;
39667  // paint-on mode (not supported)
39668  this.RESUME_DIRECT_CAPTIONING_   = this.CONTROL_ | 0x29;
39669  // Erasure
39670  this.BACKSPACE_                  = this.CONTROL_ | 0x21;
39671  this.ERASE_DISPLAYED_MEMORY_     = this.CONTROL_ | 0x2c;
39672  this.ERASE_NON_DISPLAYED_MEMORY_ = this.CONTROL_ | 0x2e;
39673};
39674
39675/**
39676 * Detects if the 2-byte packet data is a special character
39677 *
39678 * Special characters have a second byte in the range 0x30 to 0x3f,
39679 * with the first byte being 0x11 (for data channel 1) or 0x19 (for
39680 * data channel 2).
39681 *
39682 * @param  {Integer} char0 The first byte
39683 * @param  {Integer} char1 The second byte
39684 * @return {Boolean}       Whether the 2 bytes are an special character
39685 */
39686Cea608Stream.prototype.isSpecialCharacter = function(char0, char1) {
39687  return (char0 === this.EXT_ && char1 >= 0x30 && char1 <= 0x3f);
39688};
39689
39690/**
39691 * Detects if the 2-byte packet data is an extended character
39692 *
39693 * Extended characters have a second byte in the range 0x20 to 0x3f,
39694 * with the first byte being 0x12 or 0x13 (for data channel 1) or
39695 * 0x1a or 0x1b (for data channel 2).
39696 *
39697 * @param  {Integer} char0 The first byte
39698 * @param  {Integer} char1 The second byte
39699 * @return {Boolean}       Whether the 2 bytes are an extended character
39700 */
39701Cea608Stream.prototype.isExtCharacter = function(char0, char1) {
39702  return ((char0 === (this.EXT_ + 1) || char0 === (this.EXT_ + 2)) &&
39703    (char1 >= 0x20 && char1 <= 0x3f));
39704};
39705
39706/**
39707 * Detects if the 2-byte packet is a mid-row code
39708 *
39709 * Mid-row codes have a second byte in the range 0x20 to 0x2f, with
39710 * the first byte being 0x11 (for data channel 1) or 0x19 (for data
39711 * channel 2).
39712 *
39713 * @param  {Integer} char0 The first byte
39714 * @param  {Integer} char1 The second byte
39715 * @return {Boolean}       Whether the 2 bytes are a mid-row code
39716 */
39717Cea608Stream.prototype.isMidRowCode = function(char0, char1) {
39718  return (char0 === this.EXT_ && (char1 >= 0x20 && char1 <= 0x2f));
39719};
39720
39721/**
39722 * Detects if the 2-byte packet is an offset control code
39723 *
39724 * Offset control codes have a second byte in the range 0x21 to 0x23,
39725 * with the first byte being 0x17 (for data channel 1) or 0x1f (for
39726 * data channel 2).
39727 *
39728 * @param  {Integer} char0 The first byte
39729 * @param  {Integer} char1 The second byte
39730 * @return {Boolean}       Whether the 2 bytes are an offset control code
39731 */
39732Cea608Stream.prototype.isOffsetControlCode = function(char0, char1) {
39733  return (char0 === this.OFFSET_ && (char1 >= 0x21 && char1 <= 0x23));
39734};
39735
39736/**
39737 * Detects if the 2-byte packet is a Preamble Address Code
39738 *
39739 * PACs have a first byte in the range 0x10 to 0x17 (for data channel 1)
39740 * or 0x18 to 0x1f (for data channel 2), with the second byte in the
39741 * range 0x40 to 0x7f.
39742 *
39743 * @param  {Integer} char0 The first byte
39744 * @param  {Integer} char1 The second byte
39745 * @return {Boolean}       Whether the 2 bytes are a PAC
39746 */
39747Cea608Stream.prototype.isPAC = function(char0, char1) {
39748  return (char0 >= this.BASE_ && char0 < (this.BASE_ + 8) &&
39749    (char1 >= 0x40 && char1 <= 0x7f));
39750};
39751
39752/**
39753 * Detects if a packet's second byte is in the range of a PAC color code
39754 *
39755 * PAC color codes have the second byte be in the range 0x40 to 0x4f, or
39756 * 0x60 to 0x6f.
39757 *
39758 * @param  {Integer} char1 The second byte
39759 * @return {Boolean}       Whether the byte is a color PAC
39760 */
39761Cea608Stream.prototype.isColorPAC = function(char1) {
39762  return ((char1 >= 0x40 && char1 <= 0x4f) || (char1 >= 0x60 && char1 <= 0x7f));
39763};
39764
39765/**
39766 * Detects if a single byte is in the range of a normal character
39767 *
39768 * Normal text bytes are in the range 0x20 to 0x7f.
39769 *
39770 * @param  {Integer} char  The byte
39771 * @return {Boolean}       Whether the byte is a normal character
39772 */
39773Cea608Stream.prototype.isNormalChar = function(char) {
39774  return (char >= 0x20 && char <= 0x7f);
39775};
39776
39777// Adds the opening HTML tag for the passed character to the caption text,
39778// and keeps track of it for later closing
39779Cea608Stream.prototype.addFormatting = function(pts, format) {
39780  this.formatting_ = this.formatting_.concat(format);
39781  var text = format.reduce(function(text, format) {
39782    return text + '<' + format + '>';
39783  }, '');
39784  this[this.mode_](pts, text);
39785};
39786
39787// Adds HTML closing tags for current formatting to caption text and
39788// clears remembered formatting
39789Cea608Stream.prototype.clearFormatting = function(pts) {
39790  if (!this.formatting_.length) {
39791    return;
39792  }
39793  var text = this.formatting_.reverse().reduce(function(text, format) {
39794    return text + '</' + format + '>';
39795  }, '');
39796  this.formatting_ = [];
39797  this[this.mode_](pts, text);
39798};
39799
39800// Mode Implementations
39801Cea608Stream.prototype.popOn = function(pts, text) {
39802  var baseRow = this.nonDisplayed_[this.row_];
39803
39804  // buffer characters
39805  baseRow += text;
39806  this.nonDisplayed_[this.row_] = baseRow;
39807};
39808
39809Cea608Stream.prototype.rollUp = function(pts, text) {
39810  var baseRow = this.displayed_[BOTTOM_ROW];
39811
39812  baseRow += text;
39813  this.displayed_[BOTTOM_ROW] = baseRow;
39814
39815};
39816
39817Cea608Stream.prototype.shiftRowsUp_ = function() {
39818  var i;
39819  // clear out inactive rows
39820  for (i = 0; i < this.topRow_; i++) {
39821    this.displayed_[i] = '';
39822  }
39823  // shift displayed rows up
39824  for (i = this.topRow_; i < BOTTOM_ROW; i++) {
39825    this.displayed_[i] = this.displayed_[i + 1];
39826  }
39827  // clear out the bottom row
39828  this.displayed_[BOTTOM_ROW] = '';
39829};
39830
39831// paintOn mode is not implemented
39832Cea608Stream.prototype.paintOn = function() {};
39833
39834// exports
39835module.exports = {
39836  CaptionStream: CaptionStream,
39837  Cea608Stream: Cea608Stream
39838};
39839
39840},{"../utils/stream":62}],50:[function(require,module,exports){
39841/**
39842 * mux.js
39843 *
39844 * Copyright (c) 2015 Brightcove
39845 * All rights reserved.
39846 *
39847 * A stream-based mp2t to mp4 converter. This utility can be used to
39848 * deliver mp4s to a SourceBuffer on platforms that support native
39849 * Media Source Extensions.
39850 */
39851'use strict';
39852var Stream = require('../utils/stream.js'),
39853  CaptionStream = require('./caption-stream'),
39854  StreamTypes = require('./stream-types'),
39855  TimestampRolloverStream = require('./timestamp-rollover-stream').TimestampRolloverStream;
39856
39857var m2tsStreamTypes = require('./stream-types.js');
39858
39859// object types
39860var TransportPacketStream, TransportParseStream, ElementaryStream;
39861
39862// constants
39863var
39864  MP2T_PACKET_LENGTH = 188, // bytes
39865  SYNC_BYTE = 0x47;
39866
39867/**
39868 * Splits an incoming stream of binary data into MPEG-2 Transport
39869 * Stream packets.
39870 */
39871TransportPacketStream = function() {
39872  var
39873    buffer = new Uint8Array(MP2T_PACKET_LENGTH),
39874    bytesInBuffer = 0;
39875
39876  TransportPacketStream.prototype.init.call(this);
39877
39878   // Deliver new bytes to the stream.
39879
39880  this.push = function(bytes) {
39881    var
39882      startIndex = 0,
39883      endIndex = MP2T_PACKET_LENGTH,
39884      everything;
39885
39886    // If there are bytes remaining from the last segment, prepend them to the
39887    // bytes that were pushed in
39888    if (bytesInBuffer) {
39889      everything = new Uint8Array(bytes.byteLength + bytesInBuffer);
39890      everything.set(buffer.subarray(0, bytesInBuffer));
39891      everything.set(bytes, bytesInBuffer);
39892      bytesInBuffer = 0;
39893    } else {
39894      everything = bytes;
39895    }
39896
39897    // While we have enough data for a packet
39898    while (endIndex < everything.byteLength) {
39899      // Look for a pair of start and end sync bytes in the data..
39900      if (everything[startIndex] === SYNC_BYTE && everything[endIndex] === SYNC_BYTE) {
39901        // We found a packet so emit it and jump one whole packet forward in
39902        // the stream
39903        this.trigger('data', everything.subarray(startIndex, endIndex));
39904        startIndex += MP2T_PACKET_LENGTH;
39905        endIndex += MP2T_PACKET_LENGTH;
39906        continue;
39907      }
39908      // If we get here, we have somehow become de-synchronized and we need to step
39909      // forward one byte at a time until we find a pair of sync bytes that denote
39910      // a packet
39911      startIndex++;
39912      endIndex++;
39913    }
39914
39915    // If there was some data left over at the end of the segment that couldn't
39916    // possibly be a whole packet, keep it because it might be the start of a packet
39917    // that continues in the next segment
39918    if (startIndex < everything.byteLength) {
39919      buffer.set(everything.subarray(startIndex), 0);
39920      bytesInBuffer = everything.byteLength - startIndex;
39921    }
39922  };
39923
39924  this.flush = function() {
39925    // If the buffer contains a whole packet when we are being flushed, emit it
39926    // and empty the buffer. Otherwise hold onto the data because it may be
39927    // important for decoding the next segment
39928    if (bytesInBuffer === MP2T_PACKET_LENGTH && buffer[0] === SYNC_BYTE) {
39929      this.trigger('data', buffer);
39930      bytesInBuffer = 0;
39931    }
39932    this.trigger('done');
39933  };
39934};
39935TransportPacketStream.prototype = new Stream();
39936
39937/**
39938 * Accepts an MP2T TransportPacketStream and emits data events with parsed
39939 * forms of the individual transport stream packets.
39940 */
39941TransportParseStream = function() {
39942  var parsePsi, parsePat, parsePmt, self;
39943  TransportParseStream.prototype.init.call(this);
39944  self = this;
39945
39946  this.packetsWaitingForPmt = [];
39947  this.programMapTable = undefined;
39948
39949  parsePsi = function(payload, psi) {
39950    var offset = 0;
39951
39952    // PSI packets may be split into multiple sections and those
39953    // sections may be split into multiple packets. If a PSI
39954    // section starts in this packet, the payload_unit_start_indicator
39955    // will be true and the first byte of the payload will indicate
39956    // the offset from the current position to the start of the
39957    // section.
39958    if (psi.payloadUnitStartIndicator) {
39959      offset += payload[offset] + 1;
39960    }
39961
39962    if (psi.type === 'pat') {
39963      parsePat(payload.subarray(offset), psi);
39964    } else {
39965      parsePmt(payload.subarray(offset), psi);
39966    }
39967  };
39968
39969  parsePat = function(payload, pat) {
39970    pat.section_number = payload[7]; // eslint-disable-line camelcase
39971    pat.last_section_number = payload[8]; // eslint-disable-line camelcase
39972
39973    // skip the PSI header and parse the first PMT entry
39974    self.pmtPid = (payload[10] & 0x1F) << 8 | payload[11];
39975    pat.pmtPid = self.pmtPid;
39976  };
39977
39978  /**
39979   * Parse out the relevant fields of a Program Map Table (PMT).
39980   * @param payload {Uint8Array} the PMT-specific portion of an MP2T
39981   * packet. The first byte in this array should be the table_id
39982   * field.
39983   * @param pmt {object} the object that should be decorated with
39984   * fields parsed from the PMT.
39985   */
39986  parsePmt = function(payload, pmt) {
39987    var sectionLength, tableEnd, programInfoLength, offset;
39988
39989    // PMTs can be sent ahead of the time when they should actually
39990    // take effect. We don't believe this should ever be the case
39991    // for HLS but we'll ignore "forward" PMT declarations if we see
39992    // them. Future PMT declarations have the current_next_indicator
39993    // set to zero.
39994    if (!(payload[5] & 0x01)) {
39995      return;
39996    }
39997
39998    // overwrite any existing program map table
39999    self.programMapTable = {
vendor: 9,080 bytes, lines 39999-40273
39999};
40000
40001    // the mapping table ends at the end of the current section
40002    sectionLength = (payload[1] & 0x0f) << 8 | payload[2];
40003    tableEnd = 3 + sectionLength - 4;
40004
40005    // to determine where the table is, we have to figure out how
40006    // long the program info descriptors are
40007    programInfoLength = (payload[10] & 0x0f) << 8 | payload[11];
40008
40009    // advance the offset to the first entry in the mapping table
40010    offset = 12 + programInfoLength;
40011    while (offset < tableEnd) {
40012      // add an entry that maps the elementary_pid to the stream_type
40013      self.programMapTable[(payload[offset + 1] & 0x1F) << 8 | payload[offset + 2]] = payload[offset];
40014
40015      // move to the next table entry
40016      // skip past the elementary stream descriptors, if present
40017      offset += ((payload[offset + 3] & 0x0F) << 8 | payload[offset + 4]) + 5;
40018    }
40019
40020    // record the map on the packet as well
40021    pmt.programMapTable = self.programMapTable;
40022
40023    // if there are any packets waiting for a PMT to be found, process them now
40024    while (self.packetsWaitingForPmt.length) {
40025      self.processPes_.apply(self, self.packetsWaitingForPmt.shift());
40026    }
40027  };
40028
40029  /**
40030   * Deliver a new MP2T packet to the stream.
40031   */
40032  this.push = function(packet) {
40033    var
40034      result = {},
40035      offset = 4;
40036
40037    result.payloadUnitStartIndicator = !!(packet[1] & 0x40);
40038
40039    // pid is a 13-bit field starting at the last bit of packet[1]
40040    result.pid = packet[1] & 0x1f;
40041    result.pid <<= 8;
40042    result.pid |= packet[2];
40043
40044    // if an adaption field is present, its length is specified by the
40045    // fifth byte of the TS packet header. The adaptation field is
40046    // used to add stuffing to PES packets that don't fill a complete
40047    // TS packet, and to specify some forms of timing and control data
40048    // that we do not currently use.
40049    if (((packet[3] & 0x30) >>> 4) > 0x01) {
40050      offset += packet[offset] + 1;
40051    }
40052
40053    // parse the rest of the packet based on the type
40054    if (result.pid === 0) {
40055      result.type = 'pat';
40056      parsePsi(packet.subarray(offset), result);
40057      this.trigger('data', result);
40058    } else if (result.pid === this.pmtPid) {
40059      result.type = 'pmt';
40060      parsePsi(packet.subarray(offset), result);
40061      this.trigger('data', result);
40062    } else if (this.programMapTable === undefined) {
40063      // When we have not seen a PMT yet, defer further processing of
40064      // PES packets until one has been parsed
40065      this.packetsWaitingForPmt.push([packet, offset, result]);
40066    } else {
40067      this.processPes_(packet, offset, result);
40068    }
40069  };
40070
40071  this.processPes_ = function(packet, offset, result) {
40072    result.streamType = this.programMapTable[result.pid];
40073    result.type = 'pes';
40074    result.data = packet.subarray(offset);
40075
40076    this.trigger('data', result);
40077  };
40078
40079};
40080TransportParseStream.prototype = new Stream();
40081TransportParseStream.STREAM_TYPES  = {
40082  h264: 0x1b,
40083  adts: 0x0f
40084};
40085
40086/**
40087 * Reconsistutes program elementary stream (PES) packets from parsed
40088 * transport stream packets. That is, if you pipe an
40089 * mp2t.TransportParseStream into a mp2t.ElementaryStream, the output
40090 * events will be events which capture the bytes for individual PES
40091 * packets plus relevant metadata that has been extracted from the
40092 * container.
40093 */
40094ElementaryStream = function() {
40095  var
40096    self = this,
40097    // PES packet fragments
40098    video = {
40099      data: [],
40100      size: 0
40101    },
40102    audio = {
40103      data: [],
40104      size: 0
40105    },
40106    timedMetadata = {
40107      data: [],
40108      size: 0
40109    },
40110    parsePes = function(payload, pes) {
40111      var ptsDtsFlags;
40112
40113      // get the packet length, this will be 0 for video
40114      pes.packetLength = 6 + ((payload[4] << 8) | payload[5]);
40115
40116      // find out if this packets starts a new keyframe
40117      pes.dataAlignmentIndicator = (payload[6] & 0x04) !== 0;
40118      // PES packets may be annotated with a PTS value, or a PTS value
40119      // and a DTS value. Determine what combination of values is
40120      // available to work with.
40121      ptsDtsFlags = payload[7];
40122
40123      // PTS and DTS are normally stored as a 33-bit number.  Javascript
40124      // performs all bitwise operations on 32-bit integers but javascript
40125      // supports a much greater range (52-bits) of integer using standard
40126      // mathematical operations.
40127      // We construct a 31-bit value using bitwise operators over the 31
40128      // most significant bits and then multiply by 4 (equal to a left-shift
40129      // of 2) before we add the final 2 least significant bits of the
40130      // timestamp (equal to an OR.)
40131      if (ptsDtsFlags & 0xC0) {
40132        // the PTS and DTS are not written out directly. For information
40133        // on how they are encoded, see
40134        // http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
40135        pes.pts = (payload[9] & 0x0E) << 27 |
40136          (payload[10] & 0xFF) << 20 |
40137          (payload[11] & 0xFE) << 12 |
40138          (payload[12] & 0xFF) <<  5 |
40139          (payload[13] & 0xFE) >>>  3;
40140        pes.pts *= 4; // Left shift by 2
40141        pes.pts += (payload[13] & 0x06) >>> 1; // OR by the two LSBs
40142        pes.dts = pes.pts;
40143        if (ptsDtsFlags & 0x40) {
40144          pes.dts = (payload[14] & 0x0E) << 27 |
40145            (payload[15] & 0xFF) << 20 |
40146            (payload[16] & 0xFE) << 12 |
40147            (payload[17] & 0xFF) << 5 |
40148            (payload[18] & 0xFE) >>> 3;
40149          pes.dts *= 4; // Left shift by 2
40150          pes.dts += (payload[18] & 0x06) >>> 1; // OR by the two LSBs
40151        }
40152      }
40153      // the data section starts immediately after the PES header.
40154      // pes_header_data_length specifies the number of header bytes
40155      // that follow the last byte of the field.
40156      pes.data = payload.subarray(9 + payload[8]);
40157    },
40158    flushStream = function(stream, type, forceFlush) {
40159      var
40160        packetData = new Uint8Array(stream.size),
40161        event = {
40162          type: type
40163        },
40164        i = 0,
40165        offset = 0,
40166        packetFlushable = false,
40167        fragment;
40168
40169      // do nothing if there is not enough buffered data for a complete
40170      // PES header
40171      if (!stream.data.length || stream.size < 9) {
40172        return;
40173      }
40174      event.trackId = stream.data[0].pid;
40175
40176      // reassemble the packet
40177      for (i = 0; i < stream.data.length; i++) {
40178        fragment = stream.data[i];
40179
40180        packetData.set(fragment.data, offset);
40181        offset += fragment.data.byteLength;
40182      }
40183
40184      // parse assembled packet's PES header
40185      parsePes(packetData, event);
40186
40187      // non-video PES packets MUST have a non-zero PES_packet_length
40188      // check that they match before we do a flush
40189      packetFlushable = type === 'video' || event.packetLength === stream.size;
40190
40191      // flush pending packets if the conditions are right
40192      if (forceFlush || packetFlushable) {
40193        stream.size = 0;
40194        stream.data.length = 0;
40195      }
40196
40197      // only emit packets that are complete. this is to avoid assembling
40198      // incomplete PES packets due to poor segmentation
40199      if (packetFlushable) {
40200        self.trigger('data', event);
40201      }
40202    };
40203
40204  ElementaryStream.prototype.init.call(this);
40205
40206  this.push = function(data) {
40207    ({
40208      pat: function() {
40209        // we have to wait for the PMT to arrive as well before we
40210        // have any meaningful metadata
40211      },
40212      pes: function() {
40213        var stream, streamType;
40214
40215        switch (data.streamType) {
40216        case StreamTypes.H264_STREAM_TYPE:
40217        case m2tsStreamTypes.H264_STREAM_TYPE:
40218          stream = video;
40219          streamType = 'video';
40220          break;
40221        case StreamTypes.ADTS_STREAM_TYPE:
40222          stream = audio;
40223          streamType = 'audio';
40224          break;
40225        case StreamTypes.METADATA_STREAM_TYPE:
40226          stream = timedMetadata;
40227          streamType = 'timed-metadata';
40228          break;
40229        default:
40230          // ignore unknown stream types
40231          return;
40232        }
40233
40234        // if a new packet is starting, we can flush the completed
40235        // packet
40236        if (data.payloadUnitStartIndicator) {
40237          flushStream(stream, streamType, true);
40238        }
40239
40240        // buffer this fragment until we are sure we've received the
40241        // complete payload
40242        stream.data.push(data);
40243        stream.size += data.data.byteLength;
40244      },
40245      pmt: function() {
40246        var
40247          event = {
40248            type: 'metadata',
40249            tracks: []
40250          },
40251          programMapTable = data.programMapTable,
40252          k,
40253          track;
40254
40255        // translate streams to tracks
40256        for (k in programMapTable) {
40257          if (programMapTable.hasOwnProperty(k)) {
40258            track = {
40259              timelineStartInfo: {
40260                baseMediaDecodeTime: 0
40261              }
40262            };
40263            track.id = +k;
40264            if (programMapTable[k] === m2tsStreamTypes.H264_STREAM_TYPE) {
40265              track.codec = 'avc';
40266              track.type = 'video';
40267            } else if (programMapTable[k] === m2tsStreamTypes.ADTS_STREAM_TYPE) {
40268              track.codec = 'adts';
40269              track.type = 'audio';
40270            }
40271            event.tracks.push(track);
40272          }
40273        }
vendor: 57,163 bytes, lines 40273-42243
40273
40274        self.trigger('data', event);
40275      }
40276    })[data.type]();
40277  };
40278
40279  /**
40280   * Flush any remaining input. Video PES packets may be of variable
40281   * length. Normally, the start of a new video packet can trigger the
40282   * finalization of the previous packet. That is not possible if no
40283   * more video is forthcoming, however. In that case, some other
40284   * mechanism (like the end of the file) has to be employed. When it is
40285   * clear that no additional data is forthcoming, calling this method
40286   * will flush the buffered packets.
40287   */
40288  this.flush = function() {
40289    // !!THIS ORDER IS IMPORTANT!!
40290    // video first then audio
40291    flushStream(video, 'video');
40292    flushStream(audio, 'audio');
40293    flushStream(timedMetadata, 'timed-metadata');
40294    this.trigger('done');
40295  };
40296};
40297ElementaryStream.prototype = new Stream();
40298
40299var m2ts = {
40300  PAT_PID: 0x0000,
40301  MP2T_PACKET_LENGTH: MP2T_PACKET_LENGTH,
40302  TransportPacketStream: TransportPacketStream,
40303  TransportParseStream: TransportParseStream,
40304  ElementaryStream: ElementaryStream,
40305  TimestampRolloverStream: TimestampRolloverStream,
40306  CaptionStream: CaptionStream.CaptionStream,
40307  Cea608Stream: CaptionStream.Cea608Stream,
40308  MetadataStream: require('./metadata-stream')
40309};
40310
40311for (var type in StreamTypes) {
40312  if (StreamTypes.hasOwnProperty(type)) {
40313    m2ts[type] = StreamTypes[type];
40314  }
40315}
40316
40317module.exports = m2ts;
40318
40319},{"../utils/stream.js":62,"./caption-stream":49,"./metadata-stream":51,"./stream-types":53,"./stream-types.js":53,"./timestamp-rollover-stream":54}],51:[function(require,module,exports){
40320/**
40321 * Accepts program elementary stream (PES) data events and parses out
40322 * ID3 metadata from them, if present.
40323 * @see http://id3.org/id3v2.3.0
40324 */
40325'use strict';
40326var
40327  Stream = require('../utils/stream'),
40328  StreamTypes = require('./stream-types'),
40329  // return a percent-encoded representation of the specified byte range
40330  // @see http://en.wikipedia.org/wiki/Percent-encoding
40331  percentEncode = function(bytes, start, end) {
40332    var i, result = '';
40333    for (i = start; i < end; i++) {
40334      result += '%' + ('00' + bytes[i].toString(16)).slice(-2);
40335    }
40336    return result;
40337  },
40338  // return the string representation of the specified byte range,
40339  // interpreted as UTf-8.
40340  parseUtf8 = function(bytes, start, end) {
40341    return decodeURIComponent(percentEncode(bytes, start, end));
40342  },
40343  // return the string representation of the specified byte range,
40344  // interpreted as ISO-8859-1.
40345  parseIso88591 = function(bytes, start, end) {
40346    return unescape(percentEncode(bytes, start, end)); // jshint ignore:line
40347  },
40348  parseSyncSafeInteger = function(data) {
40349    return (data[0] << 21) |
40350            (data[1] << 14) |
40351            (data[2] << 7) |
40352            (data[3]);
40353  },
40354  tagParsers = {
40355    TXXX: function(tag) {
40356      var i;
40357      if (tag.data[0] !== 3) {
40358        // ignore frames with unrecognized character encodings
40359        return;
40360      }
40361
40362      for (i = 1; i < tag.data.length; i++) {
40363        if (tag.data[i] === 0) {
40364          // parse the text fields
40365          tag.description = parseUtf8(tag.data, 1, i);
40366          // do not include the null terminator in the tag value
40367          tag.value = parseUtf8(tag.data, i + 1, tag.data.length).replace(/\0*$/, '');
40368          break;
40369        }
40370      }
40371      tag.data = tag.value;
40372    },
40373    WXXX: function(tag) {
40374      var i;
40375      if (tag.data[0] !== 3) {
40376        // ignore frames with unrecognized character encodings
40377        return;
40378      }
40379
40380      for (i = 1; i < tag.data.length; i++) {
40381        if (tag.data[i] === 0) {
40382          // parse the description and URL fields
40383          tag.description = parseUtf8(tag.data, 1, i);
40384          tag.url = parseUtf8(tag.data, i + 1, tag.data.length);
40385          break;
40386        }
40387      }
40388    },
40389    PRIV: function(tag) {
40390      var i;
40391
40392      for (i = 0; i < tag.data.length; i++) {
40393        if (tag.data[i] === 0) {
40394          // parse the description and URL fields
40395          tag.owner = parseIso88591(tag.data, 0, i);
40396          break;
40397        }
40398      }
40399      tag.privateData = tag.data.subarray(i + 1);
40400      tag.data = tag.privateData;
40401    }
40402  },
40403  MetadataStream;
40404
40405MetadataStream = function(options) {
40406  var
40407    settings = {
40408      debug: !!(options && options.debug),
40409
40410      // the bytes of the program-level descriptor field in MP2T
40411      // see ISO/IEC 13818-1:2013 (E), section 2.6 "Program and
40412      // program element descriptors"
40413      descriptor: options && options.descriptor
40414    },
40415    // the total size in bytes of the ID3 tag being parsed
40416    tagSize = 0,
40417    // tag data that is not complete enough to be parsed
40418    buffer = [],
40419    // the total number of bytes currently in the buffer
40420    bufferSize = 0,
40421    i;
40422
40423  MetadataStream.prototype.init.call(this);
40424
40425  // calculate the text track in-band metadata track dispatch type
40426  // https://html.spec.whatwg.org/multipage/embedded-content.html#steps-to-expose-a-media-resource-specific-text-track
40427  this.dispatchType = StreamTypes.METADATA_STREAM_TYPE.toString(16);
40428  if (settings.descriptor) {
40429    for (i = 0; i < settings.descriptor.length; i++) {
40430      this.dispatchType += ('00' + settings.descriptor[i].toString(16)).slice(-2);
40431    }
40432  }
40433
40434  this.push = function(chunk) {
40435    var tag, frameStart, frameSize, frame, i, frameHeader;
40436    if (chunk.type !== 'timed-metadata') {
40437      return;
40438    }
40439
40440    // if data_alignment_indicator is set in the PES header,
40441    // we must have the start of a new ID3 tag. Assume anything
40442    // remaining in the buffer was malformed and throw it out
40443    if (chunk.dataAlignmentIndicator) {
40444      bufferSize = 0;
40445      buffer.length = 0;
40446    }
40447
40448    // ignore events that don't look like ID3 data
40449    if (buffer.length === 0 &&
40450        (chunk.data.length < 10 ||
40451          chunk.data[0] !== 'I'.charCodeAt(0) ||
40452          chunk.data[1] !== 'D'.charCodeAt(0) ||
40453          chunk.data[2] !== '3'.charCodeAt(0))) {
40454      if (settings.debug) {
40455        // eslint-disable-next-line no-console
40456        console.log('Skipping unrecognized metadata packet');
40457      }
40458      return;
40459    }
40460
40461    // add this chunk to the data we've collected so far
40462
40463    buffer.push(chunk);
40464    bufferSize += chunk.data.byteLength;
40465
40466    // grab the size of the entire frame from the ID3 header
40467    if (buffer.length === 1) {
40468      // the frame size is transmitted as a 28-bit integer in the
40469      // last four bytes of the ID3 header.
40470      // The most significant bit of each byte is dropped and the
40471      // results concatenated to recover the actual value.
40472      tagSize = parseSyncSafeInteger(chunk.data.subarray(6, 10));
40473
40474      // ID3 reports the tag size excluding the header but it's more
40475      // convenient for our comparisons to include it
40476      tagSize += 10;
40477    }
40478
40479    // if the entire frame has not arrived, wait for more data
40480    if (bufferSize < tagSize) {
40481      return;
40482    }
40483
40484    // collect the entire frame so it can be parsed
40485    tag = {
40486      data: new Uint8Array(tagSize),
40487      frames: [],
40488      pts: buffer[0].pts,
40489      dts: buffer[0].dts
40490    };
40491    for (i = 0; i < tagSize;) {
40492      tag.data.set(buffer[0].data.subarray(0, tagSize - i), i);
40493      i += buffer[0].data.byteLength;
40494      bufferSize -= buffer[0].data.byteLength;
40495      buffer.shift();
40496    }
40497
40498    // find the start of the first frame and the end of the tag
40499    frameStart = 10;
40500    if (tag.data[5] & 0x40) {
40501      // advance the frame start past the extended header
40502      frameStart += 4; // header size field
40503      frameStart += parseSyncSafeInteger(tag.data.subarray(10, 14));
40504
40505      // clip any padding off the end
40506      tagSize -= parseSyncSafeInteger(tag.data.subarray(16, 20));
40507    }
40508
40509    // parse one or more ID3 frames
40510    // http://id3.org/id3v2.3.0#ID3v2_frame_overview
40511    do {
40512      // determine the number of bytes in this frame
40513      frameSize = parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));
40514      if (frameSize < 1) {
40515         // eslint-disable-next-line no-console
40516        return console.log('Malformed ID3 frame encountered. Skipping metadata parsing.');
40517      }
40518      frameHeader = String.fromCharCode(tag.data[frameStart],
40519                                        tag.data[frameStart + 1],
40520                                        tag.data[frameStart + 2],
40521                                        tag.data[frameStart + 3]);
40522
40523
40524      frame = {
40525        id: frameHeader,
40526        data: tag.data.subarray(frameStart + 10, frameStart + frameSize + 10)
40527      };
40528      frame.key = frame.id;
40529      if (tagParsers[frame.id]) {
40530        tagParsers[frame.id](frame);
40531
40532        // handle the special PRIV frame used to indicate the start
40533        // time for raw AAC data
40534        if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
40535          var
40536            d = frame.data,
40537            size = ((d[3] & 0x01)  << 30) |
40538                   (d[4]  << 22) |
40539                   (d[5] << 14) |
40540                   (d[6] << 6) |
40541                   (d[7] >>> 2);
40542
40543          size *= 4;
40544          size += d[7] & 0x03;
40545          frame.timeStamp = size;
40546          // in raw AAC, all subsequent data will be timestamped based
40547          // on the value of this frame
40548          // we couldn't have known the appropriate pts and dts before
40549          // parsing this ID3 tag so set those values now
40550          if (tag.pts === undefined && tag.dts === undefined) {
40551            tag.pts = frame.timeStamp;
40552            tag.dts = frame.timeStamp;
40553          }
40554          this.trigger('timestamp', frame);
40555        }
40556      }
40557      tag.frames.push(frame);
40558
40559      frameStart += 10; // advance past the frame header
40560      frameStart += frameSize; // advance past the frame body
40561    } while (frameStart < tagSize);
40562    this.trigger('data', tag);
40563  };
40564};
40565MetadataStream.prototype = new Stream();
40566
40567module.exports = MetadataStream;
40568
40569},{"../utils/stream":62,"./stream-types":53}],52:[function(require,module,exports){
40570/**
40571 * mux.js
40572 *
40573 * Copyright (c) 2016 Brightcove
40574 * All rights reserved.
40575 *
40576 * Utilities to detect basic properties and metadata about TS Segments.
40577 */
40578'use strict';
40579
40580var StreamTypes = require('./stream-types.js');
40581
40582var parsePid = function(packet) {
40583  var pid = packet[1] & 0x1f;
40584  pid <<= 8;
40585  pid |= packet[2];
40586  return pid;
40587};
40588
40589var parsePayloadUnitStartIndicator = function(packet) {
40590  return !!(packet[1] & 0x40);
40591};
40592
40593var parseAdaptionField = function(packet) {
40594  var offset = 0;
40595  // if an adaption field is present, its length is specified by the
40596  // fifth byte of the TS packet header. The adaptation field is
40597  // used to add stuffing to PES packets that don't fill a complete
40598  // TS packet, and to specify some forms of timing and control data
40599  // that we do not currently use.
40600  if (((packet[3] & 0x30) >>> 4) > 0x01) {
40601    offset += packet[4] + 1;
40602  }
40603  return offset;
40604};
40605
40606var parseType = function(packet, pmtPid) {
40607  var pid = parsePid(packet);
40608  if (pid === 0) {
40609    return 'pat';
40610  } else if (pid === pmtPid) {
40611    return 'pmt';
40612  } else if (pmtPid) {
40613    return 'pes';
40614  }
40615  return null;
40616};
40617
40618var parsePat = function(packet) {
40619  var pusi = parsePayloadUnitStartIndicator(packet);
40620  var offset = 4 + parseAdaptionField(packet);
40621
40622  if (pusi) {
40623    offset += packet[offset] + 1;
40624  }
40625
40626  return (packet[offset + 10] & 0x1f) << 8 | packet[offset + 11];
40627};
40628
40629var parsePmt = function(packet) {
40630  var programMapTable = {};
40631  var pusi = parsePayloadUnitStartIndicator(packet);
40632  var payloadOffset = 4 + parseAdaptionField(packet);
40633
40634  if (pusi) {
40635    payloadOffset += packet[payloadOffset] + 1;
40636  }
40637
40638  // PMTs can be sent ahead of the time when they should actually
40639  // take effect. We don't believe this should ever be the case
40640  // for HLS but we'll ignore "forward" PMT declarations if we see
40641  // them. Future PMT declarations have the current_next_indicator
40642  // set to zero.
40643  if (!(packet[payloadOffset + 5] & 0x01)) {
40644    return;
40645  }
40646
40647  var sectionLength, tableEnd, programInfoLength;
40648  // the mapping table ends at the end of the current section
40649  sectionLength = (packet[payloadOffset + 1] & 0x0f) << 8 | packet[payloadOffset + 2];
40650  tableEnd = 3 + sectionLength - 4;
40651
40652  // to determine where the table is, we have to figure out how
40653  // long the program info descriptors are
40654  programInfoLength = (packet[payloadOffset + 10] & 0x0f) << 8 | packet[payloadOffset + 11];
40655
40656  // advance the offset to the first entry in the mapping table
40657  var offset = 12 + programInfoLength;
40658  while (offset < tableEnd) {
40659    var i = payloadOffset + offset;
40660    // add an entry that maps the elementary_pid to the stream_type
40661    programMapTable[(packet[i + 1] & 0x1F) << 8 | packet[i + 2]] = packet[i];
40662
40663    // move to the next table entry
40664    // skip past the elementary stream descriptors, if present
40665    offset += ((packet[i + 3] & 0x0F) << 8 | packet[i + 4]) + 5;
40666  }
40667  return programMapTable;
40668};
40669
40670var parsePesType = function(packet, programMapTable) {
40671  var pid = parsePid(packet);
40672  var type = programMapTable[pid];
40673  switch (type) {
40674    case StreamTypes.H264_STREAM_TYPE:
40675      return 'video';
40676    case StreamTypes.ADTS_STREAM_TYPE:
40677      return 'audio';
40678    case StreamTypes.METADATA_STREAM_TYPE:
40679      return 'timed-metadata';
40680    default:
40681      return null;
40682  }
40683};
40684
40685var parsePesTime = function(packet) {
40686  var pusi = parsePayloadUnitStartIndicator(packet);
40687  if (!pusi) {
40688    return null;
40689  }
40690
40691  var offset = 4 + parseAdaptionField(packet);
40692
40693  if (offset >= packet.byteLength) {
40694    // From the H 222.0 MPEG-TS spec
40695    // "For transport stream packets carrying PES packets, stuffing is needed when there
40696    //  is insufficient PES packet data to completely fill the transport stream packet
40697    //  payload bytes. Stuffing is accomplished by defining an adaptation field longer than
40698    //  the sum of the lengths of the data elements in it, so that the payload bytes
40699    //  remaining after the adaptation field exactly accommodates the available PES packet
40700    //  data."
40701    //
40702    // If the offset is >= the length of the packet, then the packet contains no data
40703    // and instead is just adaption field stuffing bytes
40704    return null;
40705  }
40706
40707  var pes = null;
40708  var ptsDtsFlags;
40709
40710  // PES packets may be annotated with a PTS value, or a PTS value
40711  // and a DTS value. Determine what combination of values is
40712  // available to work with.
40713  ptsDtsFlags = packet[offset + 7];
40714
40715  // PTS and DTS are normally stored as a 33-bit number.  Javascript
40716  // performs all bitwise operations on 32-bit integers but javascript
40717  // supports a much greater range (52-bits) of integer using standard
40718  // mathematical operations.
40719  // We construct a 31-bit value using bitwise operators over the 31
40720  // most significant bits and then multiply by 4 (equal to a left-shift
40721  // of 2) before we add the final 2 least significant bits of the
40722  // timestamp (equal to an OR.)
40723  if (ptsDtsFlags & 0xC0) {
40724    pes = {};
40725    // the PTS and DTS are not written out directly. For information
40726    // on how they are encoded, see
40727    // http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
40728    pes.pts = (packet[offset + 9] & 0x0E) << 27 |
40729      (packet[offset + 10] & 0xFF) << 20 |
40730      (packet[offset + 11] & 0xFE) << 12 |
40731      (packet[offset + 12] & 0xFF) <<  5 |
40732      (packet[offset + 13] & 0xFE) >>>  3;
40733    pes.pts *= 4; // Left shift by 2
40734    pes.pts += (packet[offset + 13] & 0x06) >>> 1; // OR by the two LSBs
40735    pes.dts = pes.pts;
40736    if (ptsDtsFlags & 0x40) {
40737      pes.dts = (packet[offset + 14] & 0x0E) << 27 |
40738        (packet[offset + 15] & 0xFF) << 20 |
40739        (packet[offset + 16] & 0xFE) << 12 |
40740        (packet[offset + 17] & 0xFF) << 5 |
40741        (packet[offset + 18] & 0xFE) >>> 3;
40742      pes.dts *= 4; // Left shift by 2
40743      pes.dts += (packet[offset + 18] & 0x06) >>> 1; // OR by the two LSBs
40744    }
40745  }
40746  return pes;
40747};
40748
40749var parseNalUnitType = function(type) {
40750  switch (type) {
40751    case 0x05:
40752      return 'slice_layer_without_partitioning_rbsp_idr';
40753    case 0x06:
40754      return 'sei_rbsp';
40755    case 0x07:
40756      return 'seq_parameter_set_rbsp';
40757    case 0x08:
40758      return 'pic_parameter_set_rbsp';
40759    case 0x09:
40760      return 'access_unit_delimiter_rbsp';
40761    default:
40762      return null;
40763  }
40764};
40765
40766var videoPacketContainsKeyFrame = function(packet) {
40767  var offset = 4 + parseAdaptionField(packet);
40768  var frameBuffer = packet.subarray(offset);
40769  var frameI = 0;
40770  var frameSyncPoint = 0;
40771  var foundKeyFrame = false;
40772  var nalType;
40773
40774  // advance the sync point to a NAL start, if necessary
40775  for (; frameSyncPoint < frameBuffer.byteLength - 3; frameSyncPoint++) {
40776    if (frameBuffer[frameSyncPoint + 2] === 1) {
40777      // the sync point is properly aligned
40778      frameI = frameSyncPoint + 5;
40779      break;
40780    }
40781  }
40782
40783  while (frameI < frameBuffer.byteLength) {
40784    // look at the current byte to determine if we've hit the end of
40785    // a NAL unit boundary
40786    switch (frameBuffer[frameI]) {
40787    case 0:
40788      // skip past non-sync sequences
40789      if (frameBuffer[frameI - 1] !== 0) {
40790        frameI += 2;
40791        break;
40792      } else if (frameBuffer[frameI - 2] !== 0) {
40793        frameI++;
40794        break;
40795      }
40796
40797      if (frameSyncPoint + 3 !== frameI - 2) {
40798        nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f);
40799        if (nalType === 'slice_layer_without_partitioning_rbsp_idr') {
40800          foundKeyFrame = true;
40801        }
40802      }
40803
40804      // drop trailing zeroes
40805      do {
40806        frameI++;
40807      } while (frameBuffer[frameI] !== 1 && frameI < frameBuffer.length);
40808      frameSyncPoint = frameI - 2;
40809      frameI += 3;
40810      break;
40811    case 1:
40812      // skip past non-sync sequences
40813      if (frameBuffer[frameI - 1] !== 0 ||
40814          frameBuffer[frameI - 2] !== 0) {
40815        frameI += 3;
40816        break;
40817      }
40818
40819      nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f);
40820      if (nalType === 'slice_layer_without_partitioning_rbsp_idr') {
40821        foundKeyFrame = true;
40822      }
40823      frameSyncPoint = frameI - 2;
40824      frameI += 3;
40825      break;
40826    default:
40827      // the current byte isn't a one or zero, so it cannot be part
40828      // of a sync sequence
40829      frameI += 3;
40830      break;
40831    }
40832  }
40833  frameBuffer = frameBuffer.subarray(frameSyncPoint);
40834  frameI -= frameSyncPoint;
40835  frameSyncPoint = 0;
40836  // parse the final nal
40837  if (frameBuffer && frameBuffer.byteLength > 3) {
40838    nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f);
40839    if (nalType === 'slice_layer_without_partitioning_rbsp_idr') {
40840      foundKeyFrame = true;
40841    }
40842  }
40843
40844  return foundKeyFrame;
40845};
40846
40847
40848module.exports = {
40849  parseType: parseType,
40850  parsePat: parsePat,
40851  parsePmt: parsePmt,
40852  parsePayloadUnitStartIndicator: parsePayloadUnitStartIndicator,
40853  parsePesType: parsePesType,
40854  parsePesTime: parsePesTime,
40855  videoPacketContainsKeyFrame: videoPacketContainsKeyFrame
40856};
40857
40858},{"./stream-types.js":53}],53:[function(require,module,exports){
40859'use strict';
40860
40861module.exports = {
40862  H264_STREAM_TYPE: 0x1B,
40863  ADTS_STREAM_TYPE: 0x0F,
40864  METADATA_STREAM_TYPE: 0x15
40865};
40866
40867},{}],54:[function(require,module,exports){
40868/**
40869 * mux.js
40870 *
40871 * Copyright (c) 2016 Brightcove
40872 * All rights reserved.
40873 *
40874 * Accepts program elementary stream (PES) data events and corrects
40875 * decode and presentation time stamps to account for a rollover
40876 * of the 33 bit value.
40877 */
40878
40879'use strict';
40880
40881var Stream = require('../utils/stream');
40882
40883var MAX_TS = 8589934592;
40884
40885var RO_THRESH = 4294967296;
40886
40887var handleRollover = function(value, reference) {
40888  var direction = 1;
40889
40890  if (value > reference) {
40891    // If the current timestamp value is greater than our reference timestamp and we detect a
40892    // timestamp rollover, this means the roll over is happening in the opposite direction.
40893    // Example scenario: Enter a long stream/video just after a rollover occurred. The reference
40894    // point will be set to a small number, e.g. 1. The user then seeks backwards over the
40895    // rollover point. In loading this segment, the timestamp values will be very large,
40896    // e.g. 2^33 - 1. Since this comes before the data we loaded previously, we want to adjust
40897    // the time stamp to be `value - 2^33`.
40898    direction = -1;
40899  }
40900
40901  // Note: A seek forwards or back that is greater than the RO_THRESH (2^32, ~13 hours) will
40902  // cause an incorrect adjustment.
40903  while (Math.abs(reference - value) > RO_THRESH) {
40904    value += (direction * MAX_TS);
40905  }
40906
40907  return value;
40908};
40909
40910var TimestampRolloverStream = function(type) {
40911  var lastDTS, referenceDTS;
40912
40913  TimestampRolloverStream.prototype.init.call(this);
40914
40915  this.type_ = type;
40916
40917  this.push = function(data) {
40918    if (data.type !== this.type_) {
40919      return;
40920    }
40921
40922    if (referenceDTS === undefined) {
40923      referenceDTS = data.dts;
40924    }
40925
40926    data.dts = handleRollover(data.dts, referenceDTS);
40927    data.pts = handleRollover(data.pts, referenceDTS);
40928
40929    lastDTS = data.dts;
40930
40931    this.trigger('data', data);
40932  };
40933
40934  this.flush = function() {
40935    referenceDTS = lastDTS;
40936    this.trigger('done');
40937  };
40938
40939  this.discontinuity = function() {
40940    referenceDTS = void 0;
40941    lastDTS = void 0;
40942  };
40943
40944};
40945
40946TimestampRolloverStream.prototype = new Stream();
40947
40948module.exports = {
40949  TimestampRolloverStream: TimestampRolloverStream,
40950  handleRollover: handleRollover
40951};
40952
40953},{"../utils/stream":62}],55:[function(require,module,exports){
40954module.exports = {
40955  generator: require('./mp4-generator'),
40956  Transmuxer: require('./transmuxer').Transmuxer,
40957  AudioSegmentStream: require('./transmuxer').AudioSegmentStream,
40958  VideoSegmentStream: require('./transmuxer').VideoSegmentStream
40959};
40960
40961},{"./mp4-generator":56,"./transmuxer":58}],56:[function(require,module,exports){
40962/**
40963 * mux.js
40964 *
40965 * Copyright (c) 2015 Brightcove
40966 * All rights reserved.
40967 *
40968 * Functions that generate fragmented MP4s suitable for use with Media
40969 * Source Extensions.
40970 */
40971'use strict';
40972
40973var UINT32_MAX = Math.pow(2, 32) - 1;
40974
40975var box, dinf, esds, ftyp, mdat, mfhd, minf, moof, moov, mvex, mvhd,
40976    trak, tkhd, mdia, mdhd, hdlr, sdtp, stbl, stsd, traf, trex,
40977    trun, types, MAJOR_BRAND, MINOR_VERSION, AVC1_BRAND, VIDEO_HDLR,
40978    AUDIO_HDLR, HDLR_TYPES, VMHD, SMHD, DREF, STCO, STSC, STSZ, STTS;
40979
40980// pre-calculate constants
40981(function() {
40982  var i;
40983  types = {
40984    avc1: [], // codingname
40985    avcC: [],
40986    btrt: [],
40987    dinf: [],
40988    dref: [],
40989    esds: [],
40990    ftyp: [],
40991    hdlr: [],
40992    mdat: [],
40993    mdhd: [],
40994    mdia: [],
40995    mfhd: [],
40996    minf: [],
40997    moof: [],
40998    moov: [],
40999    mp4a: [], // codingname
41000    mvex: [],
41001    mvhd: [],
41002    sdtp: [],
41003    smhd: [],
41004    stbl: [],
41005    stco: [],
41006    stsc: [],
41007    stsd: [],
41008    stsz: [],
41009    stts: [],
41010    styp: [],
41011    tfdt: [],
41012    tfhd: [],
41013    traf: [],
41014    trak: [],
41015    trun: [],
41016    trex: [],
41017    tkhd: [],
41018    vmhd: []
41019  };
41020
41021  // In environments where Uint8Array is undefined (e.g., IE8), skip set up so that we
41022  // don't throw an error
41023  if (typeof Uint8Array === 'undefined') {
41024    return;
41025  }
41026
41027  for (i in types) {
41028    if (types.hasOwnProperty(i)) {
41029      types[i] = [
41030        i.charCodeAt(0),
41031        i.charCodeAt(1),
41032        i.charCodeAt(2),
41033        i.charCodeAt(3)
41034      ];
41035    }
41036  }
41037
41038  MAJOR_BRAND = new Uint8Array([
41039    'i'.charCodeAt(0),
41040    's'.charCodeAt(0),
41041    'o'.charCodeAt(0),
41042    'm'.charCodeAt(0)
41043  ]);
41044  AVC1_BRAND = new Uint8Array([
41045    'a'.charCodeAt(0),
41046    'v'.charCodeAt(0),
41047    'c'.charCodeAt(0),
41048    '1'.charCodeAt(0)
41049  ]);
41050  MINOR_VERSION = new Uint8Array([0, 0, 0, 1]);
41051  VIDEO_HDLR = new Uint8Array([
41052    0x00, // version 0
41053    0x00, 0x00, 0x00, // flags
41054    0x00, 0x00, 0x00, 0x00, // pre_defined
41055    0x76, 0x69, 0x64, 0x65, // handler_type: 'vide'
41056    0x00, 0x00, 0x00, 0x00, // reserved
41057    0x00, 0x00, 0x00, 0x00, // reserved
41058    0x00, 0x00, 0x00, 0x00, // reserved
41059    0x56, 0x69, 0x64, 0x65,
41060    0x6f, 0x48, 0x61, 0x6e,
41061    0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'VideoHandler'
41062  ]);
41063  AUDIO_HDLR = new Uint8Array([
41064    0x00, // version 0
41065    0x00, 0x00, 0x00, // flags
41066    0x00, 0x00, 0x00, 0x00, // pre_defined
41067    0x73, 0x6f, 0x75, 0x6e, // handler_type: 'soun'
41068    0x00, 0x00, 0x00, 0x00, // reserved
41069    0x00, 0x00, 0x00, 0x00, // reserved
41070    0x00, 0x00, 0x00, 0x00, // reserved
41071    0x53, 0x6f, 0x75, 0x6e,
41072    0x64, 0x48, 0x61, 0x6e,
41073    0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'SoundHandler'
41074  ]);
41075  HDLR_TYPES = {
41076    video: VIDEO_HDLR,
41077    audio: AUDIO_HDLR
41078  };
41079  DREF = new Uint8Array([
41080    0x00, // version 0
41081    0x00, 0x00, 0x00, // flags
41082    0x00, 0x00, 0x00, 0x01, // entry_count
41083    0x00, 0x00, 0x00, 0x0c, // entry_size
41084    0x75, 0x72, 0x6c, 0x20, // 'url' type
41085    0x00, // version 0
41086    0x00, 0x00, 0x01 // entry_flags
41087  ]);
41088  SMHD = new Uint8Array([
41089    0x00,             // version
41090    0x00, 0x00, 0x00, // flags
41091    0x00, 0x00,       // balance, 0 means centered
41092    0x00, 0x00        // reserved
41093  ]);
41094  STCO = new Uint8Array([
41095    0x00, // version
41096    0x00, 0x00, 0x00, // flags
41097    0x00, 0x00, 0x00, 0x00 // entry_count
41098  ]);
41099  STSC = STCO;
41100  STSZ = new Uint8Array([
41101    0x00, // version
41102    0x00, 0x00, 0x00, // flags
41103    0x00, 0x00, 0x00, 0x00, // sample_size
41104    0x00, 0x00, 0x00, 0x00 // sample_count
41105  ]);
41106  STTS = STCO;
41107  VMHD = new Uint8Array([
41108    0x00, // version
41109    0x00, 0x00, 0x01, // flags
41110    0x00, 0x00, // graphicsmode
41111    0x00, 0x00,
41112    0x00, 0x00,
41113    0x00, 0x00 // opcolor
41114  ]);
41115}());
41116
41117box = function(type) {
41118  var
41119    payload = [],
41120    size = 0,
41121    i,
41122    result,
41123    view;
41124
41125  for (i = 1; i < arguments.length; i++) {
41126    payload.push(arguments[i]);
41127  }
41128
41129  i = payload.length;
41130
41131  // calculate the total size we need to allocate
41132  while (i--) {
41133    size += payload[i].byteLength;
41134  }
41135  result = new Uint8Array(size + 8);
41136  view = new DataView(result.buffer, result.byteOffset, result.byteLength);
41137  view.setUint32(0, result.byteLength);
41138  result.set(type, 4);
41139
41140  // copy the payload into the result
41141  for (i = 0, size = 8; i < payload.length; i++) {
41142    result.set(payload[i], size);
41143    size += payload[i].byteLength;
41144  }
41145  return result;
41146};
41147
41148dinf = function() {
41149  return box(types.dinf, box(types.dref, DREF));
41150};
41151
41152esds = function(track) {
41153  return box(types.esds, new Uint8Array([
41154    0x00, // version
41155    0x00, 0x00, 0x00, // flags
41156
41157    // ES_Descriptor
41158    0x03, // tag, ES_DescrTag
41159    0x19, // length
41160    0x00, 0x00, // ES_ID
41161    0x00, // streamDependenceFlag, URL_flag, reserved, streamPriority
41162
41163    // DecoderConfigDescriptor
41164    0x04, // tag, DecoderConfigDescrTag
41165    0x11, // length
41166    0x40, // object type
41167    0x15,  // streamType
41168    0x00, 0x06, 0x00, // bufferSizeDB
41169    0x00, 0x00, 0xda, 0xc0, // maxBitrate
41170    0x00, 0x00, 0xda, 0xc0, // avgBitrate
41171
41172    // DecoderSpecificInfo
41173    0x05, // tag, DecoderSpecificInfoTag
41174    0x02, // length
41175    // ISO/IEC 14496-3, AudioSpecificConfig
41176    // for samplingFrequencyIndex see ISO/IEC 13818-7:2006, 8.1.3.2.2, Table 35
41177    (track.audioobjecttype << 3) | (track.samplingfrequencyindex >>> 1),
41178    (track.samplingfrequencyindex << 7) | (track.channelcount << 3),
41179    0x06, 0x01, 0x02 // GASpecificConfig
41180  ]));
41181};
41182
41183ftyp = function() {
41184  return box(types.ftyp, MAJOR_BRAND, MINOR_VERSION, MAJOR_BRAND, AVC1_BRAND);
41185};
41186
41187hdlr = function(type) {
41188  return box(types.hdlr, HDLR_TYPES[type]);
41189};
41190mdat = function(data) {
41191  return box(types.mdat, data);
41192};
41193mdhd = function(track) {
41194  var result = new Uint8Array([
41195    0x00,                   // version 0
41196    0x00, 0x00, 0x00,       // flags
41197    0x00, 0x00, 0x00, 0x02, // creation_time
41198    0x00, 0x00, 0x00, 0x03, // modification_time
41199    0x00, 0x01, 0x5f, 0x90, // timescale, 90,000 "ticks" per second
41200
41201    (track.duration >>> 24) & 0xFF,
41202    (track.duration >>> 16) & 0xFF,
41203    (track.duration >>>  8) & 0xFF,
41204    track.duration & 0xFF,  // duration
41205    0x55, 0xc4,             // 'und' language (undetermined)
41206    0x00, 0x00
41207  ]);
41208
41209  // Use the sample rate from the track metadata, when it is
41210  // defined. The sample rate can be parsed out of an ADTS header, for
41211  // instance.
41212  if (track.samplerate) {
41213    result[12] = (track.samplerate >>> 24) & 0xFF;
41214    result[13] = (track.samplerate >>> 16) & 0xFF;
41215    result[14] = (track.samplerate >>>  8) & 0xFF;
41216    result[15] = (track.samplerate)        & 0xFF;
41217  }
41218
41219  return box(types.mdhd, result);
41220};
41221mdia = function(track) {
41222  return box(types.mdia, mdhd(track), hdlr(track.type), minf(track));
41223};
41224mfhd = function(sequenceNumber) {
41225  return box(types.mfhd, new Uint8Array([
41226    0x00,
41227    0x00, 0x00, 0x00, // flags
41228    (sequenceNumber & 0xFF000000) >> 24,
41229    (sequenceNumber & 0xFF0000) >> 16,
41230    (sequenceNumber & 0xFF00) >> 8,
41231    sequenceNumber & 0xFF // sequence_number
41232  ]));
41233};
41234minf = function(track) {
41235  return box(types.minf,
41236             track.type === 'video' ? box(types.vmhd, VMHD) : box(types.smhd, SMHD),
41237             dinf(),
41238             stbl(track));
41239};
41240moof = function(sequenceNumber, tracks) {
41241  var
41242    trackFragments = [],
41243    i = tracks.length;
41244  // build traf boxes for each track fragment
41245  while (i--) {
41246    trackFragments[i] = traf(tracks[i]);
41247  }
41248  return box.apply(null, [
41249    types.moof,
41250    mfhd(sequenceNumber)
41251  ].concat(trackFragments));
41252};
41253/**
41254 * Returns a movie box.
41255 * @param tracks {array} the tracks associated with this movie
41256 * @see ISO/IEC 14496-12:2012(E), section 8.2.1
41257 */
41258moov = function(tracks) {
41259  var
41260    i = tracks.length,
41261    boxes = [];
41262
41263  while (i--) {
41264    boxes[i] = trak(tracks[i]);
41265  }
41266
41267  return box.apply(null, [types.moov, mvhd(0xffffffff)].concat(boxes).concat(mvex(tracks)));
41268};
41269mvex = function(tracks) {
41270  var
41271    i = tracks.length,
41272    boxes = [];
41273
41274  while (i--) {
41275    boxes[i] = trex(tracks[i]);
41276  }
41277  return box.apply(null, [types.mvex].concat(boxes));
41278};
41279mvhd = function(duration) {
41280  var
41281    bytes = new Uint8Array([
41282      0x00, // version 0
41283      0x00, 0x00, 0x00, // flags
41284      0x00, 0x00, 0x00, 0x01, // creation_time
41285      0x00, 0x00, 0x00, 0x02, // modification_time
41286      0x00, 0x01, 0x5f, 0x90, // timescale, 90,000 "ticks" per second
41287      (duration & 0xFF000000) >> 24,
41288      (duration & 0xFF0000) >> 16,
41289      (duration & 0xFF00) >> 8,
41290      duration & 0xFF, // duration
41291      0x00, 0x01, 0x00, 0x00, // 1.0 rate
41292      0x01, 0x00, // 1.0 volume
41293      0x00, 0x00, // reserved
41294      0x00, 0x00, 0x00, 0x00, // reserved
41295      0x00, 0x00, 0x00, 0x00, // reserved
41296      0x00, 0x01, 0x00, 0x00,
41297      0x00, 0x00, 0x00, 0x00,
41298      0x00, 0x00, 0x00, 0x00,
41299      0x00, 0x00, 0x00, 0x00,
41300      0x00, 0x01, 0x00, 0x00,
41301      0x00, 0x00, 0x00, 0x00,
41302      0x00, 0x00, 0x00, 0x00,
41303      0x00, 0x00, 0x00, 0x00,
41304      0x40, 0x00, 0x00, 0x00, // transformation: unity matrix
41305      0x00, 0x00, 0x00, 0x00,
41306      0x00, 0x00, 0x00, 0x00,
41307      0x00, 0x00, 0x00, 0x00,
41308      0x00, 0x00, 0x00, 0x00,
41309      0x00, 0x00, 0x00, 0x00,
41310      0x00, 0x00, 0x00, 0x00, // pre_defined
41311      0xff, 0xff, 0xff, 0xff // next_track_ID
41312    ]);
41313  return box(types.mvhd, bytes);
41314};
41315
41316sdtp = function(track) {
41317  var
41318    samples = track.samples || [],
41319    bytes = new Uint8Array(4 + samples.length),
41320    flags,
41321    i;
41322
41323  // leave the full box header (4 bytes) all zero
41324
41325  // write the sample table
41326  for (i = 0; i < samples.length; i++) {
41327    flags = samples[i].flags;
41328
41329    bytes[i + 4] = (flags.dependsOn << 4) |
41330      (flags.isDependedOn << 2) |
41331      (flags.hasRedundancy);
41332  }
41333
41334  return box(types.sdtp,
41335             bytes);
41336};
41337
41338stbl = function(track) {
41339  return box(types.stbl,
41340             stsd(track),
41341             box(types.stts, STTS),
41342             box(types.stsc, STSC),
41343             box(types.stsz, STSZ),
41344             box(types.stco, STCO));
41345};
41346
41347(function() {
41348  var videoSample, audioSample;
41349
41350  stsd = function(track) {
41351
41352    return box(types.stsd, new Uint8Array([
41353      0x00, // version 0
41354      0x00, 0x00, 0x00, // flags
41355      0x00, 0x00, 0x00, 0x01
41356    ]), track.type === 'video' ? videoSample(track) : audioSample(track));
41357  };
41358
41359  videoSample = function(track) {
41360    var
41361      sps = track.sps || [],
41362      pps = track.pps || [],
41363      sequenceParameterSets = [],
41364      pictureParameterSets = [],
41365      i;
41366
41367    // assemble the SPSs
41368    for (i = 0; i < sps.length; i++) {
41369      sequenceParameterSets.push((sps[i].byteLength & 0xFF00) >>> 8);
41370      sequenceParameterSets.push((sps[i].byteLength & 0xFF)); // sequenceParameterSetLength
41371      sequenceParameterSets = sequenceParameterSets.concat(Array.prototype.slice.call(sps[i])); // SPS
41372    }
41373
41374    // assemble the PPSs
41375    for (i = 0; i < pps.length; i++) {
41376      pictureParameterSets.push((pps[i].byteLength & 0xFF00) >>> 8);
41377      pictureParameterSets.push((pps[i].byteLength & 0xFF));
41378      pictureParameterSets = pictureParameterSets.concat(Array.prototype.slice.call(pps[i]));
41379    }
41380
41381    return box(types.avc1, new Uint8Array([
41382      0x00, 0x00, 0x00,
41383      0x00, 0x00, 0x00, // reserved
41384      0x00, 0x01, // data_reference_index
41385      0x00, 0x00, // pre_defined
41386      0x00, 0x00, // reserved
41387      0x00, 0x00, 0x00, 0x00,
41388      0x00, 0x00, 0x00, 0x00,
41389      0x00, 0x00, 0x00, 0x00, // pre_defined
41390      (track.width & 0xff00) >> 8,
41391      track.width & 0xff, // width
41392      (track.height & 0xff00) >> 8,
41393      track.height & 0xff, // height
41394      0x00, 0x48, 0x00, 0x00, // horizresolution
41395      0x00, 0x48, 0x00, 0x00, // vertresolution
41396      0x00, 0x00, 0x00, 0x00, // reserved
41397      0x00, 0x01, // frame_count
41398      0x13,
41399      0x76, 0x69, 0x64, 0x65,
41400      0x6f, 0x6a, 0x73, 0x2d,
41401      0x63, 0x6f, 0x6e, 0x74,
41402      0x72, 0x69, 0x62, 0x2d,
41403      0x68, 0x6c, 0x73, 0x00,
41404      0x00, 0x00, 0x00, 0x00,
41405      0x00, 0x00, 0x00, 0x00,
41406      0x00, 0x00, 0x00, // compressorname
41407      0x00, 0x18, // depth = 24
41408      0x11, 0x11 // pre_defined = -1
41409    ]), box(types.avcC, new Uint8Array([
41410      0x01, // configurationVersion
41411      track.profileIdc, // AVCProfileIndication
41412      track.profileCompatibility, // profile_compatibility
41413      track.levelIdc, // AVCLevelIndication
41414      0xff // lengthSizeMinusOne, hard-coded to 4 bytes
41415    ].concat([
41416      sps.length // numOfSequenceParameterSets
41417    ]).concat(sequenceParameterSets).concat([
41418      pps.length // numOfPictureParameterSets
41419    ]).concat(pictureParameterSets))), // "PPS"
41420            box(types.btrt, new Uint8Array([
41421              0x00, 0x1c, 0x9c, 0x80, // bufferSizeDB
41422              0x00, 0x2d, 0xc6, 0xc0, // maxBitrate
41423              0x00, 0x2d, 0xc6, 0xc0
41424            ])) // avgBitrate
41425              );
41426  };
41427
41428  audioSample = function(track) {
41429    return box(types.mp4a, new Uint8Array([
41430
41431      // SampleEntry, ISO/IEC 14496-12
41432      0x00, 0x00, 0x00,
41433      0x00, 0x00, 0x00, // reserved
41434      0x00, 0x01, // data_reference_index
41435
41436      // AudioSampleEntry, ISO/IEC 14496-12
41437      0x00, 0x00, 0x00, 0x00, // reserved
41438      0x00, 0x00, 0x00, 0x00, // reserved
41439      (track.channelcount & 0xff00) >> 8,
41440      (track.channelcount & 0xff), // channelcount
41441
41442      (track.samplesize & 0xff00) >> 8,
41443      (track.samplesize & 0xff), // samplesize
41444      0x00, 0x00, // pre_defined
41445      0x00, 0x00, // reserved
41446
41447      (track.samplerate & 0xff00) >> 8,
41448      (track.samplerate & 0xff),
41449      0x00, 0x00 // samplerate, 16.16
41450
41451      // MP4AudioSampleEntry, ISO/IEC 14496-14
41452    ]), esds(track));
41453  };
41454}());
41455
41456tkhd = function(track) {
41457  var result = new Uint8Array([
41458    0x00, // version 0
41459    0x00, 0x00, 0x07, // flags
41460    0x00, 0x00, 0x00, 0x00, // creation_time
41461    0x00, 0x00, 0x00, 0x00, // modification_time
41462    (track.id & 0xFF000000) >> 24,
41463    (track.id & 0xFF0000) >> 16,
41464    (track.id & 0xFF00) >> 8,
41465    track.id & 0xFF, // track_ID
41466    0x00, 0x00, 0x00, 0x00, // reserved
41467    (track.duration & 0xFF000000) >> 24,
41468    (track.duration & 0xFF0000) >> 16,
41469    (track.duration & 0xFF00) >> 8,
41470    track.duration & 0xFF, // duration
41471    0x00, 0x00, 0x00, 0x00,
41472    0x00, 0x00, 0x00, 0x00, // reserved
41473    0x00, 0x00, // layer
41474    0x00, 0x00, // alternate_group
41475    0x01, 0x00, // non-audio track volume
41476    0x00, 0x00, // reserved
41477    0x00, 0x01, 0x00, 0x00,
41478    0x00, 0x00, 0x00, 0x00,
41479    0x00, 0x00, 0x00, 0x00,
41480    0x00, 0x00, 0x00, 0x00,
41481    0x00, 0x01, 0x00, 0x00,
41482    0x00, 0x00, 0x00, 0x00,
41483    0x00, 0x00, 0x00, 0x00,
41484    0x00, 0x00, 0x00, 0x00,
41485    0x40, 0x00, 0x00, 0x00, // transformation: unity matrix
41486    (track.width & 0xFF00) >> 8,
41487    track.width & 0xFF,
41488    0x00, 0x00, // width
41489    (track.height & 0xFF00) >> 8,
41490    track.height & 0xFF,
41491    0x00, 0x00 // height
41492  ]);
41493
41494  return box(types.tkhd, result);
41495};
41496
41497/**
41498 * Generate a track fragment (traf) box. A traf box collects metadata
41499 * about tracks in a movie fragment (moof) box.
41500 */
41501traf = function(track) {
41502  var trackFragmentHeader, trackFragmentDecodeTime, trackFragmentRun,
41503      sampleDependencyTable, dataOffset,
41504      upperWordBaseMediaDecodeTime, lowerWordBaseMediaDecodeTime;
41505
41506  trackFragmentHeader = box(types.tfhd, new Uint8Array([
41507    0x00, // version 0
41508    0x00, 0x00, 0x3a, // flags
41509    (track.id & 0xFF000000) >> 24,
41510    (track.id & 0xFF0000) >> 16,
41511    (track.id & 0xFF00) >> 8,
41512    (track.id & 0xFF), // track_ID
41513    0x00, 0x00, 0x00, 0x01, // sample_description_index
41514    0x00, 0x00, 0x00, 0x00, // default_sample_duration
41515    0x00, 0x00, 0x00, 0x00, // default_sample_size
41516    0x00, 0x00, 0x00, 0x00  // default_sample_flags
41517  ]));
41518
41519  upperWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime / (UINT32_MAX + 1));
41520  lowerWordBaseMediaDecodeTime = Math.floor(track.baseMediaDecodeTime % (UINT32_MAX + 1));
41521
41522  trackFragmentDecodeTime = box(types.tfdt, new Uint8Array([
41523    0x01, // version 1
41524    0x00, 0x00, 0x00, // flags
41525    // baseMediaDecodeTime
41526    (upperWordBaseMediaDecodeTime >>> 24) & 0xFF,
41527    (upperWordBaseMediaDecodeTime >>> 16) & 0xFF,
41528    (upperWordBaseMediaDecodeTime >>>  8) & 0xFF,
41529    upperWordBaseMediaDecodeTime & 0xFF,
41530    (lowerWordBaseMediaDecodeTime >>> 24) & 0xFF,
41531    (lowerWordBaseMediaDecodeTime >>> 16) & 0xFF,
41532    (lowerWordBaseMediaDecodeTime >>>  8) & 0xFF,
41533    lowerWordBaseMediaDecodeTime & 0xFF
41534  ]));
41535
41536  // the data offset specifies the number of bytes from the start of
41537  // the containing moof to the first payload byte of the associated
41538  // mdat
41539  dataOffset = (32 + // tfhd
41540                20 + // tfdt
41541                8 +  // traf header
41542                16 + // mfhd
41543                8 +  // moof header
41544                8);  // mdat header
41545
41546  // audio tracks require less metadata
41547  if (track.type === 'audio') {
41548    trackFragmentRun = trun(track, dataOffset);
41549    return box(types.traf,
41550               trackFragmentHeader,
41551               trackFragmentDecodeTime,
41552               trackFragmentRun);
41553  }
41554
41555  // video tracks should contain an independent and disposable samples
41556  // box (sdtp)
41557  // generate one and adjust offsets to match
41558  sampleDependencyTable = sdtp(track);
41559  trackFragmentRun = trun(track,
41560                          sampleDependencyTable.length + dataOffset);
41561  return box(types.traf,
41562             trackFragmentHeader,
41563             trackFragmentDecodeTime,
41564             trackFragmentRun,
41565             sampleDependencyTable);
41566};
41567
41568/**
41569 * Generate a track box.
41570 * @param track {object} a track definition
41571 * @return {Uint8Array} the track box
41572 */
41573trak = function(track) {
41574  track.duration = track.duration || 0xffffffff;
41575  return box(types.trak,
41576             tkhd(track),
41577             mdia(track));
41578};
41579
41580trex = function(track) {
41581  var result = new Uint8Array([
41582    0x00, // version 0
41583    0x00, 0x00, 0x00, // flags
41584    (track.id & 0xFF000000) >> 24,
41585    (track.id & 0xFF0000) >> 16,
41586    (track.id & 0xFF00) >> 8,
41587    (track.id & 0xFF), // track_ID
41588    0x00, 0x00, 0x00, 0x01, // default_sample_description_index
41589    0x00, 0x00, 0x00, 0x00, // default_sample_duration
41590    0x00, 0x00, 0x00, 0x00, // default_sample_size
41591    0x00, 0x01, 0x00, 0x01 // default_sample_flags
41592  ]);
41593  // the last two bytes of default_sample_flags is the sample
41594  // degradation priority, a hint about the importance of this sample
41595  // relative to others. Lower the degradation priority for all sample
41596  // types other than video.
41597  if (track.type !== 'video') {
41598    result[result.length - 1] = 0x00;
41599  }
41600
41601  return box(types.trex, result);
41602};
41603
41604(function() {
41605  var audioTrun, videoTrun, trunHeader;
41606
41607  // This method assumes all samples are uniform. That is, if a
41608  // duration is present for the first sample, it will be present for
41609  // all subsequent samples.
41610  // see ISO/IEC 14496-12:2012, Section 8.8.8.1
41611  trunHeader = function(samples, offset) {
41612    var durationPresent = 0, sizePresent = 0,
41613        flagsPresent = 0, compositionTimeOffset = 0;
41614
41615    // trun flag constants
41616    if (samples.length) {
41617      if (samples[0].duration !== undefined) {
41618        durationPresent = 0x1;
41619      }
41620      if (samples[0].size !== undefined) {
41621        sizePresent = 0x2;
41622      }
41623      if (samples[0].flags !== undefined) {
41624        flagsPresent = 0x4;
41625      }
41626      if (samples[0].compositionTimeOffset !== undefined) {
41627        compositionTimeOffset = 0x8;
41628      }
41629    }
41630
41631    return [
41632      0x00, // version 0
41633      0x00,
41634      durationPresent | sizePresent | flagsPresent | compositionTimeOffset,
41635      0x01, // flags
41636      (samples.length & 0xFF000000) >>> 24,
41637      (samples.length & 0xFF0000) >>> 16,
41638      (samples.length & 0xFF00) >>> 8,
41639      samples.length & 0xFF, // sample_count
41640      (offset & 0xFF000000) >>> 24,
41641      (offset & 0xFF0000) >>> 16,
41642      (offset & 0xFF00) >>> 8,
41643      offset & 0xFF // data_offset
41644    ];
41645  };
41646
41647  videoTrun = function(track, offset) {
41648    var bytes, samples, sample, i;
41649
41650    samples = track.samples || [];
41651    offset += 8 + 12 + (16 * samples.length);
41652
41653    bytes = trunHeader(samples, offset);
41654
41655    for (i = 0; i < samples.length; i++) {
41656      sample = samples[i];
41657      bytes = bytes.concat([
41658        (sample.duration & 0xFF000000) >>> 24,
41659        (sample.duration & 0xFF0000) >>> 16,
41660        (sample.duration & 0xFF00) >>> 8,
41661        sample.duration & 0xFF, // sample_duration
41662        (sample.size & 0xFF000000) >>> 24,
41663        (sample.size & 0xFF0000) >>> 16,
41664        (sample.size & 0xFF00) >>> 8,
41665        sample.size & 0xFF, // sample_size
41666        (sample.flags.isLeading << 2) | sample.flags.dependsOn,
41667        (sample.flags.isDependedOn << 6) |
41668          (sample.flags.hasRedundancy << 4) |
41669          (sample.flags.paddingValue << 1) |
41670          sample.flags.isNonSyncSample,
41671        sample.flags.degradationPriority & 0xF0 << 8,
41672        sample.flags.degradationPriority & 0x0F, // sample_flags
41673        (sample.compositionTimeOffset & 0xFF000000) >>> 24,
41674        (sample.compositionTimeOffset & 0xFF0000) >>> 16,
41675        (sample.compositionTimeOffset & 0xFF00) >>> 8,
41676        sample.compositionTimeOffset & 0xFF // sample_composition_time_offset
41677      ]);
41678    }
41679    return box(types.trun, new Uint8Array(bytes));
41680  };
41681
41682  audioTrun = function(track, offset) {
41683    var bytes, samples, sample, i;
41684
41685    samples = track.samples || [];
41686    offset += 8 + 12 + (8 * samples.length);
41687
41688    bytes = trunHeader(samples, offset);
41689
41690    for (i = 0; i < samples.length; i++) {
41691      sample = samples[i];
41692      bytes = bytes.concat([
41693        (sample.duration & 0xFF000000) >>> 24,
41694        (sample.duration & 0xFF0000) >>> 16,
41695        (sample.duration & 0xFF00) >>> 8,
41696        sample.duration & 0xFF, // sample_duration
41697        (sample.size & 0xFF000000) >>> 24,
41698        (sample.size & 0xFF0000) >>> 16,
41699        (sample.size & 0xFF00) >>> 8,
41700        sample.size & 0xFF]); // sample_size
41701    }
41702
41703    return box(types.trun, new Uint8Array(bytes));
41704  };
41705
41706  trun = function(track, offset) {
41707    if (track.type === 'audio') {
41708      return audioTrun(track, offset);
41709    }
41710
41711    return videoTrun(track, offset);
41712  };
41713}());
41714
41715module.exports = {
41716  ftyp: ftyp,
41717  mdat: mdat,
41718  moof: moof,
41719  moov: moov,
41720  initSegment: function(tracks) {
41721    var
41722      fileType = ftyp(),
41723      movie = moov(tracks),
41724      result;
41725
41726    result = new Uint8Array(fileType.byteLength + movie.byteLength);
41727    result.set(fileType);
41728    result.set(movie, fileType.byteLength);
41729    return result;
41730  }
41731};
41732
41733},{}],57:[function(require,module,exports){
41734/**
41735 * mux.js
41736 *
41737 * Copyright (c) 2015 Brightcove
41738 * All rights reserved.
41739 *
41740 * Utilities to detect basic properties and metadata about MP4s.
41741 */
41742'use strict';
41743
41744var findBox, parseType, timescale, startTime;
41745
41746// Find the data for a box specified by its path
41747findBox = function(data, path) {
41748  var results = [],
41749      i, size, type, end, subresults;
41750
41751  if (!path.length) {
41752    // short-circuit the search for empty paths
41753    return null;
41754  }
41755
41756  for (i = 0; i < data.byteLength;) {
41757    size  = data[i]     << 24;
41758    size |= data[i + 1] << 16;
41759    size |= data[i + 2] << 8;
41760    size |= data[i + 3];
41761
41762    type = parseType(data.subarray(i + 4, i + 8));
41763
41764    end = size > 1 ? i + size : data.byteLength;
41765
41766    if (type === path[0]) {
41767      if (path.length === 1) {
41768        // this is the end of the path and we've found the box we were
41769        // looking for
41770        results.push(data.subarray(i + 8, end));
41771      } else {
41772        // recursively search for the next box along the path
41773        subresults = findBox(data.subarray(i + 8, end), path.slice(1));
41774        if (subresults.length) {
41775          results = results.concat(subresults);
41776        }
41777      }
41778    }
41779    i = end;
41780  }
41781
41782  // we've finished searching all of data
41783  return results;
41784};
41785
41786/**
41787 * Returns the string representation of an ASCII encoded four byte buffer.
41788 * @param buffer {Uint8Array} a four-byte buffer to translate
41789 * @return {string} the corresponding string
41790 */
41791parseType = function(buffer) {
41792  var result = '';
41793  result += String.fromCharCode(buffer[0]);
41794  result += String.fromCharCode(buffer[1]);
41795  result += String.fromCharCode(buffer[2]);
41796  result += String.fromCharCode(buffer[3]);
41797  return result;
41798};
41799
41800/**
41801 * Parses an MP4 initialization segment and extracts the timescale
41802 * values for any declared tracks. Timescale values indicate the
41803 * number of clock ticks per second to assume for time-based values
41804 * elsewhere in the MP4.
41805 *
41806 * To determine the start time of an MP4, you need two pieces of
41807 * information: the timescale unit and the earliest base media decode
41808 * time. Multiple timescales can be specified within an MP4 but the
41809 * base media decode time is always expressed in the timescale from
41810 * the media header box for the track:
41811 * ```
41812 * moov > trak > mdia > mdhd.timescale
41813 * ```
41814 * @param init {Uint8Array} the bytes of the init segment
41815 * @return {object} a hash of track ids to timescale values or null if
41816 * the init segment is malformed.
41817 */
41818timescale = function(init) {
41819  var
41820    result = {},
41821    traks = findBox(init, ['moov', 'trak']);
41822
41823  // mdhd timescale
41824  return traks.reduce(function(result, trak) {
41825    var tkhd, version, index, id, mdhd;
41826
41827    tkhd = findBox(trak, ['tkhd'])[0];
41828    if (!tkhd) {
41829      return null;
41830    }
41831    version = tkhd[0];
41832    index = version === 0 ? 12 : 20;
41833    id = tkhd[index]     << 24 |
41834         tkhd[index + 1] << 16 |
41835         tkhd[index + 2] <<  8 |
41836         tkhd[index + 3];
41837
41838    mdhd = findBox(trak, ['mdia', 'mdhd'])[0];
41839    if (!mdhd) {
41840      return null;
41841    }
41842    version = mdhd[0];
41843    index = version === 0 ? 12 : 20;
41844    result[id] = mdhd[index]     << 24 |
41845                 mdhd[index + 1] << 16 |
41846                 mdhd[index + 2] <<  8 |
41847                 mdhd[index + 3];
41848    return result;
41849  }, result);
41850};
41851
41852/**
41853 * Determine the base media decode start time, in seconds, for an MP4
41854 * fragment. If multiple fragments are specified, the earliest time is
41855 * returned.
41856 *
41857 * The base media decode time can be parsed from track fragment
41858 * metadata:
41859 * ```
41860 * moof > traf > tfdt.baseMediaDecodeTime
41861 * ```
41862 * It requires the timescale value from the mdhd to interpret.
41863 *
41864 * @param timescale {object} a hash of track ids to timescale values.
41865 * @return {number} the earliest base media decode start time for the
41866 * fragment, in seconds
41867 */
41868startTime = function(timescale, fragment) {
41869  var trafs, baseTimes, result;
41870
41871  // we need info from two childrend of each track fragment box
41872  trafs = findBox(fragment, ['moof', 'traf']);
41873
41874  // determine the start times for each track
41875  baseTimes = [].concat.apply([], trafs.map(function(traf) {
41876    return findBox(traf, ['tfhd']).map(function(tfhd) {
41877      var id, scale, baseTime;
41878
41879      // get the track id from the tfhd
41880      id = tfhd[4] << 24 |
41881           tfhd[5] << 16 |
41882           tfhd[6] << 8 |
41883           tfhd[7];
41884      // assume a 90kHz clock if no timescale was specified
41885      scale = timescale[id] || 90e3;
41886
41887      // get the base media decode time from the tfdt
41888      baseTime = findBox(traf, ['tfdt']).map(function(tfdt) {
41889        var version, result;
41890
41891        version = tfdt[0];
41892        result = tfdt[4] << 24 |
41893                 tfdt[5] << 16 |
41894                 tfdt[6] <<  8 |
41895                 tfdt[7];
41896        if (version ===  1) {
41897          result *= Math.pow(2, 32);
41898          result += tfdt[8]  << 24 |
41899                    tfdt[9]  << 16 |
41900                    tfdt[10] <<  8 |
41901                    tfdt[11];
41902        }
41903        return result;
41904      })[0];
41905      baseTime = baseTime || Infinity;
41906
41907      // convert base time to seconds
41908      return baseTime / scale;
41909    });
41910  }));
41911
41912  // return the minimum
41913  result = Math.min.apply(null, baseTimes);
41914  return isFinite(result) ? result : 0;
41915};
41916
41917module.exports = {
41918  parseType: parseType,
41919  timescale: timescale,
41920  startTime: startTime
41921};
41922
41923},{}],58:[function(require,module,exports){
41924/**
41925 * mux.js
41926 *
41927 * Copyright (c) 2015 Brightcove
41928 * All rights reserved.
41929 *
41930 * A stream-based mp2t to mp4 converter. This utility can be used to
41931 * deliver mp4s to a SourceBuffer on platforms that support native
41932 * Media Source Extensions.
41933 */
41934'use strict';
41935
41936var Stream = require('../utils/stream.js');
41937var mp4 = require('./mp4-generator.js');
41938var m2ts = require('../m2ts/m2ts.js');
41939var AdtsStream = require('../codecs/adts.js');
41940var H264Stream = require('../codecs/h264').H264Stream;
41941var AacStream = require('../aac');
41942var coneOfSilence = require('../data/silence');
41943var clock = require('../utils/clock');
41944
41945// constants
41946var AUDIO_PROPERTIES = [
41947  'audioobjecttype',
41948  'channelcount',
41949  'samplerate',
41950  'samplingfrequencyindex',
41951  'samplesize'
41952];
41953
41954var VIDEO_PROPERTIES = [
41955  'width',
41956  'height',
41957  'profileIdc',
41958  'levelIdc',
41959  'profileCompatibility'
41960];
41961
41962var ONE_SECOND_IN_TS = 90000; // 90kHz clock
41963
41964// object types
41965var VideoSegmentStream, AudioSegmentStream, Transmuxer, CoalesceStream;
41966
41967// Helper functions
41968var
41969  createDefaultSample,
41970  isLikelyAacData,
41971  collectDtsInfo,
41972  clearDtsInfo,
41973  calculateTrackBaseMediaDecodeTime,
41974  arrayEquals,
41975  sumFrameByteLengths;
41976
41977/**
41978 * Default sample object
41979 * see ISO/IEC 14496-12:2012, section 8.6.4.3
41980 */
41981createDefaultSample = function() {
41982  return {
41983    size: 0,
41984    flags: {
41985      isLeading: 0,
41986      dependsOn: 1,
41987      isDependedOn: 0,
41988      hasRedundancy: 0,
41989      degradationPriority: 0
41990    }
41991  };
41992};
41993
41994isLikelyAacData = function(data) {
41995  if ((data[0] === 'I'.charCodeAt(0)) &&
41996      (data[1] === 'D'.charCodeAt(0)) &&
41997      (data[2] === '3'.charCodeAt(0))) {
41998    return true;
41999  }
42000  return false;
42001};
42002
42003/**
42004 * Compare two arrays (even typed) for same-ness
42005 */
42006arrayEquals = function(a, b) {
42007  var
42008    i;
42009
42010  if (a.length !== b.length) {
42011    return false;
42012  }
42013
42014  // compare the value of each element in the array
42015  for (i = 0; i < a.length; i++) {
42016    if (a[i] !== b[i]) {
42017      return false;
42018    }
42019  }
42020
42021  return true;
42022};
42023
42024/**
42025 * Sum the `byteLength` properties of the data in each AAC frame
42026 */
42027sumFrameByteLengths = function(array) {
42028  var
42029    i,
42030    currentObj,
42031    sum = 0;
42032
42033  // sum the byteLength's all each nal unit in the frame
42034  for (i = 0; i < array.length; i++) {
42035    currentObj = array[i];
42036    sum += currentObj.data.byteLength;
42037  }
42038
42039  return sum;
42040};
42041
42042/**
42043 * Constructs a single-track, ISO BMFF media segment from AAC data
42044 * events. The output of this stream can be fed to a SourceBuffer
42045 * configured with a suitable initialization segment.
42046 */
42047AudioSegmentStream = function(track) {
42048  var
42049    adtsFrames = [],
42050    sequenceNumber = 0,
42051    earliestAllowedDts = 0,
42052    audioAppendStartTs = 0,
42053    videoBaseMediaDecodeTime = Infinity;
42054
42055  AudioSegmentStream.prototype.init.call(this);
42056
42057  this.push = function(data) {
42058    collectDtsInfo(track, data);
42059
42060    if (track) {
42061      AUDIO_PROPERTIES.forEach(function(prop) {
42062        track[prop] = data[prop];
42063      });
42064    }
42065
42066    // buffer audio data until end() is called
42067    adtsFrames.push(data);
42068  };
42069
42070  this.setEarliestDts = function(earliestDts) {
42071    earliestAllowedDts = earliestDts - track.timelineStartInfo.baseMediaDecodeTime;
42072  };
42073
42074  this.setVideoBaseMediaDecodeTime = function(baseMediaDecodeTime) {
42075    videoBaseMediaDecodeTime = baseMediaDecodeTime;
42076  };
42077
42078  this.setAudioAppendStart = function(timestamp) {
42079    audioAppendStartTs = timestamp;
42080  };
42081
42082  this.flush = function() {
42083    var
42084      frames,
42085      moof,
42086      mdat,
42087      boxes;
42088
42089    // return early if no audio data has been observed
42090    if (adtsFrames.length === 0) {
42091      this.trigger('done', 'AudioSegmentStream');
42092      return;
42093    }
42094
42095    frames = this.trimAdtsFramesByEarliestDts_(adtsFrames);
42096    track.baseMediaDecodeTime = calculateTrackBaseMediaDecodeTime(track);
42097
42098    this.prefixWithSilence_(track, frames);
42099
42100    // we have to build the index from byte locations to
42101    // samples (that is, adts frames) in the audio data
42102    track.samples = this.generateSampleTable_(frames);
42103
42104    // concatenate the audio data to constuct the mdat
42105    mdat = mp4.mdat(this.concatenateFrameData_(frames));
42106
42107    adtsFrames = [];
42108
42109    moof = mp4.moof(sequenceNumber, [track]);
42110    boxes = new Uint8Array(moof.byteLength + mdat.byteLength);
42111
42112    // bump the sequence number for next time
42113    sequenceNumber++;
42114
42115    boxes.set(moof);
42116    boxes.set(mdat, moof.byteLength);
42117
42118    clearDtsInfo(track);
42119
42120    this.trigger('data', {track: track, boxes: boxes});
42121    this.trigger('done', 'AudioSegmentStream');
42122  };
42123
42124  // Possibly pad (prefix) the audio track with silence if appending this track
42125  // would lead to the introduction of a gap in the audio buffer
42126  this.prefixWithSilence_ = function(track, frames) {
42127    var
42128      baseMediaDecodeTimeTs,
42129      frameDuration = 0,
42130      audioGapDuration = 0,
42131      audioFillFrameCount = 0,
42132      audioFillDuration = 0,
42133      silentFrame,
42134      i;
42135
42136    if (!frames.length) {
42137      return;
42138    }
42139
42140    baseMediaDecodeTimeTs = clock.audioTsToVideoTs(track.baseMediaDecodeTime, track.samplerate);
42141    // determine frame clock duration based on sample rate, round up to avoid overfills
42142    frameDuration = Math.ceil(ONE_SECOND_IN_TS / (track.samplerate / 1024));
42143
42144    if (audioAppendStartTs && videoBaseMediaDecodeTime) {
42145      // insert the shortest possible amount (audio gap or audio to video gap)
42146      audioGapDuration =
42147        baseMediaDecodeTimeTs - Math.max(audioAppendStartTs, videoBaseMediaDecodeTime);
42148      // number of full frames in the audio gap
42149      audioFillFrameCount = Math.floor(audioGapDuration / frameDuration);
42150      audioFillDuration = audioFillFrameCount * frameDuration;
42151    }
42152
42153    // don't attempt to fill gaps smaller than a single frame or larger
42154    // than a half second
42155    if (audioFillFrameCount < 1 || audioFillDuration > ONE_SECOND_IN_TS / 2) {
42156      return;
42157    }
42158
42159    silentFrame = coneOfSilence[track.samplerate];
42160
42161    if (!silentFrame) {
42162      // we don't have a silent frame pregenerated for the sample rate, so use a frame
42163      // from the content instead
42164      silentFrame = frames[0].data;
42165    }
42166
42167    for (i = 0; i < audioFillFrameCount; i++) {
42168      frames.splice(i, 0, {
42169        data: silentFrame
42170      });
42171    }
42172
42173    track.baseMediaDecodeTime -=
42174      Math.floor(clock.videoTsToAudioTs(audioFillDuration, track.samplerate));
42175  };
42176
42177  // If the audio segment extends before the earliest allowed dts
42178  // value, remove AAC frames until starts at or after the earliest
42179  // allowed DTS so that we don't end up with a negative baseMedia-
42180  // DecodeTime for the audio track
42181  this.trimAdtsFramesByEarliestDts_ = function(adtsFrames) {
42182    if (track.minSegmentDts >= earliestAllowedDts) {
42183      return adtsFrames;
42184    }
42185
42186    // We will need to recalculate the earliest segment Dts
42187    track.minSegmentDts = Infinity;
42188
42189    return adtsFrames.filter(function(currentFrame) {
42190      // If this is an allowed frame, keep it and record it's Dts
42191      if (currentFrame.dts >= earliestAllowedDts) {
42192        track.minSegmentDts = Math.min(track.minSegmentDts, currentFrame.dts);
42193        track.minSegmentPts = track.minSegmentDts;
42194        return true;
42195      }
42196      // Otherwise, discard it
42197      return false;
42198    });
42199  };
42200
42201  // generate the track's raw mdat data from an array of frames
42202  this.generateSampleTable_ = function(frames) {
42203    var
42204      i,
42205      currentFrame,
42206      samples = [];
42207
42208    for (i = 0; i < frames.length; i++) {
42209      currentFrame = frames[i];
42210      samples.push({
42211        size: currentFrame.data.byteLength,
42212        duration: 1024 // For AAC audio, all samples contain 1024 samples
42213      });
42214    }
42215    return samples;
42216  };
42217
42218  // generate the track's sample table from an array of frames
42219  this.concatenateFrameData_ = function(frames) {
42220    var
42221      i,
42222      currentFrame,
42223      dataOffset = 0,
42224      data = new Uint8Array(sumFrameByteLengths(frames));
42225
42226    for (i = 0; i < frames.length; i++) {
42227      currentFrame = frames[i];
42228
42229      data.set(currentFrame.data, dataOffset);
42230      dataOffset += currentFrame.data.byteLength;
42231    }
42232    return data;
42233  };
42234};
42235
42236AudioSegmentStream.prototype = new Stream();
42237
42238/**
42239 * Constructs a single-track, ISO BMFF media segment from H264 data
42240 * events. The output of this stream can be fed to a SourceBuffer
42241 * configured with a suitable initialization segment.
42242 * @param track {object} track metadata configuration
42243 *
42243/
42244VideoSegmentStream = function(track) {
42245  var
42246    sequenceNumber = 0,
42247    nalUnits = [],
42248    config,
42249    pps;
42250
42251  VideoSegmentStream.prototype.init.call(this);
42252
42253  delete track.minPTS;
42254
42255  this.gopCache_ = [];
42256
42257  this.push = function(nalUnit) {
42258    collectDtsInfo(track, nalUnit);
42259
42260    // record the track config
42261    if (nalUnit.nalUnitType === 'seq_parameter_set_rbsp' && !config) {
42262      config = nalUnit.config;
42263      track.sps = [nalUnit.data];
42264
42265      VIDEO_PROPERTIES.forEach(function(prop) {
42266        track[prop] = config[prop];
42267      }, this);
42268    }
42269
42270    if (nalUnit.nalUnitType === 'pic_parameter_set_rbsp' &&
42271        !pps) {
vendor: 3,264 bytes, lines 42272-42369
42272      pps = nalUnit.data;
42273      track.pps = [nalUnit.data];
42274    }
42275
42276    // buffer video until flush() is called
42277    nalUnits.push(nalUnit);
42278  };
42279
42280  this.flush = function() {
42281    var
42282      frames,
42283      gopForFusion,
42284      gops,
42285      moof,
42286      mdat,
42287      boxes;
42288
42289    // Throw away nalUnits at the start of the byte stream until
42290    // we find the first AUD
42291    while (nalUnits.length) {
42292      if (nalUnits[0].nalUnitType === 'access_unit_delimiter_rbsp') {
42293        break;
42294      }
42295      nalUnits.shift();
42296    }
42297
42298    // Return early if no video data has been observed
42299    if (nalUnits.length === 0) {
42300      this.resetStream_();
42301      this.trigger('done', 'VideoSegmentStream');
42302      return;
42303    }
42304
42305    // Organize the raw nal-units into arrays that represent
42306    // higher-level constructs such as frames and gops
42307    // (group-of-pictures)
42308    frames = this.groupNalsIntoFrames_(nalUnits);
42309    gops = this.groupFramesIntoGops_(frames);
42310
42311    // If the first frame of this fragment is not a keyframe we have
42312    // a problem since MSE (on Chrome) requires a leading keyframe.
42313    //
42314    // We have two approaches to repairing this situation:
42315    // 1) GOP-FUSION:
42316    //    This is where we keep track of the GOPS (group-of-pictures)
42317    //    from previous fragments and attempt to find one that we can
42318    //    prepend to the current fragment in order to create a valid
42319    //    fragment.
42320    // 2) KEYFRAME-PULLING:
42321    //    Here we search for the first keyframe in the fragment and
42322    //    throw away all the frames between the start of the fragment
42323    //    and that keyframe. We then extend the duration and pull the
42324    //    PTS of the keyframe forward so that it covers the time range
42325    //    of the frames that were disposed of.
42326    //
42327    // #1 is far prefereable over #2 which can cause "stuttering" but
42328    // requires more things to be just right.
42329    if (!gops[0][0].keyFrame) {
42330      // Search for a gop for fusion from our gopCache
42331      gopForFusion = this.getGopForFusion_(nalUnits[0], track);
42332
42333      if (gopForFusion) {
42334        gops.unshift(gopForFusion);
42335        // Adjust Gops' metadata to account for the inclusion of the
42336        // new gop at the beginning
42337        gops.byteLength += gopForFusion.byteLength;
42338        gops.nalCount += gopForFusion.nalCount;
42339        gops.pts = gopForFusion.pts;
42340        gops.dts = gopForFusion.dts;
42341        gops.duration += gopForFusion.duration;
42342      } else {
42343        // If we didn't find a candidate gop fall back to keyrame-pulling
42344        gops = this.extendFirstKeyFrame_(gops);
42345      }
42346    }
42347    collectDtsInfo(track, gops);
42348
42349    // First, we have to build the index from byte locations to
42350    // samples (that is, frames) in the video data
42351    track.samples = this.generateSampleTable_(gops);
42352
42353    // Concatenate the video data and construct the mdat
42354    mdat = mp4.mdat(this.concatenateNalData_(gops));
42355
42356    // save all the nals in the last GOP into the gop cache
42357    this.gopCache_.unshift({
42358      gop: gops.pop(),
42359      pps: track.pps,
42360      sps: track.sps
42361    });
42362
42363    // Keep a maximum of 6 GOPs in the cache
42364    this.gopCache_.length = Math.min(6, this.gopCache_.length);
42365
42366    // Clear nalUnits
42367    nalUnits = [];
42368
42369    track.baseMediaDecodeTime = calculateTrackBaseMediaDecodeTime(track)
vendor: 9,111 bytes, lines 42369-42664
42369;
42370
42371    this.trigger('baseMediaDecodeTime', track.baseMediaDecodeTime);
42372    this.trigger('timelineStartInfo', track.timelineStartInfo);
42373
42374    moof = mp4.moof(sequenceNumber, [track]);
42375
42376    // it would be great to allocate this array up front instead of
42377    // throwing away hundreds of media segment fragments
42378    boxes = new Uint8Array(moof.byteLength + mdat.byteLength);
42379
42380    // Bump the sequence number for next time
42381    sequenceNumber++;
42382
42383    boxes.set(moof);
42384    boxes.set(mdat, moof.byteLength);
42385
42386    this.trigger('data', {track: track, boxes: boxes});
42387
42388    this.resetStream_();
42389
42390    // Continue with the flush process now
42391    this.trigger('done', 'VideoSegmentStream');
42392  };
42393
42394  this.resetStream_ = function() {
42395    clearDtsInfo(track);
42396
42397    // reset config and pps because they may differ across segments
42398    // for instance, when we are rendition switching
42399    config = undefined;
42400    pps = undefined;
42401  };
42402
42403  // Search for a candidate Gop for gop-fusion from the gop cache and
42404  // return it or return null if no good candidate was found
42405  this.getGopForFusion_ = function(nalUnit) {
42406    var
42407      halfSecond = 45000, // Half-a-second in a 90khz clock
42408      allowableOverlap = 10000, // About 3 frames @ 30fps
42409      nearestDistance = Infinity,
42410      dtsDistance,
42411      nearestGopObj,
42412      currentGop,
42413      currentGopObj,
42414      i;
42415
42416    // Search for the GOP nearest to the beginning of this nal unit
42417    for (i = 0; i < this.gopCache_.length; i++) {
42418      currentGopObj = this.gopCache_[i];
42419      currentGop = currentGopObj.gop;
42420
42421      // Reject Gops with different SPS or PPS
42422      if (!(track.pps && arrayEquals(track.pps[0], currentGopObj.pps[0])) ||
42423          !(track.sps && arrayEquals(track.sps[0], currentGopObj.sps[0]))) {
42424        continue;
42425      }
42426
42427      // Reject Gops that would require a negative baseMediaDecodeTime
42428      if (currentGop.dts < track.timelineStartInfo.dts) {
42429        continue;
42430      }
42431
42432      // The distance between the end of the gop and the start of the nalUnit
42433      dtsDistance = (nalUnit.dts - currentGop.dts) - currentGop.duration;
42434
42435      // Only consider GOPS that start before the nal unit and end within
42436      // a half-second of the nal unit
42437      if (dtsDistance >= -allowableOverlap &&
42438          dtsDistance <= halfSecond) {
42439
42440        // Always use the closest GOP we found if there is more than
42441        // one candidate
42442        if (!nearestGopObj ||
42443            nearestDistance > dtsDistance) {
42444          nearestGopObj = currentGopObj;
42445          nearestDistance = dtsDistance;
42446        }
42447      }
42448    }
42449
42450    if (nearestGopObj) {
42451      return nearestGopObj.gop;
42452    }
42453    return null;
42454  };
42455
42456  this.extendFirstKeyFrame_ = function(gops) {
42457    var currentGop;
42458
42459    if (!gops[0][0].keyFrame && gops.length > 1) {
42460      // Remove the first GOP
42461      currentGop = gops.shift();
42462
42463      gops.byteLength -=  currentGop.byteLength;
42464      gops.nalCount -= currentGop.nalCount;
42465
42466      // Extend the first frame of what is now the
42467      // first gop to cover the time period of the
42468      // frames we just removed
42469      gops[0][0].dts = currentGop.dts;
42470      gops[0][0].pts = currentGop.pts;
42471      gops[0][0].duration += currentGop.duration;
42472    }
42473
42474    return gops;
42475  };
42476
42477  // Convert an array of nal units into an array of frames with each frame being
42478  // composed of the nal units that make up that frame
42479  // Also keep track of cummulative data about the frame from the nal units such
42480  // as the frame duration, starting pts, etc.
42481  this.groupNalsIntoFrames_ = function(nalUnits) {
42482    var
42483      i,
42484      currentNal,
42485      currentFrame = [],
42486      frames = [];
42487
42488    currentFrame.byteLength = 0;
42489
42490    for (i = 0; i < nalUnits.length; i++) {
42491      currentNal = nalUnits[i];
42492
42493      // Split on 'aud'-type nal units
42494      if (currentNal.nalUnitType === 'access_unit_delimiter_rbsp') {
42495        // Since the very first nal unit is expected to be an AUD
42496        // only push to the frames array when currentFrame is not empty
42497        if (currentFrame.length) {
42498          currentFrame.duration = currentNal.dts - currentFrame.dts;
42499          frames.push(currentFrame);
42500        }
42501        currentFrame = [currentNal];
42502        currentFrame.byteLength = currentNal.data.byteLength;
42503        currentFrame.pts = currentNal.pts;
42504        currentFrame.dts = currentNal.dts;
42505      } else {
42506        // Specifically flag key frames for ease of use later
42507        if (currentNal.nalUnitType === 'slice_layer_without_partitioning_rbsp_idr') {
42508          currentFrame.keyFrame = true;
42509        }
42510        currentFrame.duration = currentNal.dts - currentFrame.dts;
42511        currentFrame.byteLength += currentNal.data.byteLength;
42512        currentFrame.push(currentNal);
42513      }
42514    }
42515
42516    // For the last frame, use the duration of the previous frame if we
42517    // have nothing better to go on
42518    if (frames.length &&
42519        (!currentFrame.duration ||
42520         currentFrame.duration <= 0)) {
42521      currentFrame.duration = frames[frames.length - 1].duration;
42522    }
42523
42524    // Push the final frame
42525    frames.push(currentFrame);
42526    return frames;
42527  };
42528
42529  // Convert an array of frames into an array of Gop with each Gop being composed
42530  // of the frames that make up that Gop
42531  // Also keep track of cummulative data about the Gop from the frames such as the
42532  // Gop duration, starting pts, etc.
42533  this.groupFramesIntoGops_ = function(frames) {
42534    var
42535      i,
42536      currentFrame,
42537      currentGop = [],
42538      gops = [];
42539
42540    // We must pre-set some of the values on the Gop since we
42541    // keep running totals of these values
42542    currentGop.byteLength = 0;
42543    currentGop.nalCount = 0;
42544    currentGop.duration = 0;
42545    currentGop.pts = frames[0].pts;
42546    currentGop.dts = frames[0].dts;
42547
42548    // store some metadata about all the Gops
42549    gops.byteLength = 0;
42550    gops.nalCount = 0;
42551    gops.duration = 0;
42552    gops.pts = frames[0].pts;
42553    gops.dts = frames[0].dts;
42554
42555    for (i = 0; i < frames.length; i++) {
42556      currentFrame = frames[i];
42557
42558      if (currentFrame.keyFrame) {
42559        // Since the very first frame is expected to be an keyframe
42560        // only push to the gops array when currentGop is not empty
42561        if (currentGop.length) {
42562          gops.push(currentGop);
42563          gops.byteLength += currentGop.byteLength;
42564          gops.nalCount += currentGop.nalCount;
42565          gops.duration += currentGop.duration;
42566        }
42567
42568        currentGop = [currentFrame];
42569        currentGop.nalCount = currentFrame.length;
42570        currentGop.byteLength = currentFrame.byteLength;
42571        currentGop.pts = currentFrame.pts;
42572        currentGop.dts = currentFrame.dts;
42573        currentGop.duration = currentFrame.duration;
42574      } else {
42575        currentGop.duration += currentFrame.duration;
42576        currentGop.nalCount += currentFrame.length;
42577        currentGop.byteLength += currentFrame.byteLength;
42578        currentGop.push(currentFrame);
42579      }
42580    }
42581
42582    if (gops.length && currentGop.duration <= 0) {
42583      currentGop.duration = gops[gops.length - 1].duration;
42584    }
42585    gops.byteLength += currentGop.byteLength;
42586    gops.nalCount += currentGop.nalCount;
42587    gops.duration += currentGop.duration;
42588
42589    // push the final Gop
42590    gops.push(currentGop);
42591    return gops;
42592  };
42593
42594  // generate the track's sample table from an array of gops
42595  this.generateSampleTable_ = function(gops, baseDataOffset) {
42596    var
42597      h, i,
42598      sample,
42599      currentGop,
42600      currentFrame,
42601      dataOffset = baseDataOffset || 0,
42602      samples = [];
42603
42604    for (h = 0; h < gops.length; h++) {
42605      currentGop = gops[h];
42606
42607      for (i = 0; i < currentGop.length; i++) {
42608        currentFrame = currentGop[i];
42609
42610        sample = createDefaultSample();
42611
42612        sample.dataOffset = dataOffset;
42613        sample.compositionTimeOffset = currentFrame.pts - currentFrame.dts;
42614        sample.duration = currentFrame.duration;
42615        sample.size = 4 * currentFrame.length; // Space for nal unit size
42616        sample.size += currentFrame.byteLength;
42617
42618        if (currentFrame.keyFrame) {
42619          sample.flags.dependsOn = 2;
42620        }
42621
42622        dataOffset += sample.size;
42623
42624        samples.push(sample);
42625      }
42626    }
42627    return samples;
42628  };
42629
42630  // generate the track's raw mdat data from an array of gops
42631  this.concatenateNalData_ = function(gops) {
42632    var
42633      h, i, j,
42634      currentGop,
42635      currentFrame,
42636      currentNal,
42637      dataOffset = 0,
42638      nalsByteLength = gops.byteLength,
42639      numberOfNals = gops.nalCount,
42640      totalByteLength = nalsByteLength + 4 * numberOfNals,
42641      data = new Uint8Array(totalByteLength),
42642      view = new DataView(data.buffer);
42643
42644    // For each Gop..
42645    for (h = 0; h < gops.length; h++) {
42646      currentGop = gops[h];
42647
42648      // For each Frame..
42649      for (i = 0; i < currentGop.length; i++) {
42650        currentFrame = currentGop[i];
42651
42652        // For each NAL..
42653        for (j = 0; j < currentFrame.length; j++) {
42654          currentNal = currentFrame[j];
42655
42656          view.setUint32(dataOffset, currentNal.data.byteLength);
42657          dataOffset += 4;
42658          data.set(currentNal.data, dataOffset);
42659          dataOffset += currentNal.data.byteLength;
42660        }
42661      }
42662    }
42663    return data;
42664  };
vendor: 16,853 bytes, lines 42665-43150
42665};
42666
42667VideoSegmentStream.prototype = new Stream();
42668
42669/**
42670 * Store information about the start and end of the track and the
42671 * duration for each frame/sample we process in order to calculate
42672 * the baseMediaDecodeTime
42673 */
42674collectDtsInfo = function(track, data) {
42675  if (typeof data.pts === 'number') {
42676    if (track.timelineStartInfo.pts === undefined) {
42677      track.timelineStartInfo.pts = data.pts;
42678    }
42679
42680    if (track.minSegmentPts === undefined) {
42681      track.minSegmentPts = data.pts;
42682    } else {
42683      track.minSegmentPts = Math.min(track.minSegmentPts, data.pts);
42684    }
42685
42686    if (track.maxSegmentPts === undefined) {
42687      track.maxSegmentPts = data.pts;
42688    } else {
42689      track.maxSegmentPts = Math.max(track.maxSegmentPts, data.pts);
42690    }
42691  }
42692
42693  if (typeof data.dts === 'number') {
42694    if (track.timelineStartInfo.dts === undefined) {
42695      track.timelineStartInfo.dts = data.dts;
42696    }
42697
42698    if (track.minSegmentDts === undefined) {
42699      track.minSegmentDts = data.dts;
42700    } else {
42701      track.minSegmentDts = Math.min(track.minSegmentDts, data.dts);
42702    }
42703
42704    if (track.maxSegmentDts === undefined) {
42705      track.maxSegmentDts = data.dts;
42706    } else {
42707      track.maxSegmentDts = Math.max(track.maxSegmentDts, data.dts);
42708    }
42709  }
42710};
42711
42712/**
42713 * Clear values used to calculate the baseMediaDecodeTime between
42714 * tracks
42715 */
42716clearDtsInfo = function(track) {
42717  delete track.minSegmentDts;
42718  delete track.maxSegmentDts;
42719  delete track.minSegmentPts;
42720  delete track.maxSegmentPts;
42721};
42722
42723/**
42724 * Calculate the track's baseMediaDecodeTime based on the earliest
42725 * DTS the transmuxer has ever seen and the minimum DTS for the
42726 * current track
42727 */
42728calculateTrackBaseMediaDecodeTime = function(track) {
42729  var
42730    baseMediaDecodeTime,
42731    scale,
42732    // Calculate the distance, in time, that this segment starts from the start
42733    // of the timeline (earliest time seen since the transmuxer initialized)
42734    timeSinceStartOfTimeline = track.minSegmentDts - track.timelineStartInfo.dts;
42735
42736  // track.timelineStartInfo.baseMediaDecodeTime is the location, in time, where
42737  // we want the start of the first segment to be placed
42738  baseMediaDecodeTime = track.timelineStartInfo.baseMediaDecodeTime;
42739
42740  // Add to that the distance this segment is from the very first
42741  baseMediaDecodeTime += timeSinceStartOfTimeline;
42742
42743  // baseMediaDecodeTime must not become negative
42744  baseMediaDecodeTime = Math.max(0, baseMediaDecodeTime);
42745
42746  if (track.type === 'audio') {
42747    // Audio has a different clock equal to the sampling_rate so we need to
42748    // scale the PTS values into the clock rate of the track
42749    scale = track.samplerate / ONE_SECOND_IN_TS;
42750    baseMediaDecodeTime *= scale;
42751    baseMediaDecodeTime = Math.floor(baseMediaDecodeTime);
42752  }
42753
42754  return baseMediaDecodeTime;
42755};
42756
42757/**
42758 * A Stream that can combine multiple streams (ie. audio & video)
42759 * into a single output segment for MSE. Also supports audio-only
42760 * and video-only streams.
42761 */
42762CoalesceStream = function(options, metadataStream) {
42763  // Number of Tracks per output segment
42764  // If greater than 1, we combine multiple
42765  // tracks into a single segment
42766  this.numberOfTracks = 0;
42767  this.metadataStream = metadataStream;
42768
42769  if (typeof options.remux !== 'undefined') {
42770    this.remuxTracks = !!options.remux;
42771  } else {
42772    this.remuxTracks = true;
42773  }
42774
42775  this.pendingTracks = [];
42776  this.videoTrack = null;
42777  this.pendingBoxes = [];
42778  this.pendingCaptions = [];
42779  this.pendingMetadata = [];
42780  this.pendingBytes = 0;
42781  this.emittedTracks = 0;
42782
42783  CoalesceStream.prototype.init.call(this);
42784
42785  // Take output from multiple
42786  this.push = function(output) {
42787    // buffer incoming captions until the associated video segment
42788    // finishes
42789    if (output.text) {
42790      return this.pendingCaptions.push(output);
42791    }
42792    // buffer incoming id3 tags until the final flush
42793    if (output.frames) {
42794      return this.pendingMetadata.push(output);
42795    }
42796
42797    // Add this track to the list of pending tracks and store
42798    // important information required for the construction of
42799    // the final segment
42800    this.pendingTracks.push(output.track);
42801    this.pendingBoxes.push(output.boxes);
42802    this.pendingBytes += output.boxes.byteLength;
42803
42804    if (output.track.type === 'video') {
42805      this.videoTrack = output.track;
42806    }
42807    if (output.track.type === 'audio') {
42808      this.audioTrack = output.track;
42809    }
42810  };
42811};
42812
42813CoalesceStream.prototype = new Stream();
42814CoalesceStream.prototype.flush = function(flushSource) {
42815  var
42816    offset = 0,
42817    event = {
42818      captions: [],
42819      captionStreams: {},
42820      metadata: [],
42821      info: {}
42822    },
42823    caption,
42824    id3,
42825    initSegment,
42826    timelineStartPts = 0,
42827    i;
42828
42829  if (this.pendingTracks.length < this.numberOfTracks) {
42830    if (flushSource !== 'VideoSegmentStream' &&
42831        flushSource !== 'AudioSegmentStream') {
42832      // Return because we haven't received a flush from a data-generating
42833      // portion of the segment (meaning that we have only recieved meta-data
42834      // or captions.)
42835      return;
42836    } else if (this.remuxTracks) {
42837      // Return until we have enough tracks from the pipeline to remux (if we
42838      // are remuxing audio and video into a single MP4)
42839      return;
42840    } else if (this.pendingTracks.length === 0) {
42841      // In the case where we receive a flush without any data having been
42842      // received we consider it an emitted track for the purposes of coalescing
42843      // `done` events.
42844      // We do this for the case where there is an audio and video track in the
42845      // segment but no audio data. (seen in several playlists with alternate
42846      // audio tracks and no audio present in the main TS segments.)
42847      this.emittedTracks++;
42848
42849      if (this.emittedTracks >= this.numberOfTracks) {
42850        this.trigger('done');
42851        this.emittedTracks = 0;
42852      }
42853      return;
42854    }
42855  }
42856
42857  if (this.videoTrack) {
42858    timelineStartPts = this.videoTrack.timelineStartInfo.pts;
42859    VIDEO_PROPERTIES.forEach(function(prop) {
42860      event.info[prop] = this.videoTrack[prop];
42861    }, this);
42862  } else if (this.audioTrack) {
42863    timelineStartPts = this.audioTrack.timelineStartInfo.pts;
42864    AUDIO_PROPERTIES.forEach(function(prop) {
42865      event.info[prop] = this.audioTrack[prop];
42866    }, this);
42867  }
42868
42869  if (this.pendingTracks.length === 1) {
42870    event.type = this.pendingTracks[0].type;
42871  } else {
42872    event.type = 'combined';
42873  }
42874
42875  this.emittedTracks += this.pendingTracks.length;
42876
42877  initSegment = mp4.initSegment(this.pendingTracks);
42878
42879  // Create a new typed array to hold the init segment
42880  event.initSegment = new Uint8Array(initSegment.byteLength);
42881
42882  // Create an init segment containing a moov
42883  // and track definitions
42884  event.initSegment.set(initSegment);
42885
42886  // Create a new typed array to hold the moof+mdats
42887  event.data = new Uint8Array(this.pendingBytes);
42888
42889  // Append each moof+mdat (one per track) together
42890  for (i = 0; i < this.pendingBoxes.length; i++) {
42891    event.data.set(this.pendingBoxes[i], offset);
42892    offset += this.pendingBoxes[i].byteLength;
42893  }
42894
42895  // Translate caption PTS times into second offsets into the
42896  // video timeline for the segment, and add track info
42897  for (i = 0; i < this.pendingCaptions.length; i++) {
42898    caption = this.pendingCaptions[i];
42899    caption.startTime = (caption.startPts - timelineStartPts);
42900    caption.startTime /= 90e3;
42901    caption.endTime = (caption.endPts - timelineStartPts);
42902    caption.endTime /= 90e3;
42903    event.captionStreams[caption.stream] = true;
42904    event.captions.push(caption);
42905  }
42906
42907  // Translate ID3 frame PTS times into second offsets into the
42908  // video timeline for the segment
42909  for (i = 0; i < this.pendingMetadata.length; i++) {
42910    id3 = this.pendingMetadata[i];
42911    id3.cueTime = (id3.pts - timelineStartPts);
42912    id3.cueTime /= 90e3;
42913    event.metadata.push(id3);
42914  }
42915  // We add this to every single emitted segment even though we only need
42916  // it for the first
42917  event.metadata.dispatchType = this.metadataStream.dispatchType;
42918
42919  // Reset stream state
42920  this.pendingTracks.length = 0;
42921  this.videoTrack = null;
42922  this.pendingBoxes.length = 0;
42923  this.pendingCaptions.length = 0;
42924  this.pendingBytes = 0;
42925  this.pendingMetadata.length = 0;
42926
42927  // Emit the built segment
42928  this.trigger('data', event);
42929
42930  // Only emit `done` if all tracks have been flushed and emitted
42931  if (this.emittedTracks >= this.numberOfTracks) {
42932    this.trigger('done');
42933    this.emittedTracks = 0;
42934  }
42935};
42936/**
42937 * A Stream that expects MP2T binary data as input and produces
42938 * corresponding media segments, suitable for use with Media Source
42939 * Extension (MSE) implementations that support the ISO BMFF byte
42940 * stream format, like Chrome.
42941 */
42942Transmuxer = function(options) {
42943  var
42944    self = this,
42945    hasFlushed = true,
42946    videoTrack,
42947    audioTrack;
42948
42949  Transmuxer.prototype.init.call(this);
42950
42951  options = options || {};
42952  this.baseMediaDecodeTime = options.baseMediaDecodeTime || 0;
42953  this.transmuxPipeline_ = {};
42954
42955  this.setupAacPipeline = function() {
42956    var pipeline = {};
42957    this.transmuxPipeline_ = pipeline;
42958
42959    pipeline.type = 'aac';
42960    pipeline.metadataStream = new m2ts.MetadataStream();
42961
42962    // set up the parsing pipeline
42963    pipeline.aacStream = new AacStream();
42964    pipeline.audioTimestampRolloverStream = new m2ts.TimestampRolloverStream('audio');
42965    pipeline.timedMetadataTimestampRolloverStream = new m2ts.TimestampRolloverStream('timed-metadata');
42966    pipeline.adtsStream = new AdtsStream();
42967    pipeline.coalesceStream = new CoalesceStream(options, pipeline.metadataStream);
42968    pipeline.headOfPipeline = pipeline.aacStream;
42969
42970    pipeline.aacStream
42971      .pipe(pipeline.audioTimestampRolloverStream)
42972      .pipe(pipeline.adtsStream);
42973    pipeline.aacStream
42974      .pipe(pipeline.timedMetadataTimestampRolloverStream)
42975      .pipe(pipeline.metadataStream)
42976      .pipe(pipeline.coalesceStream);
42977
42978    pipeline.metadataStream.on('timestamp', function(frame) {
42979      pipeline.aacStream.setTimestamp(frame.timeStamp);
42980    });
42981
42982    pipeline.aacStream.on('data', function(data) {
42983      if (data.type === 'timed-metadata' && !pipeline.audioSegmentStream) {
42984        audioTrack = audioTrack || {
42985          timelineStartInfo: {
42986            baseMediaDecodeTime: self.baseMediaDecodeTime
42987          },
42988          codec: 'adts',
42989          type: 'audio'
42990        };
42991        // hook up the audio segment stream to the first track with aac data
42992        pipeline.coalesceStream.numberOfTracks++;
42993        pipeline.audioSegmentStream = new AudioSegmentStream(audioTrack);
42994        // Set up the final part of the audio pipeline
42995        pipeline.adtsStream
42996          .pipe(pipeline.audioSegmentStream)
42997          .pipe(pipeline.coalesceStream);
42998      }
42999    });
43000
43001    // Re-emit any data coming from the coalesce stream to the outside world
43002    pipeline.coalesceStream.on('data', this.trigger.bind(this, 'data'));
43003    // Let the consumer know we have finished flushing the entire pipeline
43004    pipeline.coalesceStream.on('done', this.trigger.bind(this, 'done'));
43005  };
43006
43007  this.setupTsPipeline = function() {
43008    var pipeline = {};
43009    this.transmuxPipeline_ = pipeline;
43010
43011    pipeline.type = 'ts';
43012    pipeline.metadataStream = new m2ts.MetadataStream();
43013
43014    // set up the parsing pipeline
43015    pipeline.packetStream = new m2ts.TransportPacketStream();
43016    pipeline.parseStream = new m2ts.TransportParseStream();
43017    pipeline.elementaryStream = new m2ts.ElementaryStream();
43018    pipeline.videoTimestampRolloverStream = new m2ts.TimestampRolloverStream('video');
43019    pipeline.audioTimestampRolloverStream = new m2ts.TimestampRolloverStream('audio');
43020    pipeline.timedMetadataTimestampRolloverStream = new m2ts.TimestampRolloverStream('timed-metadata');
43021    pipeline.adtsStream = new AdtsStream();
43022    pipeline.h264Stream = new H264Stream();
43023    pipeline.captionStream = new m2ts.CaptionStream();
43024    pipeline.coalesceStream = new CoalesceStream(options, pipeline.metadataStream);
43025    pipeline.headOfPipeline = pipeline.packetStream;
43026
43027    // disassemble MPEG2-TS packets into elementary streams
43028    pipeline.packetStream
43029      .pipe(pipeline.parseStream)
43030      .pipe(pipeline.elementaryStream);
43031
43032    // !!THIS ORDER IS IMPORTANT!!
43033    // demux the streams
43034    pipeline.elementaryStream
43035      .pipe(pipeline.videoTimestampRolloverStream)
43036      .pipe(pipeline.h264Stream);
43037    pipeline.elementaryStream
43038      .pipe(pipeline.audioTimestampRolloverStream)
43039      .pipe(pipeline.adtsStream);
43040
43041    pipeline.elementaryStream
43042      .pipe(pipeline.timedMetadataTimestampRolloverStream)
43043      .pipe(pipeline.metadataStream)
43044      .pipe(pipeline.coalesceStream);
43045
43046    // Hook up CEA-608/708 caption stream
43047    pipeline.h264Stream.pipe(pipeline.captionStream)
43048      .pipe(pipeline.coalesceStream);
43049
43050    pipeline.elementaryStream.on('data', function(data) {
43051      var i;
43052
43053      if (data.type === 'metadata') {
43054        i = data.tracks.length;
43055
43056        // scan the tracks listed in the metadata
43057        while (i--) {
43058          if (!videoTrack && data.tracks[i].type === 'video') {
43059            videoTrack = data.tracks[i];
43060            videoTrack.timelineStartInfo.baseMediaDecodeTime = self.baseMediaDecodeTime;
43061          } else if (!audioTrack && data.tracks[i].type === 'audio') {
43062            audioTrack = data.tracks[i];
43063            audioTrack.timelineStartInfo.baseMediaDecodeTime = self.baseMediaDecodeTime;
43064          }
43065        }
43066
43067        // hook up the video segment stream to the first track with h264 data
43068        if (videoTrack && !pipeline.videoSegmentStream) {
43069          pipeline.coalesceStream.numberOfTracks++;
43070          pipeline.videoSegmentStream = new VideoSegmentStream(videoTrack);
43071
43072          pipeline.videoSegmentStream.on('timelineStartInfo', function(timelineStartInfo) {
43073          // When video emits timelineStartInfo data after a flush, we forward that
43074          // info to the AudioSegmentStream, if it exists, because video timeline
43075          // data takes precedence.
43076            if (audioTrack) {
43077              audioTrack.timelineStartInfo = timelineStartInfo;
43078              // On the first segment we trim AAC frames that exist before the
43079              // very earliest DTS we have seen in video because Chrome will
43080              // interpret any video track with a baseMediaDecodeTime that is
43081              // non-zero as a gap.
43082              pipeline.audioSegmentStream.setEarliestDts(timelineStartInfo.dts);
43083            }
43084          });
43085
43086          pipeline.videoSegmentStream.on('baseMediaDecodeTime', function(baseMediaDecodeTime) {
43087            if (audioTrack) {
43088              pipeline.audioSegmentStream.setVideoBaseMediaDecodeTime(baseMediaDecodeTime);
43089            }
43090          });
43091
43092          // Set up the final part of the video pipeline
43093          pipeline.h264Stream
43094            .pipe(pipeline.videoSegmentStream)
43095            .pipe(pipeline.coalesceStream);
43096        }
43097
43098        if (audioTrack && !pipeline.audioSegmentStream) {
43099          // hook up the audio segment stream to the first track with aac data
43100          pipeline.coalesceStream.numberOfTracks++;
43101          pipeline.audioSegmentStream = new AudioSegmentStream(audioTrack);
43102
43103          // Set up the final part of the audio pipeline
43104          pipeline.adtsStream
43105            .pipe(pipeline.audioSegmentStream)
43106            .pipe(pipeline.coalesceStream);
43107        }
43108      }
43109    });
43110
43111    // Re-emit any data coming from the coalesce stream to the outside world
43112    pipeline.coalesceStream.on('data', this.trigger.bind(this, 'data'));
43113    // Let the consumer know we have finished flushing the entire pipeline
43114    pipeline.coalesceStream.on('done', this.trigger.bind(this, 'done'));
43115  };
43116
43117  // hook up the segment streams once track metadata is delivered
43118  this.setBaseMediaDecodeTime = function(baseMediaDecodeTime) {
43119    var pipeline = this.transmuxPipeline_;
43120
43121    this.baseMediaDecodeTime = baseMediaDecodeTime;
43122    if (audioTrack) {
43123      audioTrack.timelineStartInfo.dts = undefined;
43124      audioTrack.timelineStartInfo.pts = undefined;
43125      clearDtsInfo(audioTrack);
43126      audioTrack.timelineStartInfo.baseMediaDecodeTime = baseMediaDecodeTime;
43127      if (pipeline.audioTimestampRolloverStream) {
43128        pipeline.audioTimestampRolloverStream.discontinuity();
43129      }
43130    }
43131    if (videoTrack) {
43132      if (pipeline.videoSegmentStream) {
43133        pipeline.videoSegmentStream.gopCache_ = [];
43134        pipeline.videoTimestampRolloverStream.discontinuity();
43135      }
43136      videoTrack.timelineStartInfo.dts = undefined;
43137      videoTrack.timelineStartInfo.pts = undefined;
43138      clearDtsInfo(videoTrack);
43139      pipeline.captionStream.reset();
43140      videoTrack.timelineStartInfo.baseMediaDecodeTime = baseMediaDecodeTime;
43141    }
43142
43143    if (pipeline.timedMetadataTimestampRolloverStream) {
43144      pipeline.timedMetadataTimestampRolloverStream.discontinuity();
43145    }
43146  };
43147
43148  this.setAudioAppendStart = function(timestamp) {
43149    if (audioTrack) {
43150      this.transmuxPipeline_.audioSegmentStream.setAudioAppendStart(timestamp
vendor: 24,457 bytes, lines 43150-44020
43150);
43151    }
43152  };
43153
43154  // feed incoming data to the front of the parsing pipeline
43155  this.push = function(data) {
43156    if (hasFlushed) {
43157      var isAac = isLikelyAacData(data);
43158
43159      if (isAac && this.transmuxPipeline_.type !== 'aac') {
43160        this.setupAacPipeline();
43161      } else if (!isAac && this.transmuxPipeline_.type !== 'ts') {
43162        this.setupTsPipeline();
43163      }
43164      hasFlushed = false;
43165    }
43166    this.transmuxPipeline_.headOfPipeline.push(data);
43167  };
43168
43169  // flush any buffered data
43170  this.flush = function() {
43171      hasFlushed = true;
43172    // Start at the top of the pipeline and flush all pending work
43173    this.transmuxPipeline_.headOfPipeline.flush();
43174  };
43175
43176  // Caption data has to be reset when seeking outside buffered range
43177  this.resetCaptions = function() {
43178    if (this.transmuxPipeline_.captionStream) {
43179      this.transmuxPipeline_.captionStream.reset();
43180    }
43181  };
43182
43183};
43184Transmuxer.prototype = new Stream();
43185
43186module.exports = {
43187  Transmuxer: Transmuxer,
43188  VideoSegmentStream: VideoSegmentStream,
43189  AudioSegmentStream: AudioSegmentStream,
43190  AUDIO_PROPERTIES: AUDIO_PROPERTIES,
43191  VIDEO_PROPERTIES: VIDEO_PROPERTIES
43192};
43193
43194},{"../aac":38,"../codecs/adts.js":40,"../codecs/h264":41,"../data/silence":42,"../m2ts/m2ts.js":50,"../utils/clock":60,"../utils/stream.js":62,"./mp4-generator.js":56}],59:[function(require,module,exports){
43195/**
43196 * mux.js
43197 *
43198 * Copyright (c) 2016 Brightcove
43199 * All rights reserved.
43200 *
43201 * Parse mpeg2 transport stream packets to extract basic timing information
43202 */
43203'use strict';
43204
43205var StreamTypes = require('../m2ts/stream-types.js');
43206var handleRollover = require('../m2ts/timestamp-rollover-stream.js').handleRollover;
43207var probe = {};
43208probe.ts = require('../m2ts/probe.js');
43209probe.aac = require('../aac/probe.js');
43210
43211
43212var
43213  PES_TIMESCALE = 90000,
43214  MP2T_PACKET_LENGTH = 188, // bytes
43215  SYNC_BYTE = 0x47;
43216
43217var isLikelyAacData = function(data) {
43218  if ((data[0] === 'I'.charCodeAt(0)) &&
43219      (data[1] === 'D'.charCodeAt(0)) &&
43220      (data[2] === '3'.charCodeAt(0))) {
43221    return true;
43222  }
43223  return false;
43224};
43225
43226/**
43227 * walks through segment data looking for pat and pmt packets to parse out
43228 * program map table information
43229 */
43230var parsePsi_ = function(bytes, pmt) {
43231  var
43232    startIndex = 0,
43233    endIndex = MP2T_PACKET_LENGTH,
43234    packet, type;
43235
43236  while (endIndex < bytes.byteLength) {
43237    // Look for a pair of start and end sync bytes in the data..
43238    if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) {
43239      // We found a packet
43240      packet = bytes.subarray(startIndex, endIndex);
43241      type = probe.ts.parseType(packet, pmt.pid);
43242
43243      switch (type) {
43244        case 'pat':
43245          if (!pmt.pid) {
43246            pmt.pid = probe.ts.parsePat(packet);
43247          }
43248          break;
43249        case 'pmt':
43250          if (!pmt.table) {
43251            pmt.table = probe.ts.parsePmt(packet);
43252          }
43253          break;
43254        default:
43255          break;
43256      }
43257
43258      // Found the pat and pmt, we can stop walking the segment
43259      if (pmt.pid && pmt.table) {
43260        return;
43261      }
43262
43263      startIndex += MP2T_PACKET_LENGTH;
43264      endIndex += MP2T_PACKET_LENGTH;
43265      continue;
43266    }
43267
43268    // If we get here, we have somehow become de-synchronized and we need to step
43269    // forward one byte at a time until we find a pair of sync bytes that denote
43270    // a packet
43271    startIndex++;
43272    endIndex++;
43273  }
43274};
43275
43276/**
43277 * walks through the segment data from the start and end to get timing information
43278 * for the first and last audio pes packets
43279 */
43280var parseAudioPes_ = function(bytes, pmt, result) {
43281  var
43282    startIndex = 0,
43283    endIndex = MP2T_PACKET_LENGTH,
43284    packet, type, pesType, pusi, parsed;
43285
43286  var endLoop = false;
43287
43288  // Start walking from start of segment to get first audio packet
43289  while (endIndex < bytes.byteLength) {
43290    // Look for a pair of start and end sync bytes in the data..
43291    if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) {
43292      // We found a packet
43293      packet = bytes.subarray(startIndex, endIndex);
43294      type = probe.ts.parseType(packet, pmt.pid);
43295
43296      switch (type) {
43297        case 'pes':
43298          pesType = probe.ts.parsePesType(packet, pmt.table);
43299          pusi = probe.ts.parsePayloadUnitStartIndicator(packet);
43300          if (pesType === 'audio' && pusi) {
43301            parsed = probe.ts.parsePesTime(packet);
43302            if (parsed) {
43303              parsed.type = 'audio';
43304              result.audio.push(parsed);
43305              endLoop = true;
43306            }
43307          }
43308          break;
43309        default:
43310          break;
43311      }
43312
43313      if (endLoop) {
43314        break;
43315      }
43316
43317      startIndex += MP2T_PACKET_LENGTH;
43318      endIndex += MP2T_PACKET_LENGTH;
43319      continue;
43320    }
43321
43322    // If we get here, we have somehow become de-synchronized and we need to step
43323    // forward one byte at a time until we find a pair of sync bytes that denote
43324    // a packet
43325    startIndex++;
43326    endIndex++;
43327  }
43328
43329  // Start walking from end of segment to get last audio packet
43330  endIndex = bytes.byteLength;
43331  startIndex = endIndex - MP2T_PACKET_LENGTH;
43332  endLoop = false;
43333  while (startIndex >= 0) {
43334    // Look for a pair of start and end sync bytes in the data..
43335    if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) {
43336      // We found a packet
43337      packet = bytes.subarray(startIndex, endIndex);
43338      type = probe.ts.parseType(packet, pmt.pid);
43339
43340      switch (type) {
43341        case 'pes':
43342          pesType = probe.ts.parsePesType(packet, pmt.table);
43343          pusi = probe.ts.parsePayloadUnitStartIndicator(packet);
43344          if (pesType === 'audio' && pusi) {
43345            parsed = probe.ts.parsePesTime(packet);
43346            if (parsed) {
43347              parsed.type = 'audio';
43348              result.audio.push(parsed);
43349              endLoop = true;
43350            }
43351          }
43352          break;
43353        default:
43354          break;
43355      }
43356
43357      if (endLoop) {
43358        break;
43359      }
43360
43361      startIndex -= MP2T_PACKET_LENGTH;
43362      endIndex -= MP2T_PACKET_LENGTH;
43363      continue;
43364    }
43365
43366    // If we get here, we have somehow become de-synchronized and we need to step
43367    // forward one byte at a time until we find a pair of sync bytes that denote
43368    // a packet
43369    startIndex--;
43370    endIndex--;
43371  }
43372};
43373
43374/**
43375 * walks through the segment data from the start and end to get timing information
43376 * for the first and last video pes packets as well as timing information for the first
43377 * key frame.
43378 */
43379var parseVideoPes_ = function(bytes, pmt, result) {
43380  var
43381    startIndex = 0,
43382    endIndex = MP2T_PACKET_LENGTH,
43383    packet, type, pesType, pusi, parsed, frame, i, pes;
43384
43385  var endLoop = false;
43386
43387  var currentFrame = {
43388    data: [],
43389    size: 0
43390  };
43391
43392  // Start walking from start of segment to get first video packet
43393  while (endIndex < bytes.byteLength) {
43394    // Look for a pair of start and end sync bytes in the data..
43395    if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) {
43396      // We found a packet
43397      packet = bytes.subarray(startIndex, endIndex);
43398      type = probe.ts.parseType(packet, pmt.pid);
43399
43400      switch (type) {
43401        case 'pes':
43402          pesType = probe.ts.parsePesType(packet, pmt.table);
43403          pusi = probe.ts.parsePayloadUnitStartIndicator(packet);
43404          if (pesType === 'video') {
43405            if (pusi && !endLoop) {
43406              parsed = probe.ts.parsePesTime(packet);
43407              if (parsed) {
43408                parsed.type = 'video';
43409                result.video.push(parsed);
43410                endLoop = true;
43411              }
43412            }
43413            if (!result.firstKeyFrame) {
43414              if (pusi) {
43415                if (currentFrame.size !== 0) {
43416                  frame = new Uint8Array(currentFrame.size);
43417                  i = 0;
43418                  while (currentFrame.data.length) {
43419                    pes = currentFrame.data.shift();
43420                    frame.set(pes, i);
43421                    i += pes.byteLength;
43422                  }
43423                  if (probe.ts.videoPacketContainsKeyFrame(frame)) {
43424                    result.firstKeyFrame = probe.ts.parsePesTime(frame);
43425                    result.firstKeyFrame.type = 'video';
43426                  }
43427                  currentFrame.size = 0;
43428                }
43429              }
43430              currentFrame.data.push(packet);
43431              currentFrame.size += packet.byteLength;
43432            }
43433          }
43434          break;
43435        default:
43436          break;
43437      }
43438
43439      if (endLoop && result.firstKeyFrame) {
43440        break;
43441      }
43442
43443      startIndex += MP2T_PACKET_LENGTH;
43444      endIndex += MP2T_PACKET_LENGTH;
43445      continue;
43446    }
43447
43448    // If we get here, we have somehow become de-synchronized and we need to step
43449    // forward one byte at a time until we find a pair of sync bytes that denote
43450    // a packet
43451    startIndex++;
43452    endIndex++;
43453  }
43454
43455  // Start walking from end of segment to get last video packet
43456  endIndex = bytes.byteLength;
43457  startIndex = endIndex - MP2T_PACKET_LENGTH;
43458  endLoop = false;
43459  while (startIndex >= 0) {
43460    // Look for a pair of start and end sync bytes in the data..
43461    if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) {
43462      // We found a packet
43463      packet = bytes.subarray(startIndex, endIndex);
43464      type = probe.ts.parseType(packet, pmt.pid);
43465
43466      switch (type) {
43467        case 'pes':
43468          pesType = probe.ts.parsePesType(packet, pmt.table);
43469          pusi = probe.ts.parsePayloadUnitStartIndicator(packet);
43470          if (pesType === 'video' && pusi) {
43471              parsed = probe.ts.parsePesTime(packet);
43472              if (parsed) {
43473                parsed.type = 'video';
43474                result.video.push(parsed);
43475                endLoop = true;
43476              }
43477          }
43478          break;
43479        default:
43480          break;
43481      }
43482
43483      if (endLoop) {
43484        break;
43485      }
43486
43487      startIndex -= MP2T_PACKET_LENGTH;
43488      endIndex -= MP2T_PACKET_LENGTH;
43489      continue;
43490    }
43491
43492    // If we get here, we have somehow become de-synchronized and we need to step
43493    // forward one byte at a time until we find a pair of sync bytes that denote
43494    // a packet
43495    startIndex--;
43496    endIndex--;
43497  }
43498};
43499
43500/**
43501 * Adjusts the timestamp information for the segment to account for
43502 * rollover and convert to seconds based on pes packet timescale (90khz clock)
43503 */
43504var adjustTimestamp_ = function(segmentInfo, baseTimestamp) {
43505  if (segmentInfo.audio && segmentInfo.audio.length) {
43506    var audioBaseTimestamp = baseTimestamp;
43507    if (typeof audioBaseTimestamp === 'undefined') {
43508      audioBaseTimestamp = segmentInfo.audio[0].dts;
43509    }
43510    segmentInfo.audio.forEach(function(info) {
43511      info.dts = handleRollover(info.dts, audioBaseTimestamp);
43512      info.pts = handleRollover(info.pts, audioBaseTimestamp);
43513      // time in seconds
43514      info.dtsTime = info.dts / PES_TIMESCALE;
43515      info.ptsTime = info.pts / PES_TIMESCALE;
43516    });
43517  }
43518
43519  if (segmentInfo.video && segmentInfo.video.length) {
43520    var videoBaseTimestamp = baseTimestamp;
43521    if (typeof videoBaseTimestamp === 'undefined') {
43522      videoBaseTimestamp = segmentInfo.video[0].dts;
43523    }
43524    segmentInfo.video.forEach(function(info) {
43525      info.dts = handleRollover(info.dts, videoBaseTimestamp);
43526      info.pts = handleRollover(info.pts, videoBaseTimestamp);
43527      // time in seconds
43528      info.dtsTime = info.dts / PES_TIMESCALE;
43529      info.ptsTime = info.pts / PES_TIMESCALE;
43530    });
43531    if (segmentInfo.firstKeyFrame) {
43532      var frame = segmentInfo.firstKeyFrame;
43533      frame.dts = handleRollover(frame.dts, videoBaseTimestamp);
43534      frame.pts = handleRollover(frame.pts, videoBaseTimestamp);
43535      // time in seconds
43536      frame.dtsTime = frame.dts / PES_TIMESCALE;
43537      frame.ptsTime = frame.dts / PES_TIMESCALE;
43538    }
43539  }
43540};
43541
43542/**
43543 * inspects the aac data stream for start and end time information
43544 */
43545var inspectAac_ = function(bytes) {
43546  var
43547    endLoop = false,
43548    audioCount = 0,
43549    sampleRate = null,
43550    timestamp = null,
43551    frameSize = 0,
43552    byteIndex = 0,
43553    packet;
43554
43555  while (bytes.length - byteIndex >= 3) {
43556    var type = probe.aac.parseType(bytes, byteIndex);
43557    switch (type) {
43558      case 'timed-metadata':
43559        // Exit early because we don't have enough to parse
43560        // the ID3 tag header
43561        if (bytes.length - byteIndex < 10) {
43562          endLoop = true;
43563          break;
43564        }
43565
43566        frameSize = probe.aac.parseId3TagSize(bytes, byteIndex);
43567
43568        // Exit early if we don't have enough in the buffer
43569        // to emit a full packet
43570        if (frameSize > bytes.length) {
43571          endLoop = true;
43572          break;
43573        }
43574        if (timestamp === null) {
43575          packet = bytes.subarray(byteIndex, byteIndex + frameSize);
43576          timestamp = probe.aac.parseAacTimestamp(packet);
43577        }
43578        byteIndex += frameSize;
43579        break;
43580      case 'audio':
43581        // Exit early because we don't have enough to parse
43582        // the ADTS frame header
43583        if (bytes.length - byteIndex < 7) {
43584          endLoop = true;
43585          break;
43586        }
43587
43588        frameSize = probe.aac.parseAdtsSize(bytes, byteIndex);
43589
43590        // Exit early if we don't have enough in the buffer
43591        // to emit a full packet
43592        if (frameSize > bytes.length) {
43593          endLoop = true;
43594          break;
43595        }
43596        if (sampleRate === null) {
43597          packet = bytes.subarray(byteIndex, byteIndex + frameSize);
43598          sampleRate = probe.aac.parseSampleRate(packet);
43599        }
43600        audioCount++;
43601        byteIndex += frameSize;
43602        break;
43603      default:
43604        byteIndex++;
43605        break;
43606    }
43607    if (endLoop) {
43608      return null;
43609    }
43610  }
43611  if (sampleRate === null || timestamp === null) {
43612    return null;
43613  }
43614
43615  var audioTimescale = PES_TIMESCALE / sampleRate;
43616
43617  var result = {
43618    audio: [
43619      {
43620        type: 'audio',
43621        dts: timestamp,
43622        pts: timestamp
43623      },
43624      {
43625        type: 'audio',
43626        dts: timestamp + (audioCount * 1024 * audioTimescale),
43627        pts: timestamp + (audioCount * 1024 * audioTimescale)
43628      }
43629    ]
43630  };
43631
43632  return result;
43633};
43634
43635/**
43636 * inspects the transport stream segment data for start and end time information
43637 * of the audio and video tracks (when present) as well as the first key frame's
43638 * start time.
43639 */
43640var inspectTs_ = function(bytes) {
43641  var pmt = {
43642    pid: null,
43643    table: null
43644  };
43645
43646  var result = {};
43647
43648  parsePsi_(bytes, pmt);
43649
43650  for (var pid in pmt.table) {
43651    if (pmt.table.hasOwnProperty(pid)) {
43652      var type = pmt.table[pid];
43653      switch (type) {
43654        case StreamTypes.H264_STREAM_TYPE:
43655          result.video = [];
43656          parseVideoPes_(bytes, pmt, result);
43657          if (result.video.length === 0) {
43658            delete result.video;
43659          }
43660          break;
43661        case StreamTypes.ADTS_STREAM_TYPE:
43662          result.audio = [];
43663          parseAudioPes_(bytes, pmt, result);
43664          if (result.audio.length === 0) {
43665            delete result.audio;
43666          }
43667          break;
43668        default:
43669          break;
43670      }
43671    }
43672  }
43673  return result;
43674};
43675
43676/**
43677 * Inspects segment byte data and returns an object with start and end timing information
43678 *
43679 * @param {Uint8Array} bytes The segment byte data
43680 * @param {Number} baseTimestamp Relative reference timestamp used when adjusting frame
43681 *  timestamps for rollover. This value must be in 90khz clock.
43682 * @return {Object} Object containing start and end frame timing info of segment.
43683 */
43684var inspect = function(bytes, baseTimestamp) {
43685  var isAacData = isLikelyAacData(bytes);
43686
43687  var result;
43688
43689  if (isAacData) {
43690    result = inspectAac_(bytes);
43691  } else {
43692    result = inspectTs_(bytes);
43693  }
43694
43695  if (!result || (!result.audio && !result.video)) {
43696    return null;
43697  }
43698
43699  adjustTimestamp_(result, baseTimestamp);
43700
43701  return result;
43702};
43703
43704module.exports = {
43705  inspect: inspect
43706};
43707
43708},{"../aac/probe.js":39,"../m2ts/probe.js":52,"../m2ts/stream-types.js":53,"../m2ts/timestamp-rollover-stream.js":54}],60:[function(require,module,exports){
43709var
43710  ONE_SECOND_IN_TS = 90000, // 90kHz clock
43711  secondsToVideoTs,
43712  secondsToAudioTs,
43713  videoTsToSeconds,
43714  audioTsToSeconds,
43715  audioTsToVideoTs,
43716  videoTsToAudioTs;
43717
43718secondsToVideoTs = function(seconds) {
43719  return seconds * ONE_SECOND_IN_TS;
43720};
43721
43722secondsToAudioTs = function(seconds, sampleRate) {
43723  return seconds * sampleRate;
43724};
43725
43726videoTsToSeconds = function(timestamp) {
43727  return timestamp / ONE_SECOND_IN_TS;
43728};
43729
43730audioTsToSeconds = function(timestamp, sampleRate) {
43731  return timestamp / sampleRate;
43732};
43733
43734audioTsToVideoTs = function(timestamp, sampleRate) {
43735  return secondsToVideoTs(audioTsToSeconds(timestamp, sampleRate));
43736};
43737
43738videoTsToAudioTs = function(timestamp, sampleRate) {
43739  return secondsToAudioTs(videoTsToSeconds(timestamp), sampleRate);
43740};
43741
43742module.exports = {
43743  secondsToVideoTs: secondsToVideoTs,
43744  secondsToAudioTs: secondsToAudioTs,
43745  videoTsToSeconds: videoTsToSeconds,
43746  audioTsToSeconds: audioTsToSeconds,
43747  audioTsToVideoTs: audioTsToVideoTs,
43748  videoTsToAudioTs: videoTsToAudioTs
43749};
43750
43751},{}],61:[function(require,module,exports){
43752'use strict';
43753
43754var ExpGolomb;
43755
43756/**
43757 * Parser for exponential Golomb codes, a variable-bitwidth number encoding
43758 * scheme used by h264.
43759 */
43760ExpGolomb = function(workingData) {
43761  var
43762    // the number of bytes left to examine in workingData
43763    workingBytesAvailable = workingData.byteLength,
43764
43765    // the current word being examined
43766    workingWord = 0, // :uint
43767
43768    // the number of bits left to examine in the current word
43769    workingBitsAvailable = 0; // :uint;
43770
43771  // ():uint
43772  this.length = function() {
43773    return (8 * workingBytesAvailable);
43774  };
43775
43776  // ():uint
43777  this.bitsAvailable = function() {
43778    return (8 * workingBytesAvailable) + workingBitsAvailable;
43779  };
43780
43781  // ():void
43782  this.loadWord = function() {
43783    var
43784      position = workingData.byteLength - workingBytesAvailable,
43785      workingBytes = new Uint8Array(4),
43786      availableBytes = Math.min(4, workingBytesAvailable);
43787
43788    if (availableBytes === 0) {
43789      throw new Error('no bytes available');
43790    }
43791
43792    workingBytes.set(workingData.subarray(position,
43793                                          position + availableBytes));
43794    workingWord = new DataView(workingBytes.buffer).getUint32(0);
43795
43796    // track the amount of workingData that has been processed
43797    workingBitsAvailable = availableBytes * 8;
43798    workingBytesAvailable -= availableBytes;
43799  };
43800
43801  // (count:int):void
43802  this.skipBits = function(count) {
43803    var skipBytes; // :int
43804    if (workingBitsAvailable > count) {
43805      workingWord          <<= count;
43806      workingBitsAvailable -= count;
43807    } else {
43808      count -= workingBitsAvailable;
43809      skipBytes = Math.floor(count / 8);
43810
43811      count -= (skipBytes * 8);
43812      workingBytesAvailable -= skipBytes;
43813
43814      this.loadWord();
43815
43816      workingWord <<= count;
43817      workingBitsAvailable -= count;
43818    }
43819  };
43820
43821  // (size:int):uint
43822  this.readBits = function(size) {
43823    var
43824      bits = Math.min(workingBitsAvailable, size), // :uint
43825      valu = workingWord >>> (32 - bits); // :uint
43826    // if size > 31, handle error
43827    workingBitsAvailable -= bits;
43828    if (workingBitsAvailable > 0) {
43829      workingWord <<= bits;
43830    } else if (workingBytesAvailable > 0) {
43831      this.loadWord();
43832    }
43833
43834    bits = size - bits;
43835    if (bits > 0) {
43836      return valu << bits | this.readBits(bits);
43837    }
43838    return valu;
43839  };
43840
43841  // ():uint
43842  this.skipLeadingZeros = function() {
43843    var leadingZeroCount; // :uint
43844    for (leadingZeroCount = 0; leadingZeroCount < workingBitsAvailable; ++leadingZeroCount) {
43845      if ((workingWord & (0x80000000 >>> leadingZeroCount)) !== 0) {
43846        // the first bit of working word is 1
43847        workingWord <<= leadingZeroCount;
43848        workingBitsAvailable -= leadingZeroCount;
43849        return leadingZeroCount;
43850      }
43851    }
43852
43853    // we exhausted workingWord and still have not found a 1
43854    this.loadWord();
43855    return leadingZeroCount + this.skipLeadingZeros();
43856  };
43857
43858  // ():void
43859  this.skipUnsignedExpGolomb = function() {
43860    this.skipBits(1 + this.skipLeadingZeros());
43861  };
43862
43863  // ():void
43864  this.skipExpGolomb = function() {
43865    this.skipBits(1 + this.skipLeadingZeros());
43866  };
43867
43868  // ():uint
43869  this.readUnsignedExpGolomb = function() {
43870    var clz = this.skipLeadingZeros(); // :uint
43871    return this.readBits(clz + 1) - 1;
43872  };
43873
43874  // ():int
43875  this.readExpGolomb = function() {
43876    var valu = this.readUnsignedExpGolomb(); // :int
43877    if (0x01 & valu) {
43878      // the number is odd if the low order bit is set
43879      return (1 + valu) >>> 1; // add 1 to make it even, and divide by 2
43880    }
43881    return -1 * (valu >>> 1); // divide by two then make it negative
43882  };
43883
43884  // Some convenience functions
43885  // :Boolean
43886  this.readBoolean = function() {
43887    return this.readBits(1) === 1;
43888  };
43889
43890  // ():int
43891  this.readUnsignedByte = function() {
43892    return this.readBits(8);
43893  };
43894
43895  this.loadWord();
43896};
43897
43898module.exports = ExpGolomb;
43899
43900},{}],62:[function(require,module,exports){
43901/**
43902 * mux.js
43903 *
43904 * Copyright (c) 2014 Brightcove
43905 * All rights reserved.
43906 *
43907 * A lightweight readable stream implemention that handles event dispatching.
43908 * Objects that inherit from streams should call init in their constructors.
43909 */
43910'use strict';
43911
43912var Stream = function() {
43913  this.init = function() {
43914    var listeners = {};
43915    /**
43916     * Add a listener for a specified event type.
43917     * @param type {string} the event name
43918     * @param listener {function} the callback to be invoked when an event of
43919     * the specified type occurs
43920     */
43921    this.on = function(type, listener) {
43922      if (!listeners[type]) {
43923        listeners[type] = [];
43924      }
43925      listeners[type] = listeners[type].concat(listener);
43926    };
43927    /**
43928     * Remove a listener for a specified event type.
43929     * @param type {string} the event name
43930     * @param listener {function} a function previously registered for this
43931     * type of event through `on`
43932     */
43933    this.off = function(type, listener) {
43934      var index;
43935      if (!listeners[type]) {
43936        return false;
43937      }
43938      index = listeners[type].indexOf(listener);
43939      listeners[type] = listeners[type].slice();
43940      listeners[type].splice(index, 1);
43941      return index > -1;
43942    };
43943    /**
43944     * Trigger an event of the specified type on this stream. Any additional
43945     * arguments to this function are passed as parameters to event listeners.
43946     * @param type {string} the event name
43947     */
43948    this.trigger = function(type) {
43949      var callbacks, i, length, args;
43950      callbacks = listeners[type];
43951      if (!callbacks) {
43952        return;
43953      }
43954      // Slicing the arguments on every invocation of this method
43955      // can add a significant amount of overhead. Avoid the
43956      // intermediate object creation for the common case of a
43957      // single callback argument
43958      if (arguments.length === 2) {
43959        length = callbacks.length;
43960        for (i = 0; i < length; ++i) {
43961          callbacks[i].call(this, arguments[1]);
43962        }
43963      } else {
43964        args = [];
43965        i = arguments.length;
43966        for (i = 1; i < arguments.length; ++i) {
43967          args.push(arguments[i]);
43968        }
43969        length = callbacks.length;
43970        for (i = 0; i < length; ++i) {
43971          callbacks[i].apply(this, args);
43972        }
43973      }
43974    };
43975    /**
43976     * Destroys the stream and cleans up.
43977     */
43978    this.dispose = function() {
43979      listeners = {};
43980    };
43981  };
43982};
43983
43984/**
43985 * Forwards all `data` events on this stream to the destination stream. The
43986 * destination stream should provide a method `push` to receive the data
43987 * events as they arrive.
43988 * @param destination {stream} the stream that will receive all `data` events
43989 * @param autoFlush {boolean} if false, we will not call `flush` on the destination
43990 *                            when the current stream emits a 'done' event
43991 * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
43992 */
43993Stream.prototype.pipe = function(destination) {
43994  this.on('data', function(data) {
43995    destination.push(data);
43996  });
43997
43998  this.on('done', function(flushSource) {
43999    destination.flush(flushSource);
44000  });
44001
44002  return destination;
44003};
44004
44005// Default stream functions that are expected to be overridden to perform
44006// actual work. These are provided by the prototype as a sort of no-op
44007// implementation so that we don't have to check for their existence in the
44008// `pipe` function above.
44009Stream.prototype.push = function(data) {
44010  this.trigger('data', data);
44011};
44012
44013Stream.prototype.flush = function(flushSource) {
44014  this.trigger('done', flushSource);
44015};
44016
44017module.exports = Stream;
44018
44019},{}],63:[function(require,module,exports){
44020/
44020* jshint ignore:start */
44021(function(root) { 
44022/* jshint ignore:end */
44023  var URLToolkit = {
44024    // build an absolute URL from a relative one using the provided baseURL
44025    // if relativeURL is an absolute URL it will be returned as is.
44026    buildAbsoluteURL: function(baseURL, relativeURL) {
44027      // remove any remaining space and CRLF
44028      relativeURL = relativeURL.trim();
44029      if (/^[a-z]+:/i.test(relativeURL)) {
44030        // complete url, not relative
44031        return relativeURL;
44032      }
44033
44034      var relativeURLQuery = null;
44035      var relativeURLHash = null;
44036
44037      var relativeURLHashSplit = /^([^#]*)(.*)$/.exec(relativeURL);
44038      if (relativeURLHashSplit) {
44039        relativeURLHash = relativeURLHashSplit[2];
44040        relativeURL = relativeURLHashSplit[1];
44041      }
44042      var relativeURLQuerySplit = /^([^\?]*)(.*)$/.exec(relativeURL);
44043      if (relativeURLQuerySplit) {
44044        relativeURLQuery = relativeURLQuerySplit[2];
44045        relativeURL = relativeURLQuerySplit[1];
44046      }
44047
44048      var baseURLHashSplit = /^([^#]*)(.*)$/.exec(baseURL);
44049      if (baseURLHashSplit) {
44050        baseURL = baseURLHashSplit[1];
44051      }
44052      var baseURLQuerySplit = /^([^\?]*)(.*)$/.exec(baseURL);
44053      if (baseURLQuerySplit) {
44054        baseURL = baseURLQuerySplit[1];
44055      }
44056
44057      var baseURLDomainSplit = /^(([a-z]+:)?\/\/[^:\/]+(:[0-9]+)?)?(\/?.*)$/i.exec(baseURL);
44058      if (!baseURLDomainSplit) {
44059        throw new Error('Error trying to parse base URL.');
44060      }
44061      
44062      // e.g. 'http:', 'https:', ''
44063      var baseURLProtocol = baseURLDomainSplit[2] || '';
44064      // e.g. 'http://example.com', '//example.com', ''
44065      var baseURLProtocolDomain = baseURLDomainSplit[1] || '';
44066      // e.g. '/a/b/c/playlist.m3u8', 'a/b/c/playlist.m3u8'
44067      var baseURLPath = baseURLDomainSplit[4];
44068      if (baseURLPath.indexOf('/') !== 0 && baseURLProtocolDomain !== '') {
44069        // this handles a base url of http://example.com (missing last slash)
44070        baseURLPath = '/'+baseURLPath;
44071      }
44072
44073      var builtURL = null;
44074      if (/^\/\//.test(relativeURL)) {
44075        // relative url starts wth '//' so copy protocol (which may be '' if baseUrl didn't provide one)
44076        builtURL = baseURLProtocol+'//'+URLToolkit.buildAbsolutePath('', relativeURL.substring(2));
44077      }
44078      else if (/^\//.test(relativeURL)) {
44079        // relative url starts with '/' so start from root of domain
44080        builtURL = baseURLProtocolDomain+'/'+URLToolkit.buildAbsolutePath('', relativeURL.substring(1));
44081      }
44082      else {
44083        builtURL = URLToolkit.buildAbsolutePath(baseURLProtocolDomain+baseURLPath, relativeURL);
44084      }
44085
44086      // put the query and hash parts back
44087      if (relativeURLQuery) {
44088        builtURL += relativeURLQuery;
44089      }
44090      if (relativeURLHash) {
44091        builtURL += relativeURLHash;
44092      }
44093      return builtURL;
44094    },
44095
44096    // build an absolute path using the provided basePath
44097    // adapted from https://developer.mozilla.org/en-US/docs/Web/API/document/cookie#Using_relative_URLs_in_the_path_parameter
44098    // this does not handle the case where relativePath is "/" or "//". These cases should be handled outside this.
44099    buildAbsolutePath: function(basePath, relativePath) {
44100      var sRelPath = relativePath;
44101      var nUpLn, sDir = '', sPath = basePath.replace(/[^\/]*$/, sRelPath.replace(/(\/|^)(?:\.?\/+)+/g, '$1'));
44102      for (var nEnd, nStart = 0; nEnd = sPath.indexOf('/../', nStart), nEnd > -1; nStart = nEnd + nUpLn) {
44103        nUpLn = /^\/(?:\.\.\/)*/.exec(sPath.slice(nEnd))[0].length;
44104        sDir = (sDir + sPath.substring(nStart, nEnd)).replace(new RegExp('(?:\\\/+[^\\\/]*){0,' + ((nUpLn - 1) / 3) + '}$'), '/');
44105      }
44106      return sDir + sPath.substr(nStart)
vendor: 21,510 bytes, lines 44106-44706
44106;
44107    }
44108  };
44109
44110/* jshint ignore:start */
44111  if(typeof exports === 'object' && typeof module === 'object')
44112    module.exports = URLToolkit;
44113  else if(typeof define === 'function' && define.amd)
44114    define([], function() { return URLToolkit; });
44115  else if(typeof exports === 'object')
44116    exports["URLToolkit"] = URLToolkit;
44117  else
44118    root["URLToolkit"] = URLToolkit;
44119})(this);
44120/* jshint ignore:end */
44121
44122},{}],64:[function(require,module,exports){
44123(function (global){
44124/**
44125 * @file add-text-track-data.js
44126 */
44127'use strict';
44128
44129Object.defineProperty(exports, '__esModule', {
44130  value: true
44131});
44132
44133function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
44134
44135var _globalWindow = require('global/window');
44136
44137var _globalWindow2 = _interopRequireDefault(_globalWindow);
44138
44139var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
44140
44141var _videoJs2 = _interopRequireDefault(_videoJs);
44142
44143/**
44144 * Define properties on a cue for backwards compatability,
44145 * but warn the user that the way that they are using it
44146 * is depricated and will be removed at a later date.
44147 *
44148 * @param {Cue} cue the cue to add the properties on
44149 * @private
44150 */
44151var deprecateOldCue = function deprecateOldCue(cue) {
44152  Object.defineProperties(cue.frame, {
44153    id: {
44154      get: function get() {
44155        _videoJs2['default'].log.warn('cue.frame.id is deprecated. Use cue.value.key instead.');
44156        return cue.value.key;
44157      }
44158    },
44159    value: {
44160      get: function get() {
44161        _videoJs2['default'].log.warn('cue.frame.value is deprecated. Use cue.value.data instead.');
44162        return cue.value.data;
44163      }
44164    },
44165    privateData: {
44166      get: function get() {
44167        _videoJs2['default'].log.warn('cue.frame.privateData is deprecated. Use cue.value.data instead.');
44168        return cue.value.data;
44169      }
44170    }
44171  });
44172};
44173
44174var durationOfVideo = function durationOfVideo(duration) {
44175  var dur = undefined;
44176
44177  if (isNaN(duration) || Math.abs(duration) === Infinity) {
44178    dur = Number.MAX_VALUE;
44179  } else {
44180    dur = duration;
44181  }
44182  return dur;
44183};
44184/**
44185 * Add text track data to a source handler given the captions and
44186 * metadata from the buffer.
44187 *
44188 * @param {Object} sourceHandler the flash or virtual source buffer
44189 * @param {Array} captionArray an array of caption data
44190 * @param {Array} metadataArray an array of meta data
44191 * @private
44192 */
44193var addTextTrackData = function addTextTrackData(sourceHandler, captionArray, metadataArray) {
44194  var Cue = _globalWindow2['default'].WebKitDataCue || _globalWindow2['default'].VTTCue;
44195
44196  if (captionArray) {
44197    captionArray.forEach(function (caption) {
44198      var track = caption.stream;
44199
44200      this.inbandTextTracks_[track].addCue(new Cue(caption.startTime + this.timestampOffset, caption.endTime + this.timestampOffset, caption.text));
44201    }, sourceHandler);
44202  }
44203
44204  if (metadataArray) {
44205    (function () {
44206      var videoDuration = durationOfVideo(sourceHandler.mediaSource_.duration);
44207
44208      metadataArray.forEach(function (metadata) {
44209        var time = metadata.cueTime + this.timestampOffset;
44210
44211        metadata.frames.forEach(function (frame) {
44212          var cue = new Cue(time, time, frame.value || frame.url || frame.data || '');
44213
44214          cue.frame = frame;
44215          cue.value = frame;
44216          deprecateOldCue(cue);
44217
44218          this.metadataTrack_.addCue(cue);
44219        }, this);
44220      }, sourceHandler);
44221
44222      // Updating the metadeta cues so that
44223      // the endTime of each cue is the startTime of the next cue
44224      // the endTime of last cue is the duration of the video
44225      if (sourceHandler.metadataTrack_ && sourceHandler.metadataTrack_.cues && sourceHandler.metadataTrack_.cues.length) {
44226        (function () {
44227          var cues = sourceHandler.metadataTrack_.cues;
44228          var cuesArray = [];
44229
44230          // Create a copy of the TextTrackCueList...
44231          // ...disregarding cues with a falsey value
44232          for (var i = 0; i < cues.length; i++) {
44233            if (cues[i]) {
44234              cuesArray.push(cues[i]);
44235            }
44236          }
44237
44238          // Group cues by their startTime value
44239          var cuesGroupedByStartTime = cuesArray.reduce(function (obj, cue) {
44240            var timeSlot = obj[cue.startTime] || [];
44241
44242            timeSlot.push(cue);
44243            obj[cue.startTime] = timeSlot;
44244
44245            return obj;
44246          }, {});
44247
44248          // Sort startTimes by ascending order
44249          var sortedStartTimes = Object.keys(cuesGroupedByStartTime).sort(function (a, b) {
44250            return Number(a) - Number(b);
44251          });
44252
44253          // Map each cue group's endTime to the next group's startTime
44254          sortedStartTimes.forEach(function (startTime, idx) {
44255            var cueGroup = cuesGroupedByStartTime[startTime];
44256            var nextTime = Number(sortedStartTimes[idx + 1]) || videoDuration;
44257
44258            // Map each cue's endTime the next group's startTime
44259            cueGroup.forEach(function (cue) {
44260              cue.endTime = nextTime;
44261            });
44262          });
44263        })();
44264      }
44265    })();
44266  }
44267};
44268
44269exports['default'] = {
44270  addTextTrackData: addTextTrackData,
44271  durationOfVideo: durationOfVideo
44272};
44273module.exports = exports['default'];
44274}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
44275},{"global/window":32}],65:[function(require,module,exports){
44276/**
44277 * @file codec-utils.js
44278 */
44279
44280/**
44281 * Check if a codec string refers to an audio codec.
44282 *
44283 * @param {String} codec codec string to check
44284 * @return {Boolean} if this is an audio codec
44285 * @private
44286 */
44287'use strict';
44288
44289Object.defineProperty(exports, '__esModule', {
44290  value: true
44291});
44292var isAudioCodec = function isAudioCodec(codec) {
44293  return (/mp4a\.\d+.\d+/i.test(codec)
44294  );
44295};
44296
44297/**
44298 * Check if a codec string refers to a video codec.
44299 *
44300 * @param {String} codec codec string to check
44301 * @return {Boolean} if this is a video codec
44302 * @private
44303 */
44304var isVideoCodec = function isVideoCodec(codec) {
44305  return (/avc1\.[\da-f]+/i.test(codec)
44306  );
44307};
44308
44309/**
44310 * Parse a content type header into a type and parameters
44311 * object
44312 *
44313 * @param {String} type the content type header
44314 * @return {Object} the parsed content-type
44315 * @private
44316 */
44317var parseContentType = function parseContentType(type) {
44318  var object = { type: '', parameters: {} };
44319  var parameters = type.trim().split(';');
44320
44321  // first parameter should always be content-type
44322  object.type = parameters.shift().trim();
44323  parameters.forEach(function (parameter) {
44324    var pair = parameter.trim().split('=');
44325
44326    if (pair.length > 1) {
44327      var _name = pair[0].replace(/"/g, '').trim();
44328      var value = pair[1].replace(/"/g, '').trim();
44329
44330      object.parameters[_name] = value;
44331    }
44332  });
44333
44334  return object;
44335};
44336
44337/**
44338 * Replace the old apple-style `avc1.<dd>.<dd>` codec string with the standard
44339 * `avc1.<hhhhhh>`
44340 *
44341 * @param {Array} codecs an array of codec strings to fix
44342 * @return {Array} the translated codec array
44343 * @private
44344 */
44345var translateLegacyCodecs = function translateLegacyCodecs(codecs) {
44346  return codecs.map(function (codec) {
44347    return codec.replace(/avc1\.(\d+)\.(\d+)/i, function (orig, profile, avcLevel) {
44348      var profileHex = ('00' + Number(profile).toString(16)).slice(-2);
44349      var avcLevelHex = ('00' + Number(avcLevel).toString(16)).slice(-2);
44350
44351      return 'avc1.' + profileHex + '00' + avcLevelHex;
44352    });
44353  });
44354};
44355
44356exports['default'] = {
44357  isAudioCodec: isAudioCodec,
44358  parseContentType: parseContentType,
44359  isVideoCodec: isVideoCodec,
44360  translateLegacyCodecs: translateLegacyCodecs
44361};
44362module.exports = exports['default'];
44363},{}],66:[function(require,module,exports){
44364/**
44365 * @file create-text-tracks-if-necessary.js
44366 */
44367
44368/**
44369 * Create text tracks on video.js if they exist on a segment.
44370 *
44371 * @param {Object} sourceBuffer the VSB or FSB
44372 * @param {Object} mediaSource the HTML or Flash media source
44373 * @param {Object} segment the segment that may contain the text track
44374 * @private
44375 */
44376'use strict';
44377
44378Object.defineProperty(exports, '__esModule', {
44379  value: true
44380});
44381var createTextTracksIfNecessary = function createTextTracksIfNecessary(sourceBuffer, mediaSource, segment) {
44382  var player = mediaSource.player_;
44383
44384  // create an in-band caption track if one is present in the segment
44385  if (segment.captions && segment.captions.length) {
44386    if (!sourceBuffer.inbandTextTracks_) {
44387      sourceBuffer.inbandTextTracks_ = {};
44388    }
44389
44390    for (var trackId in segment.captionStreams) {
44391      if (!sourceBuffer.inbandTextTracks_[trackId]) {
44392        player.tech_.trigger({ type: 'usage', name: 'hls-608' });
44393        var track = player.textTracks().getTrackById(trackId);
44394
44395        if (track) {
44396          // Resuse an existing track with a CC# id because this was
44397          // very likely created by videojs-contrib-hls from information
44398          // in the m3u8 for us to use
44399          sourceBuffer.inbandTextTracks_[trackId] = track;
44400        } else {
44401          // Otherwise, create a track with the default `CC#` label and
44402          // without a language
44403          sourceBuffer.inbandTextTracks_[trackId] = player.addRemoteTextTrack({
44404            kind: 'captions',
44405            id: trackId,
44406            label: trackId
44407          }, false).track;
44408        }
44409      }
44410    }
44411  }
44412
44413  if (segment.metadata && segment.metadata.length && !sourceBuffer.metadataTrack_) {
44414    sourceBuffer.metadataTrack_ = player.addRemoteTextTrack({
44415      kind: 'metadata',
44416      label: 'Timed Metadata'
44417    }, false).track;
44418    sourceBuffer.metadataTrack_.inBandMetadataTrackDispatchType = segment.metadata.dispatchType;
44419  }
44420};
44421
44422exports['default'] = createTextTracksIfNecessary;
44423module.exports = exports['default'];
44424},{}],67:[function(require,module,exports){
44425/**
44426 * @file flash-constants.js
44427 */
44428/**
44429 * The maximum size in bytes for append operations to the video.js
44430 * SWF. Calling through to Flash blocks and can be expensive so
44431 * we chunk data and pass through 4KB at a time, yielding to the
44432 * browser between chunks. This gives a theoretical maximum rate of
44433 * 1MB/s into Flash. Any higher and we begin to drop frames and UI
44434 * responsiveness suffers.
44435 *
44436 * @private
44437 */
44438"use strict";
44439
44440Object.defineProperty(exports, "__esModule", {
44441  value: true
44442});
44443var flashConstants = {
44444  // times in milliseconds
44445  TIME_BETWEEN_CHUNKS: 1,
44446  BYTES_PER_CHUNK: 1024 * 32
44447};
44448
44449exports["default"] = flashConstants;
44450module.exports = exports["default"];
44451},{}],68:[function(require,module,exports){
44452(function (global){
44453/**
44454 * @file flash-media-source.js
44455 */
44456'use strict';
44457
44458Object.defineProperty(exports, '__esModule', {
44459  value: true
44460});
44461
44462var _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; }; })();
44463
44464var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
44465
44466function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
44467
44468function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
44469
44470function _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; }
44471
44472var _globalDocument = require('global/document');
44473
44474var _globalDocument2 = _interopRequireDefault(_globalDocument);
44475
44476var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
44477
44478var _videoJs2 = _interopRequireDefault(_videoJs);
44479
44480var _flashSourceBuffer = require('./flash-source-buffer');
44481
44482var _flashSourceBuffer2 = _interopRequireDefault(_flashSourceBuffer);
44483
44484var _flashConstants = require('./flash-constants');
44485
44486var _flashConstants2 = _interopRequireDefault(_flashConstants);
44487
44488var _codecUtils = require('./codec-utils');
44489
44490/**
44491 * A flash implmentation of HTML MediaSources and a polyfill
44492 * for browsers that don't support native or HTML MediaSources..
44493 *
44494 * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource
44495 * @class FlashMediaSource
44496 * @extends videojs.EventTarget
44497 */
44498
44499var FlashMediaSource = (function (_videojs$EventTarget) {
44500  _inherits(FlashMediaSource, _videojs$EventTarget);
44501
44502  function FlashMediaSource() {
44503    var _this = this;
44504
44505    _classCallCheck(this, FlashMediaSource);
44506
44507    _get(Object.getPrototypeOf(FlashMediaSource.prototype), 'constructor', this).call(this);
44508    this.sourceBuffers = [];
44509    this.readyState = 'closed';
44510
44511    this.on(['sourceopen', 'webkitsourceopen'], function (event) {
44512      // find the swf where we will push media data
44513      _this.swfObj = _globalDocument2['default'].getElementById(event.swfId);
44514      _this.player_ = (0, _videoJs2['default'])(_this.swfObj.parentNode);
44515      _this.tech_ = _this.swfObj.tech;
44516      _this.readyState = 'open';
44517
44518      _this.tech_.on('seeking', function () {
44519        var i = _this.sourceBuffers.length;
44520
44521        while (i--) {
44522          _this.sourceBuffers[i].abort();
44523        }
44524      });
44525
44526      // trigger load events
44527      if (_this.swfObj) {
44528        _this.swfObj.vjs_load();
44529      }
44530    });
44531  }
44532
44533  /**
44534    * Set or return the presentation duration.
44535    *
44536    * @param {Double} value the duration of the media in seconds
44537    * @param {Double} the current presentation duration
44538    * @link http://www.w3.org/TR/media-source/#widl-MediaSource-duration
44539    */
44540
44541  /**
44542   * We have this function so that the html and flash interfaces
44543   * are the same.
44544   *
44545   * @private
44546   */
44547
44548  _createClass(FlashMediaSource, [{
44549    key: 'addSeekableRange_',
44550    value: function addSeekableRange_() {}
44551    // intentional no-op
44552
44553    /**
44554     * Create a new flash source buffer and add it to our flash media source.
44555     *
44556     * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/addSourceBuffer
44557     * @param {String} type the content-type of the source
44558     * @return {Object} the flash source buffer
44559     */
44560
44561  }, {
44562    key: 'addSourceBuffer',
44563    value: function addSourceBuffer(type) {
44564      var parsedType = (0, _codecUtils.parseContentType)(type);
44565      var sourceBuffer = undefined;
44566
44567      // if this is an FLV type, we'll push data to flash
44568      if (parsedType.type === 'video/mp2t' || parsedType.type === 'audio/mp2t') {
44569        // Flash source buffers
44570        sourceBuffer = new _flashSourceBuffer2['default'](this);
44571      } else {
44572        throw new Error('NotSupportedError (Video.js)');
44573      }
44574
44575      this.sourceBuffers.push(sourceBuffer);
44576      return sourceBuffer;
44577    }
44578
44579    /**
44580     * Signals the end of the stream.
44581     *
44582     * @link https://w3c.github.io/media-source/#widl-MediaSource-endOfStream-void-EndOfStreamError-error
44583     * @param {String=} error Signals that a playback error
44584     * has occurred. If specified, it must be either "network" or
44585     * "decode".
44586     */
44587  }, {
44588    key: 'endOfStream',
44589    value: function endOfStream(error) {
44590      if (error === 'network') {
44591        // MEDIA_ERR_NETWORK
44592        this.tech_.error(2);
44593      } else if (error === 'decode') {
44594        // MEDIA_ERR_DECODE
44595        this.tech_.error(3);
44596      }
44597      if (this.readyState !== 'ended') {
44598        this.readyState = 'ended';
44599        this.swfObj.vjs_endOfStream();
44600      }
44601    }
44602  }]);
44603
44604  return FlashMediaSource;
44605})(_videoJs2['default'].EventTarget);
44606
44607exports['default'] = FlashMediaSource;
44608try {
44609  Object.defineProperty(FlashMediaSource.prototype, 'duration', {
44610    /**
44611     * Return the presentation duration.
44612     *
44613     * @return {Double} the duration of the media in seconds
44614     * @link http://www.w3.org/TR/media-source/#widl-MediaSource-duration
44615     */
44616    get: function get() {
44617      if (!this.swfObj) {
44618        return NaN;
44619      }
44620      // get the current duration from the SWF
44621      return this.swfObj.vjs_getProperty('duration');
44622    },
44623    /**
44624     * Set the presentation duration.
44625     *
44626     * @param {Double} value the duration of the media in seconds
44627     * @return {Double} the duration of the media in seconds
44628     * @link http://www.w3.org/TR/media-source/#widl-MediaSource-duration
44629     */
44630    set: function set(value) {
44631      var i = undefined;
44632      var oldDuration = this.swfObj.vjs_getProperty('duration');
44633
44634      this.swfObj.vjs_setProperty('duration', value);
44635
44636      if (value < oldDuration) {
44637        // In MSE, this triggers the range removal algorithm which causes
44638        // an update to occur
44639        for (i = 0; i < this.sourceBuffers.length; i++) {
44640          this.sourceBuffers[i].remove(value, oldDuration);
44641        }
44642      }
44643
44644      return value;
44645    }
44646  });
44647} catch (e) {
44648  // IE8 throws if defineProperty is called on a non-DOM node. We
44649  // don't support IE8 but we shouldn't throw an error if loaded
44650  // there.
44651  FlashMediaSource.prototype.duration = NaN;
44652}
44653
44654for (var property in _flashConstants2['default']) {
44655  FlashMediaSource[property] = _flashConstants2['default'][property];
44656}
44657module.exports = exports['default'];
44658}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
44659},{"./codec-utils":65,"./flash-constants":67,"./flash-source-buffer":69,"global/document":31}],69:[function(require,module,exports){
44660(function (global){
44661/**
44662 * @file flash-source-buffer.js
44663 */
44664'use strict';
44665
44666Object.defineProperty(exports, '__esModule', {
44667  value: true
44668});
44669
44670var _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; }; })();
44671
44672var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
44673
44674function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
44675
44676function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
44677
44678function _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; }
44679
44680var _globalWindow = require('global/window');
44681
44682var _globalWindow2 = _interopRequireDefault(_globalWindow);
44683
44684var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
44685
44686var _videoJs2 = _interopRequireDefault(_videoJs);
44687
44688var _muxJsLibFlv = require('mux.js/lib/flv');
44689
44690var _muxJsLibFlv2 = _interopRequireDefault(_muxJsLibFlv);
44691
44692var _removeCuesFromTrack = require('./remove-cues-from-track');
44693
44694var _removeCuesFromTrack2 = _interopRequireDefault(_removeCuesFromTrack);
44695
44696var _createTextTracksIfNecessary = require('./create-text-tracks-if-necessary');
44697
44698var _createTextTracksIfNecessary2 = _interopRequireDefault(_createTextTracksIfNecessary);
44699
44700var _addTextTrackData = require('./add-text-track-data');
44701
44702var _flashTransmuxerWorker = require('./flash-transmuxer-worker');
44703
44704var _flashTransmuxerWorker2 = _interopRequireDefault(_flashTransmuxerWorker);
44705
44706var _webw
vendor: 20,239 bytes, lines 44706-45279
44706orkify = require('webworkify');
44707
44708var _webworkify2 = _interopRequireDefault(_webworkify);
44709
44710var _flashConstants = require('./flash-constants');
44711
44712var _flashConstants2 = _interopRequireDefault(_flashConstants);
44713
44714/**
44715 * A wrapper around the setTimeout function that uses
44716 * the flash constant time between ticks value.
44717 *
44718 * @param {Function} func the function callback to run
44719 * @private
44720 */
44721var scheduleTick = function scheduleTick(func) {
44722  // Chrome doesn't invoke requestAnimationFrame callbacks
44723  // in background tabs, so use setTimeout.
44724  _globalWindow2['default'].setTimeout(func, _flashConstants2['default'].TIME_BETWEEN_CHUNKS);
44725};
44726
44727/**
44728 * Generates a random string of max length 6
44729 *
44730 * @return {String} the randomly generated string
44731 * @function generateRandomString
44732 * @private
44733 */
44734var generateRandomString = function generateRandomString() {
44735  return Math.random().toString(36).slice(2, 8);
44736};
44737
44738/**
44739 * Round a number to a specified number of places much like
44740 * toFixed but return a number instead of a string representation.
44741 *
44742 * @param {Number} num A number
44743 * @param {Number} places The number of decimal places which to
44744 * round
44745 * @private
44746 */
44747var toDecimalPlaces = function toDecimalPlaces(num, places) {
44748  if (typeof places !== 'number' || places < 0) {
44749    places = 0;
44750  }
44751
44752  var scale = Math.pow(10, places);
44753
44754  return Math.round(num * scale) / scale;
44755};
44756
44757/**
44758 * A SourceBuffer implementation for Flash rather than HTML.
44759 *
44760 * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource
44761 * @param {Object} mediaSource the flash media source
44762 * @class FlashSourceBuffer
44763 * @extends videojs.EventTarget
44764 */
44765
44766var FlashSourceBuffer = (function (_videojs$EventTarget) {
44767  _inherits(FlashSourceBuffer, _videojs$EventTarget);
44768
44769  function FlashSourceBuffer(mediaSource) {
44770    var _this = this;
44771
44772    _classCallCheck(this, FlashSourceBuffer);
44773
44774    _get(Object.getPrototypeOf(FlashSourceBuffer.prototype), 'constructor', this).call(this);
44775    var encodedHeader = undefined;
44776
44777    // Start off using the globally defined value but refine
44778    // as we append data into flash
44779    this.chunkSize_ = _flashConstants2['default'].BYTES_PER_CHUNK;
44780
44781    // byte arrays queued to be appended
44782    this.buffer_ = [];
44783
44784    // the total number of queued bytes
44785    this.bufferSize_ = 0;
44786
44787    // to be able to determine the correct position to seek to, we
44788    // need to retain information about the mapping between the
44789    // media timeline and PTS values
44790    this.basePtsOffset_ = NaN;
44791
44792    this.mediaSource_ = mediaSource;
44793
44794    this.audioBufferEnd_ = NaN;
44795    this.videoBufferEnd_ = NaN;
44796
44797    // indicates whether the asynchronous continuation of an operation
44798    // is still being processed
44799    // see https://w3c.github.io/media-source/#widl-SourceBuffer-updating
44800    this.updating = false;
44801    this.timestampOffset_ = 0;
44802
44803    encodedHeader = _globalWindow2['default'].btoa(String.fromCharCode.apply(null, Array.prototype.slice.call(_muxJsLibFlv2['default'].getFlvHeader())));
44804
44805    // create function names with added randomness for the global callbacks flash will use
44806    // to get data from javascript into the swf. Random strings are added as a safety
44807    // measure for pages with multiple players since these functions will be global
44808    // instead of per instance. When making a call to the swf, the browser generates a
44809    // try catch code snippet, but just takes the function name and writes out an unquoted
44810    // call to that function. If the player id has any special characters, this will result
44811    // in an error, so safePlayerId replaces all special characters to '_'
44812    var safePlayerId = this.mediaSource_.player_.id().replace(/[^a-zA-Z0-9]/g, '_');
44813
44814    this.flashEncodedHeaderName_ = 'vjs_flashEncodedHeader_' + safePlayerId + generateRandomString();
44815    this.flashEncodedDataName_ = 'vjs_flashEncodedData_' + safePlayerId + generateRandomString();
44816
44817    _globalWindow2['default'][this.flashEncodedHeaderName_] = function () {
44818      delete _globalWindow2['default'][_this.flashEncodedHeaderName_];
44819      return encodedHeader;
44820    };
44821
44822    this.mediaSource_.swfObj.vjs_appendChunkReady(this.flashEncodedHeaderName_);
44823
44824    this.transmuxer_ = (0, _webworkify2['default'])(_flashTransmuxerWorker2['default']);
44825    this.transmuxer_.postMessage({ action: 'init', options: {} });
44826    this.transmuxer_.onmessage = function (event) {
44827      if (event.data.action === 'data') {
44828        _this.receiveBuffer_(event.data.segment);
44829      }
44830    };
44831
44832    this.one('updateend', function () {
44833      _this.mediaSource_.tech_.trigger('loadedmetadata');
44834    });
44835
44836    Object.defineProperty(this, 'timestampOffset', {
44837      get: function get() {
44838        return this.timestampOffset_;
44839      },
44840      set: function set(val) {
44841        if (typeof val === 'number' && val >= 0) {
44842          this.timestampOffset_ = val;
44843          // We have to tell flash to expect a discontinuity
44844          this.mediaSource_.swfObj.vjs_discontinuity();
44845          // the media <-> PTS mapping must be re-established after
44846          // the discontinuity
44847          this.basePtsOffset_ = NaN;
44848          this.audioBufferEnd_ = NaN;
44849          this.videoBufferEnd_ = NaN;
44850
44851          this.transmuxer_.postMessage({ action: 'reset' });
44852        }
44853      }
44854    });
44855
44856    Object.defineProperty(this, 'buffered', {
44857      get: function get() {
44858        if (!this.mediaSource_ || !this.mediaSource_.swfObj || !('vjs_getProperty' in this.mediaSource_.swfObj)) {
44859          return _videoJs2['default'].createTimeRange();
44860        }
44861
44862        var buffered = this.mediaSource_.swfObj.vjs_getProperty('buffered');
44863
44864        if (buffered && buffered.length) {
44865          buffered[0][0] = toDecimalPlaces(buffered[0][0], 3);
44866          buffered[0][1] = toDecimalPlaces(buffered[0][1], 3);
44867        }
44868        return _videoJs2['default'].createTimeRanges(buffered);
44869      }
44870    });
44871
44872    // On a seek we remove all text track data since flash has no concept
44873    // of a buffered-range and everything else is reset on seek
44874    this.mediaSource_.player_.on('seeked', function () {
44875      (0, _removeCuesFromTrack2['default'])(0, Infinity, _this.metadataTrack_);
44876      if (_this.inbandTextTracks_) {
44877        for (var track in _this.inbandTextTracks_) {
44878          (0, _removeCuesFromTrack2['default'])(0, Infinity, _this.inbandTextTracks_[track]);
44879        }
44880      }
44881    });
44882
44883    var onHlsReset = this.onHlsReset_.bind(this);
44884
44885    this.mediaSource_.player_.tech_.on('hls-reset', onHlsReset);
44886
44887    this.mediaSource_.player_.tech_.hls.on('dispose', function () {
44888      _this.transmuxer_.terminate();
44889      _this.mediaSource_.player_.tech_.off('hls-reset', onHlsReset);
44890    });
44891  }
44892
44893  /**
44894   * Append bytes to the sourcebuffers buffer, in this case we
44895   * have to append it to swf object.
44896   *
44897   * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/appendBuffer
44898   * @param {Array} bytes
44899   */
44900
44901  _createClass(FlashSourceBuffer, [{
44902    key: 'appendBuffer',
44903    value: function appendBuffer(bytes) {
44904      var error = undefined;
44905
44906      if (this.updating) {
44907        error = new Error('SourceBuffer.append() cannot be called ' + 'while an update is in progress');
44908        error.name = 'InvalidStateError';
44909        error.code = 11;
44910        throw error;
44911      }
44912      this.updating = true;
44913      this.mediaSource_.readyState = 'open';
44914      this.trigger({ type: 'update' });
44915
44916      this.transmuxer_.postMessage({
44917        action: 'push',
44918        data: bytes.buffer,
44919        byteOffset: bytes.byteOffset,
44920        byteLength: bytes.byteLength
44921      }, [bytes.buffer]);
44922      this.transmuxer_.postMessage({ action: 'flush' });
44923    }
44924
44925    /**
44926     * Reset the parser and remove any data queued to be sent to the SWF.
44927     *
44928     * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/abort
44929     */
44930  }, {
44931    key: 'abort',
44932    value: function abort() {
44933      this.buffer_ = [];
44934      this.bufferSize_ = 0;
44935      this.mediaSource_.swfObj.vjs_abort();
44936
44937      // report any outstanding updates have ended
44938      if (this.updating) {
44939        this.updating = false;
44940        this.trigger({ type: 'updateend' });
44941      }
44942    }
44943
44944    /**
44945     * Flash cannot remove ranges already buffered in the NetStream
44946     * but seeking clears the buffer entirely. For most purposes,
44947     * having this operation act as a no-op is acceptable.
44948     *
44949     * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/remove
44950     * @param {Double} start start of the section to remove
44951     * @param {Double} end end of the section to remove
44952     */
44953  }, {
44954    key: 'remove',
44955    value: function remove(start, end) {
44956      (0, _removeCuesFromTrack2['default'])(start, end, this.metadataTrack_);
44957      if (this.inbandTextTracks_) {
44958        for (var track in this.inbandTextTracks_) {
44959          (0, _removeCuesFromTrack2['default'])(start, end, this.inbandTextTracks_[track]);
44960        }
44961      }
44962      this.trigger({ type: 'update' });
44963      this.trigger({ type: 'updateend' });
44964    }
44965
44966    /**
44967     * Receive a buffer from the flv.
44968     *
44969     * @param {Object} segment
44970     * @private
44971     */
44972  }, {
44973    key: 'receiveBuffer_',
44974    value: function receiveBuffer_(segment) {
44975      var _this2 = this;
44976
44977      // create an in-band caption track if one is present in the segment
44978      (0, _createTextTracksIfNecessary2['default'])(this, this.mediaSource_, segment);
44979      (0, _addTextTrackData.addTextTrackData)(this, segment.captions, segment.metadata);
44980
44981      // Do this asynchronously since convertTagsToData_ can be time consuming
44982      scheduleTick(function () {
44983        var flvBytes = _this2.convertTagsToData_(segment);
44984
44985        if (_this2.buffer_.length === 0) {
44986          scheduleTick(_this2.processBuffer_.bind(_this2));
44987        }
44988
44989        if (flvBytes) {
44990          _this2.buffer_.push(flvBytes);
44991          _this2.bufferSize_ += flvBytes.byteLength;
44992        }
44993      });
44994    }
44995
44996    /**
44997     * Append a portion of the current buffer to the SWF.
44998     *
44999     * @private
45000     */
45001  }, {
45002    key: 'processBuffer_',
45003    value: function processBuffer_() {
45004      var _this3 = this;
45005
45006      var chunkSize = _flashConstants2['default'].BYTES_PER_CHUNK;
45007
45008      if (!this.buffer_.length) {
45009        if (this.updating !== false) {
45010          this.updating = false;
45011          this.trigger({ type: 'updateend' });
45012        }
45013        // do nothing if the buffer is empty
45014        return;
45015      }
45016
45017      // concatenate appends up to the max append size
45018      var chunk = this.buffer_[0].subarray(0, chunkSize);
45019
45020      // requeue any bytes that won't make it this round
45021      if (chunk.byteLength < chunkSize || this.buffer_[0].byteLength === chunkSize) {
45022        this.buffer_.shift();
45023      } else {
45024        this.buffer_[0] = this.buffer_[0].subarray(chunkSize);
45025      }
45026
45027      this.bufferSize_ -= chunk.byteLength;
45028
45029      // base64 encode the bytes
45030      var binary = [];
45031      var length = chunk.byteLength;
45032
45033      for (var i = 0; i < length; i++) {
45034        binary.push(String.fromCharCode(chunk[i]));
45035      }
45036      var b64str = _globalWindow2['default'].btoa(binary.join(''));
45037
45038      _globalWindow2['default'][this.flashEncodedDataName_] = function () {
45039        // schedule another processBuffer to process any left over data or to
45040        // trigger updateend
45041        scheduleTick(_this3.processBuffer_.bind(_this3));
45042        delete _globalWindow2['default'][_this3.flashEncodedDataName_];
45043        return b64str;
45044      };
45045
45046      // Notify the swf that segment data is ready to be appended
45047      this.mediaSource_.swfObj.vjs_appendChunkReady(this.flashEncodedDataName_);
45048    }
45049
45050    /**
45051     * Turns an array of flv tags into a Uint8Array representing the
45052     * flv data. Also removes any tags that are before the current
45053     * time so that playback begins at or slightly after the right
45054     * place on a seek
45055     *
45056     * @private
45057     * @param {Object} segmentData object of segment data
45058     */
45059  }, {
45060    key: 'convertTagsToData_',
45061    value: function convertTagsToData_(segmentData) {
45062      var segmentByteLength = 0;
45063      var tech = this.mediaSource_.tech_;
45064      var videoTargetPts = 0;
45065      var segment = undefined;
45066      var videoTags = segmentData.tags.videoTags;
45067      var audioTags = segmentData.tags.audioTags;
45068
45069      // Establish the media timeline to PTS translation if we don't
45070      // have one already
45071      if (isNaN(this.basePtsOffset_) && (videoTags.length || audioTags.length)) {
45072        // We know there is at least one video or audio tag, but since we may not have both,
45073        // we use pts: Infinity for the missing tag. The will force the following Math.min
45074        // call will to use the proper pts value since it will always be less than Infinity
45075        var firstVideoTag = videoTags[0] || { pts: Infinity };
45076        var firstAudioTag = audioTags[0] || { pts: Infinity };
45077
45078        this.basePtsOffset_ = Math.min(firstAudioTag.pts, firstVideoTag.pts);
45079      }
45080
45081      if (tech.seeking()) {
45082        // Do not use previously saved buffer end values while seeking since buffer
45083        // is cleared on all seeks
45084        this.videoBufferEnd_ = NaN;
45085        this.audioBufferEnd_ = NaN;
45086      }
45087
45088      if (isNaN(this.videoBufferEnd_)) {
45089        if (tech.buffered().length) {
45090          videoTargetPts = tech.buffered().end(0) - this.timestampOffset;
45091        }
45092
45093        // Trim to currentTime if seeking
45094        if (tech.seeking()) {
45095          videoTargetPts = Math.max(videoTargetPts, tech.currentTime() - this.timestampOffset);
45096        }
45097
45098        // PTS values are represented in milliseconds
45099        videoTargetPts *= 1e3;
45100        videoTargetPts += this.basePtsOffset_;
45101      } else {
45102        // Add a fudge factor of 0.1 to the last video pts appended since a rendition change
45103        // could append an overlapping segment, in which case there is a high likelyhood
45104        // a tag could have a matching pts to videoBufferEnd_, which would cause
45105        // that tag to get appended by the tag.pts >= targetPts check below even though it
45106        // is a duplicate of what was previously appended
45107        videoTargetPts = this.videoBufferEnd_ + 0.1;
45108      }
45109
45110      // filter complete GOPs with a presentation time less than the seek target/end of buffer
45111      var currentIndex = videoTags.length;
45112
45113      // if the last tag is beyond videoTargetPts, then do not search the list for a GOP
45114      // since our videoTargetPts lies in a future segment
45115      if (currentIndex && videoTags[currentIndex - 1].pts >= videoTargetPts) {
45116        // Start by walking backwards from the end of the list until we reach a tag that
45117        // is equal to or less than videoTargetPts
45118        while (--currentIndex) {
45119          var currentTag = videoTags[currentIndex];
45120
45121          if (currentTag.pts > videoTargetPts) {
45122            continue;
45123          }
45124
45125          // if we see a keyFrame or metadata tag once we've gone below videoTargetPts,
45126          // exit the loop as this is the start of the GOP that we want to append
45127          if (currentTag.keyFrame || currentTag.metaDataTag) {
45128            break;
45129          }
45130        }
45131
45132        // We need to check if there are any metadata tags that come before currentIndex
45133        // as those will be metadata tags associated with the GOP we are appending
45134        // There could be 0 to 2 metadata tags that come before the currentIndex depending
45135        // on what videoTargetPts is and whether the transmuxer prepended metadata tags to this
45136        // key frame
45137        while (currentIndex) {
45138          var nextTag = videoTags[currentIndex - 1];
45139
45140          if (!nextTag.metaDataTag) {
45141            break;
45142          }
45143
45144          currentIndex--;
45145        }
45146      }
45147
45148      var filteredVideoTags = videoTags.slice(currentIndex);
45149
45150      var audioTargetPts = undefined;
45151
45152      if (isNaN(this.audioBufferEnd_)) {
45153        audioTargetPts = videoTargetPts;
45154      } else {
45155        // Add a fudge factor of 0.1 to the last video pts appended since a rendition change
45156        // could append an overlapping segment, in which case there is a high likelyhood
45157        // a tag could have a matching pts to videoBufferEnd_, which would cause
45158        // that tag to get appended by the tag.pts >= targetPts check below even though it
45159        // is a duplicate of what was previously appended
45160        audioTargetPts = this.audioBufferEnd_ + 0.1;
45161      }
45162
45163      if (filteredVideoTags.length) {
45164        // If targetPts intersects a GOP and we appended the tags for the GOP that came
45165        // before targetPts, we want to make sure to trim audio tags at the pts
45166        // of the first video tag to avoid brief moments of silence
45167        audioTargetPts = Math.min(audioTargetPts, filteredVideoTags[0].pts);
45168      }
45169
45170      // skip tags with a presentation time less than the seek target/end of buffer
45171      currentIndex = 0;
45172
45173      while (currentIndex < audioTags.length) {
45174        if (audioTags[currentIndex].pts >= audioTargetPts) {
45175          break;
45176        }
45177
45178        currentIndex++;
45179      }
45180
45181      var filteredAudioTags = audioTags.slice(currentIndex);
45182
45183      // update the audio and video buffer ends
45184      if (filteredAudioTags.length) {
45185        this.audioBufferEnd_ = filteredAudioTags[filteredAudioTags.length - 1].pts;
45186      }
45187      if (filteredVideoTags.length) {
45188        this.videoBufferEnd_ = filteredVideoTags[filteredVideoTags.length - 1].pts;
45189      }
45190
45191      var tags = this.getOrderedTags_(filteredVideoTags, filteredAudioTags);
45192
45193      if (tags.length === 0) {
45194        return;
45195      }
45196
45197      // If we are appending data that comes before our target pts, we want to tell
45198      // the swf to adjust its notion of current time to account for the extra tags
45199      // we are appending to complete the GOP that intersects with targetPts
45200      if (tags[0].pts < videoTargetPts && tech.seeking()) {
45201        var fudgeFactor = 1 / 30;
45202        var currentTime = tech.currentTime();
45203        var diff = (videoTargetPts - tags[0].pts) / 1e3;
45204        var adjustedTime = currentTime - diff;
45205
45206        if (adjustedTime < fudgeFactor) {
45207          adjustedTime = 0;
45208        }
45209
45210        try {
45211          this.mediaSource_.swfObj.vjs_adjustCurrentTime(adjustedTime);
45212        } catch (e) {
45213          // no-op for backwards compatability of swf. If adjustCurrentTime fails,
45214          // the swf may incorrectly report currentTime and buffered ranges
45215          // but should not affect playback over than the time displayed on the
45216          // progress bar is inaccurate
45217        }
45218      }
45219
45220      // concatenate the bytes into a single segment
45221      for (var i = 0; i < tags.length; i++) {
45222        segmentByteLength += tags[i].bytes.byteLength;
45223      }
45224      segment = new Uint8Array(segmentByteLength);
45225      for (var i = 0, j = 0; i < tags.length; i++) {
45226        segment.set(tags[i].bytes, j);
45227        j += tags[i].bytes.byteLength;
45228      }
45229
45230      return segment;
45231    }
45232
45233    /**
45234     * Assemble the FLV tags in decoder order.
45235     *
45236     * @private
45237     * @param {Array} videoTags list of video tags
45238     * @param {Array} audioTags list of audio tags
45239     */
45240  }, {
45241    key: 'getOrderedTags_',
45242    value: function getOrderedTags_(videoTags, audioTags) {
45243      var tag = undefined;
45244      var tags = [];
45245
45246      while (videoTags.length || audioTags.length) {
45247        if (!videoTags.length) {
45248          // only audio tags remain
45249          tag = audioTags.shift();
45250        } else if (!audioTags.length) {
45251          // only video tags remain
45252          tag = videoTags.shift();
45253        } else if (audioTags[0].dts < videoTags[0].dts) {
45254          // audio should be decoded next
45255          tag = audioTags.shift();
45256        } else {
45257          // video should be decoded next
45258          tag = videoTags.shift();
45259        }
45260
45261        tags.push(tag);
45262      }
45263
45264      return tags;
45265    }
45266  }, {
45267    key: 'onHlsReset_',
45268    value: function onHlsReset_() {
45269      this.transmuxer_.postMessage({ action: 'resetCaptions' });
45270    }
45271  }]);
45272
45273  return FlashSourceBuffer;
45274})(_videoJs2['default'].EventTarget);
45275
45276exports['default'] = FlashSourceBuffer;
45277module.exports = exports['default'];
45278}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
45279},{"./add-text-track-data":64,"./create-text-tracks-if-necessary":66,"./flash-constants":67,"./flash-transmuxer-worker":70,"./remove-cues-from-track":72,"global/window":32,"mux.js/lib/flv":46,"webwor
vendor: 12,774 bytes, lines 45279-45629
45279kify":76}],70:[function(require,module,exports){
45280/**
45281 * @file flash-transmuxer-worker.js
45282 */
45283'use strict';
45284
45285Object.defineProperty(exports, '__esModule', {
45286  value: true
45287});
45288
45289var _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; }; })();
45290
45291function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
45292
45293function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
45294
45295var _globalWindow = require('global/window');
45296
45297var _globalWindow2 = _interopRequireDefault(_globalWindow);
45298
45299var _muxJsLibFlv = require('mux.js/lib/flv');
45300
45301var _muxJsLibFlv2 = _interopRequireDefault(_muxJsLibFlv);
45302
45303/**
45304 * Re-emits transmuxer events by converting them into messages to the
45305 * world outside the worker.
45306 *
45307 * @param {Object} transmuxer the transmuxer to wire events on
45308 * @private
45309 */
45310var wireTransmuxerEvents = function wireTransmuxerEvents(transmuxer) {
45311  transmuxer.on('data', function (segment) {
45312    _globalWindow2['default'].postMessage({
45313      action: 'data',
45314      segment: segment
45315    });
45316  });
45317
45318  transmuxer.on('done', function (data) {
45319    _globalWindow2['default'].postMessage({ action: 'done' });
45320  });
45321};
45322
45323/**
45324 * All incoming messages route through this hash. If no function exists
45325 * to handle an incoming message, then we ignore the message.
45326 *
45327 * @class MessageHandlers
45328 * @param {Object} options the options to initialize with
45329 */
45330
45331var MessageHandlers = (function () {
45332  function MessageHandlers(options) {
45333    _classCallCheck(this, MessageHandlers);
45334
45335    this.options = options || {};
45336    this.init();
45337  }
45338
45339  /**
45340   * Our web wroker interface so that things can talk to mux.js
45341   * that will be running in a web worker. The scope is passed to this by
45342   * webworkify.
45343   *
45344   * @param {Object} self the scope for the web worker
45345   */
45346
45347  /**
45348   * initialize our web worker and wire all the events.
45349   */
45350
45351  _createClass(MessageHandlers, [{
45352    key: 'init',
45353    value: function init() {
45354      if (this.transmuxer) {
45355        this.transmuxer.dispose();
45356      }
45357      this.transmuxer = new _muxJsLibFlv2['default'].Transmuxer(this.options);
45358      wireTransmuxerEvents(this.transmuxer);
45359    }
45360
45361    /**
45362     * Adds data (a ts segment) to the start of the transmuxer pipeline for
45363     * processing.
45364     *
45365     * @param {ArrayBuffer} data data to push into the muxer
45366     */
45367  }, {
45368    key: 'push',
45369    value: function push(data) {
45370      // Cast array buffer to correct type for transmuxer
45371      var segment = new Uint8Array(data.data, data.byteOffset, data.byteLength);
45372
45373      this.transmuxer.push(segment);
45374    }
45375
45376    /**
45377     * Recreate the transmuxer so that the next segment added via `push`
45378     * start with a fresh transmuxer.
45379     */
45380  }, {
45381    key: 'reset',
45382    value: function reset() {
45383      this.init();
45384    }
45385
45386    /**
45387     * Forces the pipeline to finish processing the last segment and emit its
45388     * results.
45389     */
45390  }, {
45391    key: 'flush',
45392    value: function flush() {
45393      this.transmuxer.flush();
45394    }
45395  }, {
45396    key: 'resetCaptions',
45397    value: function resetCaptions() {
45398      this.transmuxer.resetCaptions();
45399    }
45400  }]);
45401
45402  return MessageHandlers;
45403})();
45404
45405var FlashTransmuxerWorker = function FlashTransmuxerWorker(self) {
45406  self.onmessage = function (event) {
45407    if (event.data.action === 'init' && event.data.options) {
45408      this.messageHandlers = new MessageHandlers(event.data.options);
45409      return;
45410    }
45411
45412    if (!this.messageHandlers) {
45413      this.messageHandlers = new MessageHandlers();
45414    }
45415
45416    if (event.data && event.data.action && event.data.action !== 'init') {
45417      if (this.messageHandlers[event.data.action]) {
45418        this.messageHandlers[event.data.action](event.data);
45419      }
45420    }
45421  };
45422};
45423
45424exports['default'] = function (self) {
45425  return new FlashTransmuxerWorker(self);
45426};
45427
45428module.exports = exports['default'];
45429},{"global/window":32,"mux.js/lib/flv":46}],71:[function(require,module,exports){
45430(function (global){
45431/**
45432 * @file html-media-source.js
45433 */
45434'use strict';
45435
45436Object.defineProperty(exports, '__esModule', {
45437  value: true
45438});
45439
45440var _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; }; })();
45441
45442var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
45443
45444function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
45445
45446function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
45447
45448function _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; }
45449
45450var _globalWindow = require('global/window');
45451
45452var _globalWindow2 = _interopRequireDefault(_globalWindow);
45453
45454var _globalDocument = require('global/document');
45455
45456var _globalDocument2 = _interopRequireDefault(_globalDocument);
45457
45458var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
45459
45460var _videoJs2 = _interopRequireDefault(_videoJs);
45461
45462var _virtualSourceBuffer = require('./virtual-source-buffer');
45463
45464var _virtualSourceBuffer2 = _interopRequireDefault(_virtualSourceBuffer);
45465
45466var _addTextTrackData = require('./add-text-track-data');
45467
45468var _codecUtils = require('./codec-utils');
45469
45470/**
45471 * Our MediaSource implementation in HTML, mimics native
45472 * MediaSource where/if possible.
45473 *
45474 * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource
45475 * @class HtmlMediaSource
45476 * @extends videojs.EventTarget
45477 */
45478
45479var HtmlMediaSource = (function (_videojs$EventTarget) {
45480  _inherits(HtmlMediaSource, _videojs$EventTarget);
45481
45482  function HtmlMediaSource() {
45483    var _this = this;
45484
45485    _classCallCheck(this, HtmlMediaSource);
45486
45487    _get(Object.getPrototypeOf(HtmlMediaSource.prototype), 'constructor', this).call(this);
45488    var property = undefined;
45489
45490    this.nativeMediaSource_ = new _globalWindow2['default'].MediaSource();
45491    // delegate to the native MediaSource's methods by default
45492    for (property in this.nativeMediaSource_) {
45493      if (!(property in HtmlMediaSource.prototype) && typeof this.nativeMediaSource_[property] === 'function') {
45494        this[property] = this.nativeMediaSource_[property].bind(this.nativeMediaSource_);
45495      }
45496    }
45497
45498    // emulate `duration` and `seekable` until seeking can be
45499    // handled uniformly for live streams
45500    // see https://github.com/w3c/media-source/issues/5
45501    this.duration_ = NaN;
45502    Object.defineProperty(this, 'duration', {
45503      get: function get() {
45504        if (this.duration_ === Infinity) {
45505          return this.duration_;
45506        }
45507        return this.nativeMediaSource_.duration;
45508      },
45509      set: function set(duration) {
45510        this.duration_ = duration;
45511        if (duration !== Infinity) {
45512          this.nativeMediaSource_.duration = duration;
45513          return;
45514        }
45515      }
45516    });
45517    Object.defineProperty(this, 'seekable', {
45518      get: function get() {
45519        if (this.duration_ === Infinity) {
45520          return _videoJs2['default'].createTimeRanges([[0, this.nativeMediaSource_.duration]]);
45521        }
45522        return this.nativeMediaSource_.seekable;
45523      }
45524    });
45525
45526    Object.defineProperty(this, 'readyState', {
45527      get: function get() {
45528        return this.nativeMediaSource_.readyState;
45529      }
45530    });
45531
45532    Object.defineProperty(this, 'activeSourceBuffers', {
45533      get: function get() {
45534        return this.activeSourceBuffers_;
45535      }
45536    });
45537
45538    // the list of virtual and native SourceBuffers created by this
45539    // MediaSource
45540    this.sourceBuffers = [];
45541
45542    this.activeSourceBuffers_ = [];
45543
45544    /**
45545     * update the list of active source buffers based upon various
45546     * imformation from HLS and video.js
45547     *
45548     * @private
45549     */
45550    this.updateActiveSourceBuffers_ = function () {
45551      // Retain the reference but empty the array
45552      _this.activeSourceBuffers_.length = 0;
45553
45554      // If there is only one source buffer, then it will always be active and audio will
45555      // be disabled based on the codec of the source buffer
45556      if (_this.sourceBuffers.length === 1) {
45557        var sourceBuffer = _this.sourceBuffers[0];
45558
45559        sourceBuffer.appendAudioInitSegment_ = true;
45560        sourceBuffer.audioDisabled_ = !sourceBuffer.audioCodec_;
45561        _this.activeSourceBuffers_.push(sourceBuffer);
45562        return;
45563      }
45564
45565      // There are 2 source buffers, a combined (possibly video only) source buffer and
45566      // and an audio only source buffer.
45567      // By default, the audio in the combined virtual source buffer is enabled
45568      // and the audio-only source buffer (if it exists) is disabled.
45569      var disableCombined = false;
45570      var disableAudioOnly = true;
45571
45572      // TODO: maybe we can store the sourcebuffers on the track objects?
45573      // safari may do something like this
45574      for (var i = 0; i < _this.player_.audioTracks().length; i++) {
45575        var track = _this.player_.audioTracks()[i];
45576
45577        if (track.enabled && track.kind !== 'main') {
45578          // The enabled track is an alternate audio track so disable the audio in
45579          // the combined source buffer and enable the audio-only source buffer.
45580          disableCombined = true;
45581          disableAudioOnly = false;
45582          break;
45583        }
45584      }
45585
45586      _this.sourceBuffers.forEach(function (sourceBuffer) {
45587        /* eslinst-disable */
45588        // TODO once codecs are required, we can switch to using the codecs to determine
45589        //      what stream is the video stream, rather than relying on videoTracks
45590        /* eslinst-enable */
45591
45592        sourceBuffer.appendAudioInitSegment_ = true;
45593
45594        if (sourceBuffer.videoCodec_ && sourceBuffer.audioCodec_) {
45595          // combined
45596          sourceBuffer.audioDisabled_ = disableCombined;
45597        } else if (sourceBuffer.videoCodec_ && !sourceBuffer.audioCodec_) {
45598          // If the "combined" source buffer is video only, then we do not want
45599          // disable the audio-only source buffer (this is mostly for demuxed
45600          // audio and video hls)
45601          sourceBuffer.audioDisabled_ = true;
45602          disableAudioOnly = false;
45603        } else if (!sourceBuffer.videoCodec_ && sourceBuffer.audioCodec_) {
45604          // audio only
45605          sourceBuffer.audioDisabled_ = disableAudioOnly;
45606          if (disableAudioOnly) {
45607            return;
45608          }
45609        }
45610
45611        _this.activeSourceBuffers_.push(sourceBuffer);
45612      });
45613    };
45614
45615    this.onPlayerMediachange_ = function () {
45616      _this.sourceBuffers.forEach(function (sourceBuffer) {
45617        sourceBuffer.appendAudioInitSegment_ = true;
45618      });
45619    };
45620
45621    this.onHlsReset_ = function () {
45622      _this.sourceBuffers.forEach(function (sourceBuffer) {
45623        if (sourceBuffer.transmuxer_) {
45624          sourceBuffer.transmuxer_.postMessage({ action: 'resetCaptions' });
45625        }
45626      });
45627    };
45628
45629    
vendor: 12,480 bytes, lines 45629-46009
45629// Re-emit MediaSource events on the polyfill
45630    ['sourceopen', 'sourceclose', 'sourceended'].forEach(function (eventName) {
45631      this.nativeMediaSource_.addEventListener(eventName, this.trigger.bind(this));
45632    }, this);
45633
45634    // capture the associated player when the MediaSource is
45635    // successfully attached
45636    this.on('sourceopen', function (event) {
45637      // Get the player this MediaSource is attached to
45638      var video = _globalDocument2['default'].querySelector('[src="' + _this.url_ + '"]');
45639
45640      if (!video) {
45641        return;
45642      }
45643
45644      _this.player_ = (0, _videoJs2['default'])(video.parentNode);
45645
45646      _this.player_.tech_.on('hls-reset', _this.onHlsReset_);
45647
45648      if (_this.player_.audioTracks && _this.player_.audioTracks()) {
45649        _this.player_.audioTracks().on('change', _this.updateActiveSourceBuffers_);
45650        _this.player_.audioTracks().on('addtrack', _this.updateActiveSourceBuffers_);
45651        _this.player_.audioTracks().on('removetrack', _this.updateActiveSourceBuffers_);
45652      }
45653
45654      _this.player_.on('mediachange', _this.onPlayerMediachange_);
45655    });
45656
45657    this.on('sourceended', function (event) {
45658      var duration = (0, _addTextTrackData.durationOfVideo)(_this.duration);
45659
45660      for (var i = 0; i < _this.sourceBuffers.length; i++) {
45661        var sourcebuffer = _this.sourceBuffers[i];
45662        var cues = sourcebuffer.metadataTrack_ && sourcebuffer.metadataTrack_.cues;
45663
45664        if (cues && cues.length) {
45665          cues[cues.length - 1].endTime = duration;
45666        }
45667      }
45668    });
45669
45670    // explicitly terminate any WebWorkers that were created
45671    // by SourceHandlers
45672    this.on('sourceclose', function (event) {
45673      this.sourceBuffers.forEach(function (sourceBuffer) {
45674        if (sourceBuffer.transmuxer_) {
45675          sourceBuffer.transmuxer_.terminate();
45676        }
45677      });
45678
45679      this.sourceBuffers.length = 0;
45680      if (!this.player_) {
45681        return;
45682      }
45683
45684      if (this.player_.audioTracks && this.player_.audioTracks()) {
45685        this.player_.audioTracks().off('change', this.updateActiveSourceBuffers_);
45686        this.player_.audioTracks().off('addtrack', this.updateActiveSourceBuffers_);
45687        this.player_.audioTracks().off('removetrack', this.updateActiveSourceBuffers_);
45688      }
45689
45690      // We can only change this if the player hasn't been disposed of yet
45691      // because `off` eventually tries to use the el_ property. If it has
45692      // been disposed of, then don't worry about it because there are no
45693      // event handlers left to unbind anyway
45694      if (this.player_.el_) {
45695        this.player_.off('mediachange', this.onPlayerMediachange_);
45696        this.player_.tech_.off('hls-reset', this.onHlsReset_);
45697      }
45698    });
45699  }
45700
45701  /**
45702   * Add a range that that can now be seeked to.
45703   *
45704   * @param {Double} start where to start the addition
45705   * @param {Double} end where to end the addition
45706   * @private
45707   */
45708
45709  _createClass(HtmlMediaSource, [{
45710    key: 'addSeekableRange_',
45711    value: function addSeekableRange_(start, end) {
45712      var error = undefined;
45713
45714      if (this.duration !== Infinity) {
45715        error = new Error('MediaSource.addSeekableRange() can only be invoked ' + 'when the duration is Infinity');
45716        error.name = 'InvalidStateError';
45717        error.code = 11;
45718        throw error;
45719      }
45720
45721      if (end > this.nativeMediaSource_.duration || isNaN(this.nativeMediaSource_.duration)) {
45722        this.nativeMediaSource_.duration = end;
45723      }
45724    }
45725
45726    /**
45727     * Add a source buffer to the media source.
45728     *
45729     * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/addSourceBuffer
45730     * @param {String} type the content-type of the content
45731     * @return {Object} the created source buffer
45732     */
45733  }, {
45734    key: 'addSourceBuffer',
45735    value: function addSourceBuffer(type) {
45736      var buffer = undefined;
45737      var parsedType = (0, _codecUtils.parseContentType)(type);
45738
45739      // Create a VirtualSourceBuffer to transmux MPEG-2 transport
45740      // stream segments into fragmented MP4s
45741      if (/^(video|audio)\/mp2t$/i.test(parsedType.type)) {
45742        var codecs = [];
45743
45744        if (parsedType.parameters && parsedType.parameters.codecs) {
45745          codecs = parsedType.parameters.codecs.split(',');
45746          codecs = (0, _codecUtils.translateLegacyCodecs)(codecs);
45747          codecs = codecs.filter(function (codec) {
45748            return (0, _codecUtils.isAudioCodec)(codec) || (0, _codecUtils.isVideoCodec)(codec);
45749          });
45750        }
45751
45752        if (codecs.length === 0) {
45753          codecs = ['avc1.4d400d', 'mp4a.40.2'];
45754        }
45755
45756        buffer = new _virtualSourceBuffer2['default'](this, codecs);
45757
45758        if (this.sourceBuffers.length !== 0) {
45759          // If another VirtualSourceBuffer already exists, then we are creating a
45760          // SourceBuffer for an alternate audio track and therefore we know that
45761          // the source has both an audio and video track.
45762          // That means we should trigger the manual creation of the real
45763          // SourceBuffers instead of waiting for the transmuxer to return data
45764          this.sourceBuffers[0].createRealSourceBuffers_();
45765          buffer.createRealSourceBuffers_();
45766
45767          // Automatically disable the audio on the first source buffer if
45768          // a second source buffer is ever created
45769          this.sourceBuffers[0].audioDisabled_ = true;
45770        }
45771      } else {
45772        // delegate to the native implementation
45773        buffer = this.nativeMediaSource_.addSourceBuffer(type);
45774      }
45775
45776      this.sourceBuffers.push(buffer);
45777      return buffer;
45778    }
45779  }]);
45780
45781  return HtmlMediaSource;
45782})(_videoJs2['default'].EventTarget);
45783
45784exports['default'] = HtmlMediaSource;
45785module.exports = exports['default'];
45786}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
45787},{"./add-text-track-data":64,"./codec-utils":65,"./virtual-source-buffer":75,"global/document":31,"global/window":32}],72:[function(require,module,exports){
45788/**
45789 * @file remove-cues-from-track.js
45790 */
45791
45792/**
45793 * Remove cues from a track on video.js.
45794 *
45795 * @param {Double} start start of where we should remove the cue
45796 * @param {Double} end end of where the we should remove the cue
45797 * @param {Object} track the text track to remove the cues from
45798 * @private
45799 */
45800"use strict";
45801
45802Object.defineProperty(exports, "__esModule", {
45803  value: true
45804});
45805var removeCuesFromTrack = function removeCuesFromTrack(start, end, track) {
45806  var i = undefined;
45807  var cue = undefined;
45808
45809  if (!track) {
45810    return;
45811  }
45812
45813  if (!track.cues) {
45814    return;
45815  }
45816
45817  i = track.cues.length;
45818
45819  while (i--) {
45820    cue = track.cues[i];
45821
45822    // Remove any overlapping cue
45823    if (cue.startTime <= end && cue.endTime >= start) {
45824      track.removeCue(cue);
45825    }
45826  }
45827};
45828
45829exports["default"] = removeCuesFromTrack;
45830module.exports = exports["default"];
45831},{}],73:[function(require,module,exports){
45832/**
45833 * @file transmuxer-worker.js
45834 */
45835
45836/**
45837 * videojs-contrib-media-sources
45838 *
45839 * Copyright (c) 2015 Brightcove
45840 * All rights reserved.
45841 *
45842 * Handles communication between the browser-world and the mux.js
45843 * transmuxer running inside of a WebWorker by exposing a simple
45844 * message-based interface to a Transmuxer object.
45845 */
45846'use strict';
45847
45848Object.defineProperty(exports, '__esModule', {
45849  value: true
45850});
45851
45852var _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; }; })();
45853
45854function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
45855
45856function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
45857
45858var _globalWindow = require('global/window');
45859
45860var _globalWindow2 = _interopRequireDefault(_globalWindow);
45861
45862var _muxJsLibMp4 = require('mux.js/lib/mp4');
45863
45864var _muxJsLibMp42 = _interopRequireDefault(_muxJsLibMp4);
45865
45866/**
45867 * Re-emits transmuxer events by converting them into messages to the
45868 * world outside the worker.
45869 *
45870 * @param {Object} transmuxer the transmuxer to wire events on
45871 * @private
45872 */
45873var wireTransmuxerEvents = function wireTransmuxerEvents(transmuxer) {
45874  transmuxer.on('data', function (segment) {
45875    // transfer ownership of the underlying ArrayBuffer
45876    // instead of doing a copy to save memory
45877    // ArrayBuffers are transferable but generic TypedArrays are not
45878    // @link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Passing_data_by_transferring_ownership_(transferable_objects)
45879    var initArray = segment.initSegment;
45880
45881    segment.initSegment = {
45882      data: initArray.buffer,
45883      byteOffset: initArray.byteOffset,
45884      byteLength: initArray.byteLength
45885    };
45886
45887    var typedArray = segment.data;
45888
45889    segment.data = typedArray.buffer;
45890    _globalWindow2['default'].postMessage({
45891      action: 'data',
45892      segment: segment,
45893      byteOffset: typedArray.byteOffset,
45894      byteLength: typedArray.byteLength
45895    }, [segment.data]);
45896  });
45897
45898  if (transmuxer.captionStream) {
45899    transmuxer.captionStream.on('data', function (caption) {
45900      _globalWindow2['default'].postMessage({
45901        action: 'caption',
45902        data: caption
45903      });
45904    });
45905  }
45906
45907  transmuxer.on('done', function (data) {
45908    _globalWindow2['default'].postMessage({ action: 'done' });
45909  });
45910};
45911
45912/**
45913 * All incoming messages route through this hash. If no function exists
45914 * to handle an incoming message, then we ignore the message.
45915 *
45916 * @class MessageHandlers
45917 * @param {Object} options the options to initialize with
45918 */
45919
45920var MessageHandlers = (function () {
45921  function MessageHandlers(options) {
45922    _classCallCheck(this, MessageHandlers);
45923
45924    this.options = options || {};
45925    this.init();
45926  }
45927
45928  /**
45929   * Our web wroker interface so that things can talk to mux.js
45930   * that will be running in a web worker. the scope is passed to this by
45931   * webworkify.
45932   *
45933   * @param {Object} self the scope for the web worker
45934   */
45935
45936  /**
45937   * initialize our web worker and wire all the events.
45938   */
45939
45940  _createClass(MessageHandlers, [{
45941    key: 'init',
45942    value: function init() {
45943      if (this.transmuxer) {
45944        this.transmuxer.dispose();
45945      }
45946      this.transmuxer = new _muxJsLibMp42['default'].Transmuxer(this.options);
45947      wireTransmuxerEvents(this.transmuxer);
45948    }
45949
45950    /**
45951     * Adds data (a ts segment) to the start of the transmuxer pipeline for
45952     * processing.
45953     *
45954     * @param {ArrayBuffer} data data to push into the muxer
45955     */
45956  }, {
45957    key: 'push',
45958    value: function push(data) {
45959      // Cast array buffer to correct type for transmuxer
45960      var segment = new Uint8Array(data.data, data.byteOffset, data.byteLength);
45961
45962      this.transmuxer.push(segment);
45963    }
45964
45965    /**
45966     * Recreate the transmuxer so that the next segment added via `push`
45967     * start with a fresh transmuxer.
45968     */
45969  }, {
45970    key: 'reset',
45971    value: function reset() {
45972      this.init();
45973    }
45974
45975    /**
45976     * Set the value that will be used as the `baseMediaDecodeTime` time for the
45977     * next segment pushed in. Subsequent segments will have their `baseMediaDecodeTime`
45978     * set relative to the first based on the PTS values.
45979     *
45980     * @param {Object} data used to set the timestamp offset in the muxer
45981     */
45982  }, {
45983    key: 'setTimestampOffset',
45984    value: function setTimestampOffset(data) {
45985      var timestampOffset = data.timestampOffset || 0;
45986
45987      this.transmuxer.setBaseMediaDecodeTime(Math.round(timestampOffset * 90000));
45988    }
45989  }, {
45990    key: 'setAudioAppendStart',
45991    value: function setAudioAppendStart(data) {
45992      this.transmuxer.setAudioAppendStart(Math.ceil(data.appendStart * 90000));
45993    }
45994
45995    /**
45996     * Forces the pipeline to finish processing the last segment and emit it's
45997     * results.
45998     *
45999     * @param {Object} data event data, not really used
46000     */
46001  }, {
46002    key: 'flush',
46003    value: function flush(data) {
46004      this.transmuxer.flush();
46005    }
46006  }, {
46007    key: 'resetCaptions',
46008    value: function resetCaptions() {
46009      this.transmuxer.resetCaptions(
vendor: 8,813 bytes, lines 46009-46234
46009);
46010    }
46011  }]);
46012
46013  return MessageHandlers;
46014})();
46015
46016var TransmuxerWorker = function TransmuxerWorker(self) {
46017  self.onmessage = function (event) {
46018    if (event.data.action === 'init' && event.data.options) {
46019      this.messageHandlers = new MessageHandlers(event.data.options);
46020      return;
46021    }
46022
46023    if (!this.messageHandlers) {
46024      this.messageHandlers = new MessageHandlers();
46025    }
46026
46027    if (event.data && event.data.action && event.data.action !== 'init') {
46028      if (this.messageHandlers[event.data.action]) {
46029        this.messageHandlers[event.data.action](event.data);
46030      }
46031    }
46032  };
46033};
46034
46035exports['default'] = function (self) {
46036  return new TransmuxerWorker(self);
46037};
46038
46039module.exports = exports['default'];
46040},{"global/window":32,"mux.js/lib/mp4":55}],74:[function(require,module,exports){
46041(function (global){
46042/**
46043 * @file videojs-contrib-media-sources.js
46044 */
46045'use strict';
46046
46047Object.defineProperty(exports, '__esModule', {
46048  value: true
46049});
46050
46051function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
46052
46053var _globalWindow = require('global/window');
46054
46055var _globalWindow2 = _interopRequireDefault(_globalWindow);
46056
46057var _flashMediaSource = require('./flash-media-source');
46058
46059var _flashMediaSource2 = _interopRequireDefault(_flashMediaSource);
46060
46061var _htmlMediaSource = require('./html-media-source');
46062
46063var _htmlMediaSource2 = _interopRequireDefault(_htmlMediaSource);
46064
46065var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
46066
46067var _videoJs2 = _interopRequireDefault(_videoJs);
46068
46069var urlCount = 0;
46070
46071// ------------
46072// Media Source
46073// ------------
46074
46075var defaults = {
46076  // how to determine the MediaSource implementation to use. There
46077  // are three available modes:
46078  // - auto: use native MediaSources where available and Flash
46079  //   everywhere else
46080  // - html5: always use native MediaSources
46081  // - flash: always use the Flash MediaSource polyfill
46082  mode: 'auto'
46083};
46084
46085// store references to the media sources so they can be connected
46086// to a video element (a swf object)
46087// TODO: can we store this somewhere local to this module?
46088_videoJs2['default'].mediaSources = {};
46089
46090/**
46091 * Provide a method for a swf object to notify JS that a
46092 * media source is now open.
46093 *
46094 * @param {String} msObjectURL string referencing the MSE Object URL
46095 * @param {String} swfId the swf id
46096 */
46097var open = function open(msObjectURL, swfId) {
46098  var mediaSource = _videoJs2['default'].mediaSources[msObjectURL];
46099
46100  if (mediaSource) {
46101    mediaSource.trigger({ type: 'sourceopen', swfId: swfId });
46102  } else {
46103    throw new Error('Media Source not found (Video.js)');
46104  }
46105};
46106
46107/**
46108 * Check to see if the native MediaSource object exists and supports
46109 * an MP4 container with both H.264 video and AAC-LC audio.
46110 *
46111 * @return {Boolean} if  native media sources are supported
46112 */
46113var supportsNativeMediaSources = function supportsNativeMediaSources() {
46114  return !!_globalWindow2['default'].MediaSource && !!_globalWindow2['default'].MediaSource.isTypeSupported && _globalWindow2['default'].MediaSource.isTypeSupported('video/mp4;codecs="avc1.4d400d,mp4a.40.2"');
46115};
46116
46117/**
46118 * An emulation of the MediaSource API so that we can support
46119 * native and non-native functionality such as flash and
46120 * video/mp2t videos. returns an instance of HtmlMediaSource or
46121 * FlashMediaSource depending on what is supported and what options
46122 * are passed in.
46123 *
46124 * @link https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/MediaSource
46125 * @param {Object} options options to use during setup.
46126 */
46127var MediaSource = function MediaSource(options) {
46128  var settings = _videoJs2['default'].mergeOptions(defaults, options);
46129
46130  this.MediaSource = {
46131    open: open,
46132    supportsNativeMediaSources: supportsNativeMediaSources
46133  };
46134
46135  // determine whether HTML MediaSources should be used
46136  if (settings.mode === 'html5' || settings.mode === 'auto' && supportsNativeMediaSources()) {
46137    return new _htmlMediaSource2['default']();
46138  } else if (_videoJs2['default'].getTech('Flash')) {
46139    return new _flashMediaSource2['default']();
46140  }
46141
46142  throw new Error('Cannot use Flash or Html5 to create a MediaSource for this video');
46143};
46144
46145exports.MediaSource = MediaSource;
46146MediaSource.open = open;
46147MediaSource.supportsNativeMediaSources = supportsNativeMediaSources;
46148
46149/**
46150 * A wrapper around the native URL for our MSE object
46151 * implementation, this object is exposed under videojs.URL
46152 *
46153 * @link https://developer.mozilla.org/en-US/docs/Web/API/URL/URL
46154 */
46155var URL = {
46156  /**
46157   * A wrapper around the native createObjectURL for our objects.
46158   * This function maps a native or emulated mediaSource to a blob
46159   * url so that it can be loaded into video.js
46160   *
46161   * @link https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
46162   * @param {MediaSource} object the object to create a blob url to
46163   */
46164  createObjectURL: function createObjectURL(object) {
46165    var objectUrlPrefix = 'blob:vjs-media-source/';
46166    var url = undefined;
46167
46168    // use the native MediaSource to generate an object URL
46169    if (object instanceof _htmlMediaSource2['default']) {
46170      url = _globalWindow2['default'].URL.createObjectURL(object.nativeMediaSource_);
46171      object.url_ = url;
46172      return url;
46173    }
46174    // if the object isn't an emulated MediaSource, delegate to the
46175    // native implementation
46176    if (!(object instanceof _flashMediaSource2['default'])) {
46177      url = _globalWindow2['default'].URL.createObjectURL(object);
46178      object.url_ = url;
46179      return url;
46180    }
46181
46182    // build a URL that can be used to map back to the emulated
46183    // MediaSource
46184    url = objectUrlPrefix + urlCount;
46185
46186    urlCount++;
46187
46188    // setup the mapping back to object
46189    _videoJs2['default'].mediaSources[url] = object;
46190
46191    return url;
46192  }
46193};
46194
46195exports.URL = URL;
46196_videoJs2['default'].MediaSource = MediaSource;
46197_videoJs2['default'].URL = URL;
46198}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
46199},{"./flash-media-source":68,"./html-media-source":71,"global/window":32}],75:[function(require,module,exports){
46200(function (global){
46201/**
46202 * @file virtual-source-buffer.js
46203 */
46204'use strict';
46205
46206Object.defineProperty(exports, '__esModule', {
46207  value: true
46208});
46209
46210var _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; }; })();
46211
46212var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
46213
46214function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
46215
46216function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
46217
46218function _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; }
46219
46220var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
46221
46222var _videoJs2 = _interopRequireDefault(_videoJs);
46223
46224var _createTextTracksIfNecessary = require('./create-text-tracks-if-necessary');
46225
46226var _createTextTracksIfNecessary2 = _interopRequireDefault(_createTextTracksIfNecessary);
46227
46228var _removeCuesFromTrack = require('./remove-cues-from-track');
46229
46230var _removeCuesFromTrack2 = _interopRequireDefault(_removeCuesFromTrack);
46231
46232var _addTextTrackData = require('./add-text-track-data');
46233
46234var _webw
vendor: 9,611 bytes, lines 46234-46528
46234orkify = require('webworkify');
46235
46236var _webworkify2 = _interopRequireDefault(_webworkify);
46237
46238var _transmuxerWorker = require('./transmuxer-worker');
46239
46240var _transmuxerWorker2 = _interopRequireDefault(_transmuxerWorker);
46241
46242var _codecUtils = require('./codec-utils');
46243
46244// We create a wrapper around the SourceBuffer so that we can manage the
46245// state of the `updating` property manually. We have to do this because
46246// Firefox changes `updating` to false long before triggering `updateend`
46247// events and that was causing strange problems in videojs-contrib-hls
46248var makeWrappedSourceBuffer = function makeWrappedSourceBuffer(mediaSource, mimeType) {
46249  var sourceBuffer = mediaSource.addSourceBuffer(mimeType);
46250  var wrapper = Object.create(null);
46251
46252  wrapper.updating = false;
46253  wrapper.realBuffer_ = sourceBuffer;
46254
46255  var _loop = function (key) {
46256    if (typeof sourceBuffer[key] === 'function') {
46257      wrapper[key] = function () {
46258        return sourceBuffer[key].apply(sourceBuffer, arguments);
46259      };
46260    } else if (typeof wrapper[key] === 'undefined') {
46261      Object.defineProperty(wrapper, key, {
46262        get: function get() {
46263          return sourceBuffer[key];
46264        },
46265        set: function set(v) {
46266          return sourceBuffer[key] = v;
46267        }
46268      });
46269    }
46270  };
46271
46272  for (var key in sourceBuffer) {
46273    _loop(key);
46274  }
46275
46276  return wrapper;
46277};
46278
46279/**
46280 * VirtualSourceBuffers exist so that we can transmux non native formats
46281 * into a native format, but keep the same api as a native source buffer.
46282 * It creates a transmuxer, that works in its own thread (a web worker) and
46283 * that transmuxer muxes the data into a native format. VirtualSourceBuffer will
46284 * then send all of that data to the naive sourcebuffer so that it is
46285 * indestinguishable from a natively supported format.
46286 *
46287 * @param {HtmlMediaSource} mediaSource the parent mediaSource
46288 * @param {Array} codecs array of codecs that we will be dealing with
46289 * @class VirtualSourceBuffer
46290 * @extends video.js.EventTarget
46291 */
46292
46293var VirtualSourceBuffer = (function (_videojs$EventTarget) {
46294  _inherits(VirtualSourceBuffer, _videojs$EventTarget);
46295
46296  function VirtualSourceBuffer(mediaSource, codecs) {
46297    var _this = this;
46298
46299    _classCallCheck(this, VirtualSourceBuffer);
46300
46301    _get(Object.getPrototypeOf(VirtualSourceBuffer.prototype), 'constructor', this).call(this, _videoJs2['default'].EventTarget);
46302    this.timestampOffset_ = 0;
46303    this.pendingBuffers_ = [];
46304    this.bufferUpdating_ = false;
46305
46306    this.mediaSource_ = mediaSource;
46307    this.codecs_ = codecs;
46308    this.audioCodec_ = null;
46309    this.videoCodec_ = null;
46310    this.audioDisabled_ = false;
46311    this.appendAudioInitSegment_ = true;
46312
46313    var options = {
46314      remux: false
46315    };
46316
46317    this.codecs_.forEach(function (codec) {
46318      if ((0, _codecUtils.isAudioCodec)(codec)) {
46319        _this.audioCodec_ = codec;
46320      } else if ((0, _codecUtils.isVideoCodec)(codec)) {
46321        _this.videoCodec_ = codec;
46322      }
46323    });
46324
46325    // append muxed segments to their respective native buffers as
46326    // soon as they are available
46327    this.transmuxer_ = (0, _webworkify2['default'])(_transmuxerWorker2['default']);
46328    this.transmuxer_.postMessage({ action: 'init', options: options });
46329
46330    this.transmuxer_.onmessage = function (event) {
46331      if (event.data.action === 'data') {
46332        return _this.data_(event);
46333      }
46334
46335      if (event.data.action === 'done') {
46336        return _this.done_(event);
46337      }
46338    };
46339
46340    // this timestampOffset is a property with the side-effect of resetting
46341    // baseMediaDecodeTime in the transmuxer on the setter
46342    Object.defineProperty(this, 'timestampOffset', {
46343      get: function get() {
46344        return this.timestampOffset_;
46345      },
46346      set: function set(val) {
46347        if (typeof val === 'number' && val >= 0) {
46348          this.timestampOffset_ = val;
46349          this.appendAudioInitSegment_ = true;
46350
46351          // We have to tell the transmuxer to set the baseMediaDecodeTime to
46352          // the desired timestampOffset for the next segment
46353          this.transmuxer_.postMessage({
46354            action: 'setTimestampOffset',
46355            timestampOffset: val
46356          });
46357        }
46358      }
46359    });
46360
46361    // setting the append window affects both source buffers
46362    Object.defineProperty(this, 'appendWindowStart', {
46363      get: function get() {
46364        return (this.videoBuffer_ || this.audioBuffer_).appendWindowStart;
46365      },
46366      set: function set(start) {
46367        if (this.videoBuffer_) {
46368          this.videoBuffer_.appendWindowStart = start;
46369        }
46370        if (this.audioBuffer_) {
46371          this.audioBuffer_.appendWindowStart = start;
46372        }
46373      }
46374    });
46375
46376    // this buffer is "updating" if either of its native buffers are
46377    Object.defineProperty(this, 'updating', {
46378      get: function get() {
46379        return !!(this.bufferUpdating_ || !this.audioDisabled_ && this.audioBuffer_ && this.audioBuffer_.updating || this.videoBuffer_ && this.videoBuffer_.updating);
46380      }
46381    });
46382
46383    // the buffered property is the intersection of the buffered
46384    // ranges of the native source buffers
46385    Object.defineProperty(this, 'buffered', {
46386      get: function get() {
46387        var start = null;
46388        var end = null;
46389        var arity = 0;
46390        var extents = [];
46391        var ranges = [];
46392
46393        // neither buffer has been created yet
46394        if (!this.videoBuffer_ && !this.audioBuffer_) {
46395          return _videoJs2['default'].createTimeRange();
46396        }
46397
46398        // only one buffer is configured
46399        if (!this.videoBuffer_) {
46400          return this.audioBuffer_.buffered;
46401        }
46402        if (!this.audioBuffer_) {
46403          return this.videoBuffer_.buffered;
46404        }
46405
46406        // both buffers are configured
46407        if (this.audioDisabled_) {
46408          return this.videoBuffer_.buffered;
46409        }
46410
46411        // both buffers are empty
46412        if (this.videoBuffer_.buffered.length === 0 && this.audioBuffer_.buffered.length === 0) {
46413          return _videoJs2['default'].createTimeRange();
46414        }
46415
46416        // Handle the case where we have both buffers and create an
46417        // intersection of the two
46418        var videoBuffered = this.videoBuffer_.buffered;
46419        var audioBuffered = this.audioBuffer_.buffered;
46420        var count = videoBuffered.length;
46421
46422        // A) Gather up all start and end times
46423        while (count--) {
46424          extents.push({ time: videoBuffered.start(count), type: 'start' });
46425          extents.push({ time: videoBuffered.end(count), type: 'end' });
46426        }
46427        count = audioBuffered.length;
46428        while (count--) {
46429          extents.push({ time: audioBuffered.start(count), type: 'start' });
46430          extents.push({ time: audioBuffered.end(count), type: 'end' });
46431        }
46432        // B) Sort them by time
46433        extents.sort(function (a, b) {
46434          return a.time - b.time;
46435        });
46436
46437        // C) Go along one by one incrementing arity for start and decrementing
46438        //    arity for ends
46439        for (count = 0; count < extents.length; count++) {
46440          if (extents[count].type === 'start') {
46441            arity++;
46442
46443            // D) If arity is ever incremented to 2 we are entering an
46444            //    overlapping range
46445            if (arity === 2) {
46446              start = extents[count].time;
46447            }
46448          } else if (extents[count].type === 'end') {
46449            arity--;
46450
46451            // E) If arity is ever decremented to 1 we leaving an
46452            //    overlapping range
46453            if (arity === 1) {
46454              end = extents[count].time;
46455            }
46456          }
46457
46458          // F) Record overlapping ranges
46459          if (start !== null && end !== null) {
46460            ranges.push([start, end]);
46461            start = null;
46462            end = null;
46463          }
46464        }
46465
46466        return _videoJs2['default'].createTimeRanges(ranges);
46467      }
46468    });
46469  }
46470
46471  /**
46472   * When we get a data event from the transmuxer
46473   * we call this function and handle the data that
46474   * was sent to us
46475   *
46476   * @private
46477   * @param {Event} event the data event from the transmuxer
46478   */
46479
46480  _createClass(VirtualSourceBuffer, [{
46481    key: 'data_',
46482    value: function data_(event) {
46483      var segment = event.data.segment;
46484
46485      // Cast ArrayBuffer to TypedArray
46486      segment.data = new Uint8Array(segment.data, event.data.byteOffset, event.data.byteLength);
46487
46488      segment.initSegment = new Uint8Array(segment.initSegment.data, segment.initSegment.byteOffset, segment.initSegment.byteLength);
46489
46490      (0, _createTextTracksIfNecessary2['default'])(this, this.mediaSource_, segment);
46491
46492      // Add the segments to the pendingBuffers array
46493      this.pendingBuffers_.push(segment);
46494      return;
46495    }
46496
46497    /**
46498     * When we get a done event from the transmuxer
46499     * we call this function and we process all
46500     * of the pending data that we have been saving in the
46501     * data_ function
46502     *
46503     * @private
46504     * @param {Event} event the done event from the transmuxer
46505     */
46506  }, {
46507    key: 'done_',
46508    value: function done_(event) {
46509      // Don't process and append data if the mediaSource is closed
46510      if (this.mediaSource_.readyState === 'closed') {
46511        this.pendingBuffers_.length = 0;
46512        return;
46513      }
46514
46515      // All buffers should have been flushed from the muxer
46516      // start processing anything we have received
46517      this.processPendingSegments_();
46518      return;
46519    }
46520
46521    /**
46522     * Create our internal native audio/video source buffers and add
46523     * event handlers to them with the following conditions:
46524     * 1. they do not already exist on the mediaSource
46525     * 2. this VSB has a codec for them
46526     *
46527     * @private
46528     */
vendor: 3,306 bytes, lines 46528-46617
46528
46529  }, {
46530    key: 'createRealSourceBuffers_',
46531    value: function createRealSourceBuffers_() {
46532      var _this2 = this;
46533
46534      var types = ['audio', 'video'];
46535
46536      types.forEach(function (type) {
46537        // Don't create a SourceBuffer of this type if we don't have a
46538        // codec for it
46539        if (!_this2[type + 'Codec_']) {
46540          return;
46541        }
46542
46543        // Do nothing if a SourceBuffer of this type already exists
46544        if (_this2[type + 'Buffer_']) {
46545          return;
46546        }
46547
46548        var buffer = null;
46549
46550        // If the mediasource already has a SourceBuffer for the codec
46551        // use that
46552        if (_this2.mediaSource_[type + 'Buffer_']) {
46553          buffer = _this2.mediaSource_[type + 'Buffer_'];
46554          // In multiple audio track cases, the audio source buffer is disabled
46555          // on the main VirtualSourceBuffer by the HTMLMediaSource much earlier
46556          // than createRealSourceBuffers_ is called to create the second
46557          // VirtualSourceBuffer because that happens as a side-effect of
46558          // videojs-contrib-hls starting the audioSegmentLoader. As a result,
46559          // the audioBuffer is essentially "ownerless" and no one will toggle
46560          // the `updating` state back to false once the `updateend` event is received
46561          //
46562          // Setting `updating` to false manually will work around this
46563          // situation and allow work to continue
46564          buffer.updating = false;
46565        } else {
46566          var codecProperty = type + 'Codec_';
46567          var mimeType = type + '/mp4;codecs="' + _this2[codecProperty] + '"';
46568
46569          buffer = makeWrappedSourceBuffer(_this2.mediaSource_.nativeMediaSource_, mimeType);
46570
46571          _this2.mediaSource_[type + 'Buffer_'] = buffer;
46572        }
46573
46574        _this2[type + 'Buffer_'] = buffer;
46575
46576        // Wire up the events to the SourceBuffer
46577        ['update', 'updatestart', 'updateend'].forEach(function (event) {
46578          buffer.addEventListener(event, function () {
46579            // if audio is disabled
46580            if (type === 'audio' && _this2.audioDisabled_) {
46581              return;
46582            }
46583
46584            if (event === 'updateend') {
46585              _this2[type + 'Buffer_'].updating = false;
46586            }
46587
46588            var shouldTrigger = types.every(function (t) {
46589              // skip checking audio's updating status if audio
46590              // is not enabled
46591              if (t === 'audio' && _this2.audioDisabled_) {
46592                return true;
46593              }
46594              // if the other type if updating we don't trigger
46595              if (type !== t && _this2[t + 'Buffer_'] && _this2[t + 'Buffer_'].updating) {
46596                return false;
46597              }
46598              return true;
46599            });
46600
46601            if (shouldTrigger) {
46602              return _this2.trigger(event);
46603            }
46604          });
46605        });
46606      });
46607    }
46608
46609    /**
46610     * Emulate the native mediasource function, but our function will
46611     * send all of the proposed segments to the transmuxer so that we
46612     * can transmux them before we append them to our internal
46613     * native source buffers in the correct format.
46614     *
46615     * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/appendBuffer
46616     * @param {Uint8Array} segment the segment to append to the buffer
46617     */
vendor: 4,661 bytes, lines 46618-46758
46618  }, {
46619    key: 'appendBuffer',
46620    value: function appendBuffer(segment) {
46621      // Start the internal "updating" state
46622      this.bufferUpdating_ = true;
46623
46624      if (this.audioBuffer_ && this.audioBuffer_.buffered.length) {
46625        var audioBuffered = this.audioBuffer_.buffered;
46626
46627        this.transmuxer_.postMessage({
46628          action: 'setAudioAppendStart',
46629          appendStart: audioBuffered.end(audioBuffered.length - 1)
46630        });
46631      }
46632
46633      this.transmuxer_.postMessage({
46634        action: 'push',
46635        // Send the typed-array of data as an ArrayBuffer so that
46636        // it can be sent as a "Transferable" and avoid the costly
46637        // memory copy
46638        data: segment.buffer,
46639
46640        // To recreate the original typed-array, we need information
46641        // about what portion of the ArrayBuffer it was a view into
46642        byteOffset: segment.byteOffset,
46643        byteLength: segment.byteLength
46644      }, [segment.buffer]);
46645      this.transmuxer_.postMessage({ action: 'flush' });
46646    }
46647
46648    /**
46649     * Emulate the native mediasource function and remove parts
46650     * of the buffer from any of our internal buffers that exist
46651     *
46652     * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/remove
46653     * @param {Double} start position to start the remove at
46654     * @param {Double} end position to end the remove at
46655     */
46656  }, {
46657    key: 'remove',
46658    value: function remove(start, end) {
46659      if (this.videoBuffer_) {
46660        this.videoBuffer_.updating = true;
46661        this.videoBuffer_.remove(start, end);
46662      }
46663      if (!this.audioDisabled_ && this.audioBuffer_) {
46664        this.audioBuffer_.updating = true;
46665        this.audioBuffer_.remove(start, end);
46666      }
46667
46668      // Remove Metadata Cues (id3)
46669      (0, _removeCuesFromTrack2['default'])(start, end, this.metadataTrack_);
46670
46671      // Remove Any Captions
46672      if (this.inbandTextTracks_) {
46673        for (var track in this.inbandTextTracks_) {
46674          (0, _removeCuesFromTrack2['default'])(start, end, this.inbandTextTracks_[track]);
46675        }
46676      }
46677    }
46678
46679    /**
46680     * Process any segments that the muxer has output
46681     * Concatenate segments together based on type and append them into
46682     * their respective sourceBuffers
46683     *
46684     * @private
46685     */
46686  }, {
46687    key: 'processPendingSegments_',
46688    value: function processPendingSegments_() {
46689      var sortedSegments = {
46690        video: {
46691          segments: [],
46692          bytes: 0
46693        },
46694        audio: {
46695          segments: [],
46696          bytes: 0
46697        },
46698        captions: [],
46699        metadata: []
46700      };
46701
46702      // Sort segments into separate video/audio arrays and
46703      // keep track of their total byte lengths
46704      sortedSegments = this.pendingBuffers_.reduce(function (segmentObj, segment) {
46705        var type = segment.type;
46706        var data = segment.data;
46707        var initSegment = segment.initSegment;
46708
46709        segmentObj[type].segments.push(data);
46710        segmentObj[type].bytes += data.byteLength;
46711
46712        segmentObj[type].initSegment = initSegment;
46713
46714        // Gather any captions into a single array
46715        if (segment.captions) {
46716          segmentObj.captions = segmentObj.captions.concat(segment.captions);
46717        }
46718
46719        if (segment.info) {
46720          segmentObj[type].info = segment.info;
46721        }
46722
46723        // Gather any metadata into a single array
46724        if (segment.metadata) {
46725          segmentObj.metadata = segmentObj.metadata.concat(segment.metadata);
46726        }
46727
46728        return segmentObj;
46729      }, sortedSegments);
46730
46731      // Create the real source buffers if they don't exist by now since we
46732      // finally are sure what tracks are contained in the source
46733      if (!this.videoBuffer_ && !this.audioBuffer_) {
46734        // Remove any codecs that may have been specified by default but
46735        // are no longer applicable now
46736        if (sortedSegments.video.bytes === 0) {
46737          this.videoCodec_ = null;
46738        }
46739        if (sortedSegments.audio.bytes === 0) {
46740          this.audioCodec_ = null;
46741        }
46742
46743        this.createRealSourceBuffers_();
46744      }
46745
46746      if (sortedSegments.audio.info) {
46747        this.mediaSource_.trigger({ type: 'audioinfo', info: sortedSegments.audio.info });
46748      }
46749      if (sortedSegments.video.info) {
46750        this.mediaSource_.trigger({ type: 'videoinfo', info: sortedSegments.video.info });
46751      }
46752
46753      if (this.appendAudioInitSegment_) {
46754        if (!this.audioDisabled_ && this.audioBuffer_) {
46755          sortedSegments.audio.segments.unshift(sortedSegments.audio.initSegment);
46756          sortedSegments.audio.bytes += sortedSegments.audio.initSegment.byteLength;
46757        }
46758        this.appendAudioInitSegment_ = false;
46759      }
46760
46761      // Merge multiple video and audio segments into one and append
46762      if (this.videoBuffer_) {
46763        sortedSegments.video.segments.unshift(sortedSegments.video.initSegment);
46764        sortedSegments.video.bytes += sortedSegments.video.initSegment.byteLength;
46765        this.concatAndAppendSegments_(sortedSegments.video, this.videoBuffer_);
46766        // TODO: are video tracks the only ones with text tracks?
46767        (0, _addTextTrackData.addTextTrackData)(this, sortedSegments.captions, sortedSegments.metadata);
46768      }
46769
46770      if (!this.audioDisabled_ && this.audioBuffer_) {
46771        this.concatAndAppendSegments_(sortedSegments.audio, this.audioBuffer_);
46772      }
46773
46774      this.pendingBuffers_.length = 0;
46775
46776      // We are no longer in the internal "updating" state
46777      this.bufferUpdating_ = false;
46778    }
46779
46780    /**
46781     * Combine all segments into a single Uint8Array and then append them
46782     * to the destination buffer
46783     *
46784     * @param {Object} segmentObj
46785     * @param {SourceBuffer} destinationBuffer native source buffer to append data to
46786     * @private
46787     */
46788  }, {
46789    key: 'concatAndAppendSegments_',
46790    value: function concatAndAppendSegments_(segmentObj, destinationBuffer) {
46791      var offset = 0;
46792      var tempBuffer = undefined;
46793
46794      if (segmentObj.bytes) {
46795        tempBuffer = new Uint8Array(segmentObj.bytes);
46796
46797        // Combine the individual segments into one large typed-array
46798        segmentObj.segments.forEach(function (segment) {
46799          tempBuffer.set(segment, offset);
46800          offset += segment.byteLength;
46801        });
46802
46803        try {
46804          destinationBuffer.updating = true;
46805          destinationBuffer.appendBuffer(tempBuffer);
46806        } catch (error) {
46807          if (this.mediaSource_.player_) {
46808            this.mediaSource_.player_.error({
46809              code: -3,
46810              type: 'APPEND_BUFFER_ERR',
46811              message: error.message,
46812              originalError: error
46813            });
46814          }
46815        }
46816      }
46817    }
46818
46819    /**
46820     * Emulate the native mediasource function. abort any soureBuffer
46821     * actions and throw out any un-appended data.
46822     *
46823     * @link https://developer.mozilla.org/en-US/docs/Web/API/SourceBuffer/abort
46824     */
46825  }, {
46826    key: 'abort',
46827    value: function abort() {
46828      if (this.videoBuffer_) {
46829        this.videoBuffer_.abort();
46830      }
46831      if (!this.audioDisabled_ && this.audioBuffer_) {
46832        this.audioBuffer_.abort();
46833      }
46834      if (this.transmuxer_) {
46835        this.transmuxer_.postMessage({ action: 'reset' });
46836      }
46837      this.pendingBuffers_.length = 0;
46838      this.bufferUpdating_ = false;
46839    }
46840  }]);
46841
46842  return VirtualSourceBuffer;
46843})(_videoJs2['default'].EventTarget);
46844
46845exports['default'] = VirtualSourceBuffer;
46846module.exports = exports['default'];
46847}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
46848},{"./add-text-track-data":64,"./codec-utils":65,"./create-text-tracks-if-necessary":66,"./remove-cues-from-track":72,"./transmuxer-worker":73,"webworkify":76}],76:[function(require,module,exports){
46849var bundleFn = arguments[3];
46850var sources = arguments[4];
46851var cache = arguments[5];
46852
46853var stringify = JSON.stringify;
46854
46855module.exports = function (fn) {
46856    var keys = [];
46857    var wkey;
46858    var cacheKeys = Object.keys(cache);
46859    
46860    for (var i = 0, l = cacheKeys.length; i < l; i++) {
46861        var key = cacheKeys[i];
46862        if (cache[key].exports === fn) {
46863            wkey = key;
46864            break;
46865        }
46866    }
46867    
46868    if (!wkey) {
46869        wkey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16);
46870        var wcache = {};
46871        for (var i = 0, l = cacheKeys.length; i < l; i++) {
46872            var key = cacheKeys[i];
46873            wcache[key] = key;
46874        }
46875        sources[wkey] = [
46876            Function(['require','module','exports'], '(' + fn + ')(self)'),
46877            wcache
46878        ];
46879    }
46880    var skey = Math.floor(Math.pow(16, 8) * Math.random()).toString(16);
46881    
46882    var scache = {}; scache[wkey] = wkey;
46883    sources[skey] = [
46884        Function(['require'],'require(' + stringify(wkey) + ')(self)'),
46885        scache
46886    ];
46887    
46888    var src = '(' + bundleFn + ')({'
46889        + Object.keys(sources).map(function (key) {
46890            return stringify(key) + ':['
46891                + sources[key][0]
46892                + ',' + stringify(sources[key][1]) + ']'
46893            ;
46894        }).join(',')
46895        + '},{},[' + stringify(skey) + '])'
46896    ;
46897    
46898    var URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
46899    
46900    return new Worker(URL.createObjectURL(
46901        new Blob([src], { type: 'text/javascript' })
46902    ))
vendor: 25,532 bytes, lines 46902-47597
46902;
46903};
46904
46905},{}],77:[function(require,module,exports){
46906(function (global){
46907/**
46908 * @file videojs-contrib-hls.js
46909 *
46910 * The main file for the HLS project.
46911 * License: https://github.com/videojs/videojs-contrib-hls/blob/master/LICENSE
46912 */
46913'use strict';
46914
46915var _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; }; })();
46916
46917var _get = function get(_x4, _x5, _x6) { var _again = true; _function: while (_again) { var object = _x4, property = _x5, receiver = _x6; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x4 = parent; _x5 = property; _x6 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
46918
46919function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
46920
46921function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
46922
46923function _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; }
46924
46925var _globalDocument = require('global/document');
46926
46927var _globalDocument2 = _interopRequireDefault(_globalDocument);
46928
46929var _playlistLoader = require('./playlist-loader');
46930
46931var _playlistLoader2 = _interopRequireDefault(_playlistLoader);
46932
46933var _playlist = require('./playlist');
46934
46935var _playlist2 = _interopRequireDefault(_playlist);
46936
46937var _xhr = require('./xhr');
46938
46939var _xhr2 = _interopRequireDefault(_xhr);
46940
46941var _aesDecrypter = require('aes-decrypter');
46942
46943var _binUtils = require('./bin-utils');
46944
46945var _binUtils2 = _interopRequireDefault(_binUtils);
46946
46947var _videojsContribMediaSources = require('videojs-contrib-media-sources');
46948
46949var _m3u8Parser = require('m3u8-parser');
46950
46951var _m3u8Parser2 = _interopRequireDefault(_m3u8Parser);
46952
46953var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null);
46954
46955var _videoJs2 = _interopRequireDefault(_videoJs);
46956
46957var _masterPlaylistController = require('./master-playlist-controller');
46958
46959var _config = require('./config');
46960
46961var _config2 = _interopRequireDefault(_config);
46962
46963var _renditionMixin = require('./rendition-mixin');
46964
46965var _renditionMixin2 = _interopRequireDefault(_renditionMixin);
46966
46967var _globalWindow = require('global/window');
46968
46969var _globalWindow2 = _interopRequireDefault(_globalWindow);
46970
46971var _playbackWatcher = require('./playback-watcher');
46972
46973var _playbackWatcher2 = _interopRequireDefault(_playbackWatcher);
46974
46975var _reloadSourceOnError = require('./reload-source-on-error');
46976
46977var _reloadSourceOnError2 = _interopRequireDefault(_reloadSourceOnError);
46978
46979var _playlistSelectorsJs = require('./playlist-selectors.js');
46980
46981var Hls = {
46982  PlaylistLoader: _playlistLoader2['default'],
46983  Playlist: _playlist2['default'],
46984  Decrypter: _aesDecrypter.Decrypter,
46985  AsyncStream: _aesDecrypter.AsyncStream,
46986  decrypt: _aesDecrypter.decrypt,
46987  utils: _binUtils2['default'],
46988
46989  STANDARD_PLAYLIST_SELECTOR: _playlistSelectorsJs.lastBandwidthSelector,
46990  INITIAL_PLAYLIST_SELECTOR: _playlistSelectorsJs.lowestBitrateCompatibleVariantSelector,
46991  comparePlaylistBandwidth: _playlistSelectorsJs.comparePlaylistBandwidth,
46992  comparePlaylistResolution: _playlistSelectorsJs.comparePlaylistResolution,
46993
46994  xhr: (0, _xhr2['default'])()
46995};
46996
46997// 0.5 MB/s
46998var INITIAL_BANDWIDTH = 4194304;
46999
47000// Define getter/setters for config properites
47001['GOAL_BUFFER_LENGTH', 'MAX_GOAL_BUFFER_LENGTH', 'GOAL_BUFFER_LENGTH_RATE', 'BUFFER_LOW_WATER_LINE', 'MAX_BUFFER_LOW_WATER_LINE', 'BUFFER_LOW_WATER_LINE_RATE', 'BANDWIDTH_VARIANCE'].forEach(function (prop) {
47002  Object.defineProperty(Hls, prop, {
47003    get: function get() {
47004      _videoJs2['default'].log.warn('using Hls.' + prop + ' is UNSAFE be sure you know what you are doing');
47005      return _config2['default'][prop];
47006    },
47007    set: function set(value) {
47008      _videoJs2['default'].log.warn('using Hls.' + prop + ' is UNSAFE be sure you know what you are doing');
47009
47010      if (typeof value !== 'number' || value < 0) {
47011        _videoJs2['default'].log.warn('value of Hls.' + prop + ' must be greater than or equal to 0');
47012        return;
47013      }
47014
47015      _config2['default'][prop] = value;
47016    }
47017  });
47018});
47019
47020/**
47021 * Updates the selectedIndex of the QualityLevelList when a mediachange happens in hls.
47022 *
47023 * @param {QualityLevelList} qualityLevels The QualityLevelList to update.
47024 * @param {PlaylistLoader} playlistLoader PlaylistLoader containing the new media info.
47025 * @function handleHlsMediaChange
47026 */
47027var handleHlsMediaChange = function handleHlsMediaChange(qualityLevels, playlistLoader) {
47028  var newPlaylist = playlistLoader.media();
47029  var selectedIndex = -1;
47030
47031  for (var i = 0; i < qualityLevels.length; i++) {
47032    if (qualityLevels[i].id === newPlaylist.uri) {
47033      selectedIndex = i;
47034      break;
47035    }
47036  }
47037
47038  qualityLevels.selectedIndex_ = selectedIndex;
47039  qualityLevels.trigger({
47040    selectedIndex: selectedIndex,
47041    type: 'change'
47042  });
47043};
47044
47045/**
47046 * Adds quality levels to list once playlist metadata is available
47047 *
47048 * @param {QualityLevelList} qualityLevels The QualityLevelList to attach events to.
47049 * @param {Object} hls Hls object to listen to for media events.
47050 * @function handleHlsLoadedMetadata
47051 */
47052var handleHlsLoadedMetadata = function handleHlsLoadedMetadata(qualityLevels, hls) {
47053  hls.representations().forEach(function (rep) {
47054    qualityLevels.addQualityLevel(rep);
47055  });
47056  handleHlsMediaChange(qualityLevels, hls.playlists);
47057};
47058
47059// HLS is a source handler, not a tech. Make sure attempts to use it
47060// as one do not cause exceptions.
47061Hls.canPlaySource = function () {
47062  return _videoJs2['default'].log.warn('HLS is no longer a tech. Please remove it from ' + 'your player\'s techOrder.');
47063};
47064
47065/**
47066 * Whether the browser has built-in HLS support.
47067 */
47068Hls.supportsNativeHls = (function () {
47069  var video = _globalDocument2['default'].createElement('video');
47070
47071  // native HLS is definitely not supported if HTML5 video isn't
47072  if (!_videoJs2['default'].getTech('Html5').isSupported()) {
47073    return false;
47074  }
47075
47076  // HLS manifests can go by many mime-types
47077  var canPlay = [
47078  // Apple santioned
47079  'application/vnd.apple.mpegurl',
47080  // Apple sanctioned for backwards compatibility
47081  'audio/mpegurl',
47082  // Very common
47083  'audio/x-mpegurl',
47084  // Very common
47085  'application/x-mpegurl',
47086  // Included for completeness
47087  'video/x-mpegurl', 'video/mpegurl', 'application/mpegurl'];
47088
47089  return canPlay.some(function (canItPlay) {
47090    return (/maybe|probably/i.test(video.canPlayType(canItPlay))
47091    );
47092  });
47093})();
47094
47095/**
47096 * HLS is a source handler, not a tech. Make sure attempts to use it
47097 * as one do not cause exceptions.
47098 */
47099Hls.isSupported = function () {
47100  return _videoJs2['default'].log.warn('HLS is no longer a tech. Please remove it from ' + 'your player\'s techOrder.');
47101};
47102
47103var Component = _videoJs2['default'].getComponent('Component');
47104
47105/**
47106 * The Hls Handler object, where we orchestrate all of the parts
47107 * of HLS to interact with video.js
47108 *
47109 * @class HlsHandler
47110 * @extends videojs.Component
47111 * @param {Object} source the soruce object
47112 * @param {Tech} tech the parent tech object
47113 * @param {Object} options optional and required options
47114 */
47115
47116var HlsHandler = (function (_Component) {
47117  _inherits(HlsHandler, _Component);
47118
47119  function HlsHandler(source, tech, options) {
47120    var _this = this;
47121
47122    _classCallCheck(this, HlsHandler);
47123
47124    _get(Object.getPrototypeOf(HlsHandler.prototype), 'constructor', this).call(this, tech, options.hls);
47125
47126    // tech.player() is deprecated but setup a reference to HLS for
47127    // backwards-compatibility
47128    if (tech.options_ && tech.options_.playerId) {
47129      var _player = (0, _videoJs2['default'])(tech.options_.playerId);
47130
47131      if (!_player.hasOwnProperty('hls')) {
47132        Object.defineProperty(_player, 'hls', {
47133          get: function get() {
47134            _videoJs2['default'].log.warn('player.hls is deprecated. Use player.tech_.hls instead.');
47135            tech.trigger({ type: 'usage', name: 'hls-player-access' });
47136            return _this;
47137          }
47138        });
47139      }
47140    }
47141
47142    this.tech_ = tech;
47143    this.source_ = source;
47144    this.stats = {};
47145    this.ignoreNextSeekingEvent_ = false;
47146    this.setOptions_();
47147
47148    // overriding native HLS only works if audio tracks have been emulated
47149    // error early if we're misconfigured:
47150    if (this.options_.overrideNative && (tech.featuresNativeVideoTracks || tech.featuresNativeAudioTracks)) {
47151      throw new Error('Overriding native HLS requires emulated tracks. ' + 'See https://git.io/vMpjB');
47152    }
47153
47154    // listen for fullscreenchange events for this player so that we
47155    // can adjust our quality selection quickly
47156    this.on(_globalDocument2['default'], ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange', 'MSFullscreenChange'], function (event) {
47157      var fullscreenElement = _globalDocument2['default'].fullscreenElement || _globalDocument2['default'].webkitFullscreenElement || _globalDocument2['default'].mozFullScreenElement || _globalDocument2['default'].msFullscreenElement;
47158
47159      if (fullscreenElement && fullscreenElement.contains(_this.tech_.el())) {
47160        _this.masterPlaylistController_.fastQualityChange_();
47161      }
47162    });
47163
47164    this.on(this.tech_, 'seeking', function () {
47165      if (this.ignoreNextSeekingEvent_) {
47166        this.ignoreNextSeekingEvent_ = false;
47167        return;
47168      }
47169
47170      this.setCurrentTime(this.tech_.currentTime());
47171    });
47172    this.on(this.tech_, 'error', function () {
47173      if (this.masterPlaylistController_) {
47174        this.masterPlaylistController_.pauseLoading();
47175      }
47176    });
47177
47178    this.on(this.tech_, 'play', this.play);
47179  }
47180
47181  /**
47182   * The Source Handler object, which informs video.js what additional
47183   * MIME types are supported and sets up playback. It is registered
47184   * automatically to the appropriate tech based on the capabilities of
47185   * the browser it is running in. It is not necessary to use or modify
47186   * this object in normal usage.
47187   */
47188
47189  _createClass(HlsHandler, [{
47190    key: 'setOptions_',
47191    value: function setOptions_() {
47192      var _this2 = this;
47193
47194      // defaults
47195      this.options_.withCredentials = this.options_.withCredentials || false;
47196
47197      if (typeof this.options_.blacklistDuration !== 'number') {
47198        this.options_.blacklistDuration = 5 * 60;
47199      }
47200
47201      // start playlist selection at a reasonable bandwidth for
47202      // broadband internet (0.5 MB/s) or mobile (0.0625 MB/s)
47203      if (typeof this.options_.bandwidth !== 'number') {
47204        this.options_.bandwidth = INITIAL_BANDWIDTH;
47205      }
47206
47207      // If the bandwidth number is unchanged from the initial setting
47208      // then this takes precedence over the enableLowInitialPlaylist option
47209      this.options_.enableLowInitialPlaylist = this.options_.enableLowInitialPlaylist && this.options_.bandwidth === INITIAL_BANDWIDTH;
47210
47211      // grab options passed to player.src
47212      ['withCredentials', 'bandwidth'].forEach(function (option) {
47213        if (typeof _this2.source_[option] !== 'undefined') {
47214          _this2.options_[option] = _this2.source_[option];
47215        }
47216      });
47217
47218      this.bandwidth = this.options_.bandwidth;
47219    }
47220
47221    /**
47222     * called when player.src gets called, handle a new source
47223     *
47224     * @param {Object} src the source object to handle
47225     */
47226  }, {
47227    key: 'src',
47228    value: function src(_src) {
47229      var _this3 = this;
47230
47231      // do nothing if the src is falsey
47232      if (!_src) {
47233        return;
47234      }
47235      this.setOptions_();
47236      // add master playlist controller options
47237      this.options_.url = this.source_.src;
47238      this.options_.tech = this.tech_;
47239      this.options_.externHls = Hls;
47240
47241      this.masterPlaylistController_ = new _masterPlaylistController.MasterPlaylistController(this.options_);
47242      this.playbackWatcher_ = new _playbackWatcher2['default'](_videoJs2['default'].mergeOptions(this.options_, {
47243        seekable: function seekable() {
47244          return _this3.seekable();
47245        }
47246      }));
47247
47248      this.masterPlaylistController_.on('error', function () {
47249        var player = _videoJs2['default'].players[_this3.tech_.options_.playerId];
47250
47251        player.error(_this3.masterPlaylistController_.error);
47252      });
47253
47254      // `this` in selectPlaylist should be the HlsHandler for backwards
47255      // compatibility with < v2
47256      this.masterPlaylistController_.selectPlaylist = this.selectPlaylist ? this.selectPlaylist.bind(this) : Hls.STANDARD_PLAYLIST_SELECTOR.bind(this);
47257
47258      this.masterPlaylistController_.selectInitialPlaylist = Hls.INITIAL_PLAYLIST_SELECTOR.bind(this);
47259
47260      // re-expose some internal objects for backwards compatibility with < v2
47261      this.playlists = this.masterPlaylistController_.masterPlaylistLoader_;
47262      this.mediaSource = this.masterPlaylistController_.mediaSource;
47263
47264      // Proxy assignment of some properties to the master playlist
47265      // controller. Using a custom property for backwards compatibility
47266      // with < v2
47267      Object.defineProperties(this, {
47268        selectPlaylist: {
47269          get: function get() {
47270            return this.masterPlaylistController_.selectPlaylist;
47271          },
47272          set: function set(selectPlaylist) {
47273            this.masterPlaylistController_.selectPlaylist = selectPlaylist.bind(this);
47274          }
47275        },
47276        throughput: {
47277          get: function get() {
47278            return this.masterPlaylistController_.mainSegmentLoader_.throughput.rate;
47279          },
47280          set: function set(throughput) {
47281            this.masterPlaylistController_.mainSegmentLoader_.throughput.rate = throughput;
47282            // By setting `count` to 1 the throughput value becomes the starting value
47283            // for the cumulative average
47284            this.masterPlaylistController_.mainSegmentLoader_.throughput.count = 1;
47285          }
47286        },
47287        bandwidth: {
47288          get: function get() {
47289            return this.masterPlaylistController_.mainSegmentLoader_.bandwidth;
47290          },
47291          set: function set(bandwidth) {
47292            this.masterPlaylistController_.mainSegmentLoader_.bandwidth = bandwidth;
47293            // setting the bandwidth manually resets the throughput counter
47294            // `count` is set to zero that current value of `rate` isn't included
47295            // in the cumulative average
47296            this.masterPlaylistController_.mainSegmentLoader_.throughput = {
47297              rate: 0,
47298              count: 0
47299            };
47300          }
47301        },
47302        /**
47303         * `systemBandwidth` is a combination of two serial processes bit-rates. The first
47304         * is the network bitrate provided by `bandwidth` and the second is the bitrate of
47305         * the entire process after that - decryption, transmuxing, and appending - provided
47306         * by `throughput`.
47307         *
47308         * Since the two process are serial, the overall system bandwidth is given by:
47309         *   sysBandwidth = 1 / (1 / bandwidth + 1 / throughput)
47310         */
47311        systemBandwidth: {
47312          get: function get() {
47313            var invBandwidth = 1 / (this.bandwidth || 1);
47314            var invThroughput = undefined;
47315
47316            if (this.throughput > 0) {
47317              invThroughput = 1 / this.throughput;
47318            } else {
47319              invThroughput = 0;
47320            }
47321
47322            var systemBitrate = Math.floor(1 / (invBandwidth + invThroughput));
47323
47324            return systemBitrate;
47325          },
47326          set: function set() {
47327            _videoJs2['default'].log.error('The "systemBandwidth" property is read-only');
47328          }
47329        }
47330      });
47331
47332      Object.defineProperties(this.stats, {
47333        bandwidth: {
47334          get: function get() {
47335            return _this3.bandwidth || 0;
47336          },
47337          enumerable: true
47338        },
47339        mediaRequests: {
47340          get: function get() {
47341            return _this3.masterPlaylistController_.mediaRequests_() || 0;
47342          },
47343          enumerable: true
47344        },
47345        mediaRequestsAborted: {
47346          get: function get() {
47347            return _this3.masterPlaylistController_.mediaRequestsAborted_() || 0;
47348          },
47349          enumerable: true
47350        },
47351        mediaRequestsTimedout: {
47352          get: function get() {
47353            return _this3.masterPlaylistController_.mediaRequestsTimedout_() || 0;
47354          },
47355          enumerable: true
47356        },
47357        mediaRequestsErrored: {
47358          get: function get() {
47359            return _this3.masterPlaylistController_.mediaRequestsErrored_() || 0;
47360          },
47361          enumerable: true
47362        },
47363        mediaTransferDuration: {
47364          get: function get() {
47365            return _this3.masterPlaylistController_.mediaTransferDuration_() || 0;
47366          },
47367          enumerable: true
47368        },
47369        mediaBytesTransferred: {
47370          get: function get() {
47371            return _this3.masterPlaylistController_.mediaBytesTransferred_() || 0;
47372          },
47373          enumerable: true
47374        },
47375        mediaSecondsLoaded: {
47376          get: function get() {
47377            return _this3.masterPlaylistController_.mediaSecondsLoaded_() || 0;
47378          },
47379          enumerable: true
47380        }
47381      });
47382
47383      this.tech_.one('canplay', this.masterPlaylistController_.setupFirstPlay.bind(this.masterPlaylistController_));
47384
47385      this.masterPlaylistController_.on('selectedinitialmedia', function () {
47386        // Add the manual rendition mix-in to HlsHandler
47387        (0, _renditionMixin2['default'])(_this3);
47388      });
47389
47390      // the bandwidth of the primary segment loader is our best
47391      // estimate of overall bandwidth
47392      this.on(this.masterPlaylistController_, 'progress', function () {
47393        this.tech_.trigger('progress');
47394      });
47395
47396      // In the live case, we need to ignore the very first `seeking` event since
47397      // that will be the result of the seek-to-live behavior
47398      this.on(this.masterPlaylistController_, 'firstplay', function () {
47399        this.ignoreNextSeekingEvent_ = true;
47400      });
47401
47402      this.tech_.ready(function () {
47403        return _this3.setupQualityLevels_();
47404      });
47405
47406      // do nothing if the tech has been disposed already
47407      // this can occur if someone sets the src in player.ready(), for instance
47408      if (!this.tech_.el()) {
47409        return;
47410      }
47411
47412      this.tech_.src(_videoJs2['default'].URL.createObjectURL(this.masterPlaylistController_.mediaSource));
47413    }
47414
47415    /**
47416     * Initializes the quality levels and sets listeners to update them.
47417     *
47418     * @method setupQualityLevels_
47419     * @private
47420     */
47421  }, {
47422    key: 'setupQualityLevels_',
47423    value: function setupQualityLevels_() {
47424      var _this4 = this;
47425
47426      var player = _videoJs2['default'].players[this.tech_.options_.playerId];
47427
47428      if (player && player.qualityLevels) {
47429        this.qualityLevels_ = player.qualityLevels();
47430
47431        this.masterPlaylistController_.on('selectedinitialmedia', function () {
47432          handleHlsLoadedMetadata(_this4.qualityLevels_, _this4);
47433        });
47434
47435        this.playlists.on('mediachange', function () {
47436          handleHlsMediaChange(_this4.qualityLevels_, _this4.playlists);
47437        });
47438      }
47439    }
47440
47441    /**
47442     * Begin playing the video.
47443     */
47444  }, {
47445    key: 'play',
47446    value: function play() {
47447      this.masterPlaylistController_.play();
47448    }
47449
47450    /**
47451     * a wrapper around the function in MasterPlaylistController
47452     */
47453  }, {
47454    key: 'setCurrentTime',
47455    value: function setCurrentTime(currentTime) {
47456      this.masterPlaylistController_.setCurrentTime(currentTime);
47457    }
47458
47459    /**
47460     * a wrapper around the function in MasterPlaylistController
47461     */
47462  }, {
47463    key: 'duration',
47464    value: function duration() {
47465      return this.masterPlaylistController_.duration();
47466    }
47467
47468    /**
47469     * a wrapper around the function in MasterPlaylistController
47470     */
47471  }, {
47472    key: 'seekable',
47473    value: function seekable() {
47474      return this.masterPlaylistController_.seekable();
47475    }
47476
47477    /**
47478    * Abort all outstanding work and cleanup.
47479    */
47480  }, {
47481    key: 'dispose',
47482    value: function dispose() {
47483      if (this.playbackWatcher_) {
47484        this.playbackWatcher_.dispose();
47485      }
47486      if (this.masterPlaylistController_) {
47487        this.masterPlaylistController_.dispose();
47488      }
47489      if (this.qualityLevels_) {
47490        this.qualityLevels_.dispose();
47491      }
47492      _get(Object.getPrototypeOf(HlsHandler.prototype), 'dispose', this).call(this);
47493    }
47494  }]);
47495
47496  return HlsHandler;
47497})(Component);
47498
47499var HlsSourceHandler = function HlsSourceHandler(mode) {
47500  return {
47501    canHandleSource: function canHandleSource(srcObj) {
47502      var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
47503
47504      var localOptions = _videoJs2['default'].mergeOptions(_videoJs2['default'].options, options);
47505
47506      // this forces video.js to skip this tech/mode if its not the one we have been
47507      // overriden to use, by returing that we cannot handle the source.
47508      if (localOptions.hls && localOptions.hls.mode && localOptions.hls.mode !== mode) {
47509        return false;
47510      }
47511      return HlsSourceHandler.canPlayType(srcObj.type, localOptions);
47512    },
47513    handleSource: function handleSource(source, tech) {
47514      var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
47515
47516      var localOptions = _videoJs2['default'].mergeOptions(_videoJs2['default'].options, options, { hls: { mode: mode } });
47517
47518      if (mode === 'flash') {
47519        // We need to trigger this asynchronously to give others the chance
47520        // to bind to the event when a source is set at player creation
47521        tech.setTimeout(function () {
47522          tech.trigger('loadstart');
47523        }, 1);
47524      }
47525
47526      tech.hls = new HlsHandler(source, tech, localOptions);
47527      tech.hls.xhr = (0, _xhr2['default'])();
47528
47529      tech.hls.src(source.src);
47530      return tech.hls;
47531    },
47532    canPlayType: function canPlayType(type) {
47533      var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
47534
47535      var localOptions = _videoJs2['default'].mergeOptions(_videoJs2['default'].options, options);
47536
47537      if (HlsSourceHandler.canPlayType(type, localOptions)) {
47538        return 'maybe';
47539      }
47540      return '';
47541    }
47542  };
47543};
47544
47545HlsSourceHandler.canPlayType = function (type, options) {
47546  // No support for IE 10 or below
47547  if (_videoJs2['default'].browser.IE_VERSION && _videoJs2['default'].browser.IE_VERSION <= 10) {
47548    return false;
47549  }
47550
47551  var mpegurlRE = /^(audio|video|application)\/(x-|vnd\.apple\.)?mpegurl/i;
47552
47553  // favor native HLS support if it's available
47554  if (!options.hls.overrideNative && Hls.supportsNativeHls) {
47555    return false;
47556  }
47557  return mpegurlRE.test(type);
47558};
47559
47560if (typeof _videoJs2['default'].MediaSource === 'undefined' || typeof _videoJs2['default'].URL === 'undefined') {
47561  _videoJs2['default'].MediaSource = _videojsContribMediaSources.MediaSource;
47562  _videoJs2['default'].URL = _videojsContribMediaSources.URL;
47563}
47564
47565var flashTech = _videoJs2['default'].getTech('Flash');
47566
47567// register source handlers with the appropriate techs
47568if (_videojsContribMediaSources.MediaSource.supportsNativeMediaSources()) {
47569  _videoJs2['default'].getTech('Html5').registerSourceHandler(HlsSourceHandler('html5'), 0);
47570}
47571if (_globalWindow2['default'].Uint8Array && flashTech) {
47572  flashTech.registerSourceHandler(HlsSourceHandler('flash'));
47573}
47574
47575_videoJs2['default'].HlsHandler = HlsHandler;
47576_videoJs2['default'].HlsSourceHandler = HlsSourceHandler;
47577_videoJs2['default'].Hls = Hls;
47578if (!_videoJs2['default'].use) {
47579  _videoJs2['default'].registerComponent('Hls', Hls);
47580}
47581_videoJs2['default'].m3u8 = _m3u8Parser2['default'];
47582_videoJs2['default'].options.hls = _videoJs2['default'].options.hls || {};
47583
47584if (_videoJs2['default'].registerPlugin) {
47585  _videoJs2['default'].registerPlugin('reloadSourceOnError', _reloadSourceOnError2['default']);
47586} else {
47587  _videoJs2['default'].plugin('reloadSourceOnError', _reloadSourceOnError2['default']);
47588}
47589
47590module.exports = {
47591  Hls: Hls,
47592  HlsHandler: HlsHandler,
47593  HlsSourceHandler: HlsSourceHandler
47594};
47595}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
47596},{"./bin-utils":2,"./config":3,"./master-playlist-controller":5,"./playback-watcher":8,"./playlist":11,"./playlist-loader":9,"./playlist-selectors.js":10,"./reload-source-on-error":13,"./rendition-mixin":14,"./xhr":21,"aes-decrypter":25,"global/document":31,"global/window":32,"m3u8-parser":33,"videojs-contrib-media-sources":74}]},{},[77])(77)
47597});
47597
47598!function e(t,n,o){function i(r,u){if(!n[r]){if(!t[r]){var f="function"==typeof require&&require;if(!u&&f)return f(r,!0);if(l)return l(r,!0);var d=new Error("Cannot find module '"+r+"'");throw d.code="MODULE_NOT_FOUND",d}var s=n[r]={exports:{}};t[r][0].call(s.exports,function(e){var n=t[r][1][e];return i(n?n:e)},s,s.exports,e,t,n,o)}return n[r].exports}for(var l="function"==typeof require&&require,r=0;r<o.length;r++)i(o[r]);return i}({1:[function(e,t,n){(function(t){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function l(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function r(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}n.__esModule=!0;var u="undefined"!=typeof window?window.videojs:"undefined"!=typeof t?t.videojs:null,f=o(u),d=e(4),s=o(d),a=e(2),c=o(a),p=function(e){function t(){var n;i(this,t);var o=l(this,e.call(this)),r=o;if(f["default"].browser.IS_IE8){r=s["default"].createElement("custom");for(var u in t.prototype)"constructor"!==u&&(r[u]=t.prototype[u])}return r.levels_=[],r.selectedIndex_=-1,Object.defineProperty(r,"selectedIndex",{get:function(){return r.selectedIndex_}}),Object.defineProperty(r,"length",{get:function(){return r.levels_.length}}),n=r,l(o,n)}return r(t,e),t.prototype.addQualityLevel=function(e){var t=this.getQualityLevelById(e.id);if(t)return t;var n=this.levels_.length;return t=new c["default"](e),""+n in this||Object.defineProperty(this,n,{get:function(){return this.levels_[n]}}),this.levels_.push(t),this.trigger({qualityLevel:t,type:"addqualitylevel"}),t},t.prototype.removeQualityLevel=function(e){for(var t=null,n=0,o=this.length;n<o;n++)if(this[n]===e){t=this.levels_.splice(n,1)[0],this.selectedIndex_===n?this.selectedIndex_=-1:this.selectedIndex_>n&&this.selectedIndex_--;break}return t&&this.trigger({qualityLevel:e,type:"removequalitylevel"}),t},t.prototype.getQualityLevelById=function(e){for(var t=0,n=this.length;t<n;t++){var o=this[t];if(o.id===e)return o}return null},t.prototype.dispose=function(){this.selectedIndex_=-1,this.levels_.length=0},t}(f["default"].EventTarget);p.prototype.allowedEvents_={change:"change",addqualitylevel:"addqualitylevel",removequalitylevel:"removequalitylevel"};for(var y in p.prototype.allowedEvents_)p.prototype["on"+y]=null;n["default"]=p}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],2:[function(e,t,n){(function(t){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}n.__esModule=!0;var l="undefined"!=typeof window?window.videojs:"undefined"!=typeof t?t.videojs:null,r=o(l),u=e(4),f=o(u),d=function s(e){i(this,s);var t=this;if(r["default"].browser.IS_IE8){t=f["default"].createElement("custom");for(var n in s.prototype)"constructor"!==n&&(t[n]=s.prototype[n])}return t.id=e.id,t.label=t.id,t.width=e.width,t.height=e.height,t.bitrate=e.bandwidth,t.enabled_=e.enabled,Object.defineProperty(t,"enabled",{get:function(){return t.enabled_()},set:function(e){t.enabled_(e)}}),t};n["default"]=d}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],3:[function(e,t,n){},{}],4:[function(e,t,n){(function(n){var o="undefined"!=typeof n?n:"undefined"!=typeof window?window:{},i=e(3);if("undefined"!=typeof document)t.exports=document;else{var l=o["__GLOBAL_DOCUMENT_CACHE@4"];l||(l=o["__GLOBAL_DOCUMENT_CACHE@4"]=i),t.exports=l}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],5:[function(e,t,n){(function(t){"use strict";
47598function o(e){return e&&e.__esModule?e:{"default":e}}n.__esModule=!0;var i="undefined"!=typeof window?window.videojs:"undefined"!=typeof t?t.videojs:null,l=o(i),r=e(1),u=o(r),f=l["default"].registerPlugin||l["default"].plugin,d=function(e,t){var n=e.qualityLevels,o=new u["default"],i=function l(){o.dispose(),e.qualityLevels=n,e.off("dispose",l)};return e.on("dispose",i),e.qualityLevels=function(){return o},e.qualityLevels.VERSION="2.0.3",o},s=function(e){return d(this,l["default"].mergeOptions({},e))};f("qualityLevels",s),s.VERSION="2.0.3",n["default"]=s}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[5]);
47599// Monkey-patch our way to greater glory!!!
47600(function () {
47601
47602	// Shim Object.create if our browser is too old and crusty
47603	if (typeof Object['create'] !== 'function') {
47604		Object['create'] = function (o) {
47605			function F() {}
47606			F.prototype = o;
47607			return new F();
47608		};
47609	}
47610
47611	function setTracking() {
47612		this.one('ended', onEndedOnce);
47613		this.one('play', onPlayOnce);
47614		this.on('timeupdate', onProgressOnce);
47615	}
47616
47617	// custom logic applied when "ready" is triggered on any player
47618	var player = window['videojs'].getComponent('Player'),
47619		triggerReady = player.prototype.triggerReady;
47620	player.prototype.triggerReady = function () {
47621		setTracking.call(this);
47622		// trigger the normal "ready" events
47623		triggerReady.call(this);
47624	};
47625
47626	// We will be hanging on to the native vjsPlayer
47627	var vjsPlayer = window['videojs'];
47628	// ... and hack that constructor!
47629	function monkeyPlayer() {
47630		vjsPlayer.apply(this, arguments);
47631		// Wire in Google Analytics tracking on any event we can think of
47632		this.one('ended', onEndedOnce);
47633		this.one('play', onPlayOnce);
47634		this.on('timeupdate', onProgressOnce);
47635
47636	}
47637	// Borrow the prototype
47638	monkeyPlayer.prototype = Object.create(vjsPlayer.prototype);
47639	// Throw any static properties on there as well
47640	for (var key in vjsPlayer) {
47641		if (vjsPlayer.hasOwnProperty(key)) {
47642			monkeyPlayer[key] = vjsPlayer[key];
47643		}
47644	}
47645	// Keep the native vjsPlayer just for good measure
47646	monkeyPlayer.vjsPlayer = vjsPlayer;
47647	// ... and patch that videojs!
47648	window['videojs']['Player'] = monkeyPlayer;
47649
47650	// Function definitions
47651	// (these were monkey patched in the constructor in case you didn't notice)
47652	function onEndedOnce(e) {
47653		_gaq_push(['_trackEvent', 'Videos', 'Video Completed', getVideoId(this)]);
47654	}
47655	function onPlayOnce(e) {
47656		_gaq_push(['_trackEvent', 'Videos', 'Play', getVideoId(this)]);
47657	}
47658	function onProgressOnce(e) {
47659		var progress;
47660		try {
47661			// Sometimes duration() errors, so we will not try to send this
47662			// event if we cannot tell when to send it.
47663			progress = this.currentTime() / this.duration();
47664		} catch (e) {
47665			return;
47666		}
47667		if (progress >= 0.2) {
47668			this.off('timeupdate', onProgressOnce);
47669			this.on('timeupdate', onProgressTwice);
47670			_gaq_push(['_trackEvent', 'Videos', 'Watched 20%', getVideoId(this)]);
47671		}
47672	}
47673	function onProgressTwice(e) {
47674		var progress;
47675		try {
47676			// Sometimes duration() errors, so we will not try to send this
47677			// event if we cannot tell when to send it.
47678			progress = this.currentTime() / this.duration();
47679		} catch (e) {
47680			return;
47681		}
47682		if (progress >= 0.8) {
47683			this.off('timeupdate', onProgressTwice);
47684			_gaq_push(['_trackEvent', 'Videos', 'Watched 80%', getVideoId(this)]);
47685		}
47686	}
47687
47688	// For convenience
47689	function _gaq_push() {
47690		if (window._tr) window._tr.push.apply(_tr, arguments);
47691		if (window._gaq) return window._gaq.push.apply(_gaq, arguments);
47692		if (window.console) console.log.apply(console, arguments);
47693	}
47694	function getVideoId(vid) {
47695		var src = vid.currentSrc();
47696
47697		var hlsParts = vid.currentSrc().match(/([^/_]*)_.*[.]csmil\/master[.]m3u8$/);
47698
47699		if(hlsParts && hlsParts.length >= 2 ) {
47700			return hlsParts[1];
47701		}
47702
47703
47704		var parts = src.match(/\?v=([^&]*)/);
47705		if (parts) return parts[1];
47706		// default to the filename at the end of the path
47707		parts = src.match(/[^\/]*$/);
47708		if (parts) return parts[0];
47709		// give up and return the src
47710		return src;
47711	}
47712
47713})();
47714/**
47715@file
47716Generic JS util functions useful for the responsive slideshow.
47717No dependencies.
47718Should be included after the slideshow DOM, as early as possible.
47719*/
47720
47721
47722//<script>
47723
47724if (!window.responsiveSliderDetermineFirstSlide) {
47725
47726    
47727    
47728    function responsiveSliderDetermineFirstSlide() {
47729
47730        if (window.globalSlideshowOptionsOverride && globalSlideshowOptionsOverride.startSlide) {
47731            return globalSlideshowOptionsOverride.startSlide;
47732        }
47733
47734        
47735        if (!document.querySelectorAll || !Array.prototype.reduce) return;
47736
47737        
47738        if (globalGetParams.video || globalGetParams['video-play']) {
47739
47740            var videoParam = globalGetParams.video || globalGetParams['video-play'];
47741            var mySlides = document.querySelectorAll('#header .slideshow-main slide');
47742            var slideMatching = Array.prototype.reduce.call(
47743                document.querySelectorAll('#header .slideshow-main slide .video-js'),
47744                function(m, v) {
47745                    if (m != null) return m;
47746                    var parentSlide = window._getParentForType && _getParentForType(v, 'SLIDE');
47747                    for (var i = 0; i < mySlides.length; i++) {
47748                        if (mySlides[i] == parentSlide) {
47749                            if (_getVideoIdForSlide(mySlides, i) == videoParam) return i;
47750                            break;
47751                        }
47752                    }
47753                },
47754                null
47755            );
47756
47757            if (slideMatching !== void 0) return parseInt(slideMatching) + 1;
47758            
47759            
47760            if (globalGetParams.slide) return globalGetParams.slide;
47761            
47762            
47763            return 1;
47764
47765        }
47766
47767        if (location.hash) {
47768            var newSlideIdx = parseInt(location.hash.substring(1).replace(/slide/, '')) - 1;
47769            if (!isNaN(newSlideIdx) && newSlideIdx >= 0 && newSlideIdx <= document.querySelectorAll('#header slide').length - 1) {
47770                return newSlideIdx + 1;
47771        }
47772        }
47773
47774        
47775        return 1;
47776
47777    }
47778
47779}
47780
47781if (!window._slideToSlideId) {
47782
47783    
47784    function _slideToSlideId(slidesIdx) {
47785        var deltaX = (isRTL ? -1 : 1) * (slidesIdx-1) * 100;
47786        var slideHolder = document.querySelector('#header .slideshow-main .slide-holder');
47787        if (!slideHolder) return;
47788        setTransform(slideHolder, 'translate3d(calc(' + (-deltaX) + '% - ' + (deltaX / 2) + 'px), 0, 0)');
47789    }
47790
47791}
47792
47793if (!window.setTransform) {
47794
47795    
47796    
47797    function setTransform(elem, transform) {
47798        elem.style.MozTransform = transform;  
47799        elem.style.msTransform = transform;  
47800        elem.style.OTransform = transform;  
47801        elem.style.WebkitTransform = transform;  
47802        elem.style.transform = transform;   
47803    }
47804
47805}
47806
47807if  (!window.cookieMonster) {
47808
47809    
47810
47811    var cookieMonster = {
47812        get: function (sKey) {
47813            return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
47814        },
47815        set: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
47816            if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
47817            var sExpires = "";
47818            if (vEnd) {
47819                switch (vEnd.constructor) {
47820                    case Number:
47821                        sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
47822                        break;
47823                    case String:
47824                        sExpires = "; expires=" + vEnd;
47825                        break;
47826                    case Date:
47827                        sExpires = "; expires=" + vEnd.toUTCString();
47828                        break;
47829                }
47830            }
47831            document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
47832            return true;
47833        },
47834        remove: function (sKey, sPath, sDomain) {
47835            if (!sKey || !this.has(sKey)) { return false; }
47836            document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + ( sDomain ? "; domain=" + sDomain : "") + ( sPath ? "; path=" + sPath : "");
47837            return true;
47838        },
47839        has: function (sKey) {
47840            return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
47841        }
47842    };
47843
47844}
47845
47846
47847function slideshowCaptionsOverflow() {
47848
47849    
47850    if (document.body.className.match(/authoring-true/)) return;
47851
47852    
47853    
47854
47855    if(document.documentElement.lang == "zh" && document.location.pathname == "/scientology-today/events/new-years-2017.html") {
47856        
47857        return true;
47858    }
47859
47860    [].forEach.call(document.querySelectorAll('#header_slideshow_wraper .slide-templated-new .item.text-item'), function(v) {
47861        
47862        if (v.className.match(/caption-overflow-adjusted/)) {
47863            v.classList.remove('caption-overflow-adjusted');
47864            var full = v.parentNode.querySelector('.slider-captions-more-full');
47865
47866            if (full) {
47867                v.innerHTML = full.innerHTML;
47868                $(full).parent('slide').find('.text-item').show();
47869                full.parentNode.removeChild(full);
47870                v.offsetTop;
47871            }
47872        }
47873
47874        if (v.offsetHeight < v.scrollHeight) {
47875
47876            var origCont = v.innerHTML,
47877                tempSlideCaptionAdjusted= false;
47878
47879            for (var infiniteGuard = 200; infiniteGuard > 0; infiniteGuard--) {
47880
47881                
47882
47883                var cont = v.innerHTML.replace(new RegExp('... <a[^>]*>' + (window.moreTexti18n ? moreTexti18n : 'more') + ' »<.a>.*$'), '');
47884
47885
47886                
47887                cont = cont.replace(/&[a-z]+;$/, '');
47888
47889                
47890                var lastDivider = Math.max(cont.lastIndexOf(' '), cont.lastIndexOf('.'), cont.lastIndexOf(','), cont.lastIndexOf('。'), cont.lastIndexOf('、'), cont.lastIndexOf('・'));
47891
47892                if (lastDivider < 1) {
47893                    
47894                    window.console && console.error && console.error('could not break this string: ' + origCont);
47895                    v.innerHTML = origCont;
47896                    break;
47897                }
47898
47899                var newCont = cont.substring(0, lastDivider);
47900                
47901                
47902                var tempElem = document.createElement('DIV');
47903                tempElem.innerHTML = newCont;
47904                newCont = tempElem.innerHTML;
47905
47906                if (cont == newCont) {
47907                    window.console && console.error && console.error('no change:');
47908                    window.console && console.error && console.error(cont);
47909                    window.console && console.error && console.error(newCont);
47910                    break;
47911                }
47912
47913                v.innerHTML = newCont + '... <a href="#" class="slider-captions-more">' + (window.moreTexti18n ? moreTexti18n : 'more') + ' »</a>';
47914
47915                
47916                v.offsetTop;
47917                if (v.offsetHeight >= v.scrollHeight) {
47918                    v.classList.add('caption-overflow-adjusted');
47919
47920                    v.insertAdjacentHTML('afterend', '<span class="slider-captions-more-full ignore-zoom item">' + origCont + '<div class="close-full-caption">'+closeTexti18n+'<span class="glyphicon glyphicon-remove-circle"></span></div></span>');
47921                    tempSlideCaptionAdjusted = true;
47922                    break;
47923                }
47924                
47925            };
47926
47927            if (!tempSlideCaptionAdjusted) 
47928                window.console && console.error && console.error('could not break this string: ' + origCont);
47929
47930        }
47931
47932    });
47933}
47934
47935
47936
47937
47938
47939
47940
47941
47942
47943
47944
47945
47946
47947
47948
47949
47950var effectivePixelRatio = 1;
47951if (window.devicePixelRatio) {
47952    if (window.devicePixelRatio > 1.0 && window.devicePixelRatio <= 1.5) {
47953        effectivePixelRatio = 1.5;
47954    } else if (window.devicePixelRatio > 1.5) {
47955        
47956        effectivePixelRatio = 2;
47957    }
47958}
47959
47960
47961var deviceCustomType = 'tablet';
47962if (screen.height > 1024 || screen.width > 1024 || /Trident/.test(navigator.userAgent))  {
47963    deviceCustomType = 'desktop';
47964} else if (screen.height < 768 && screen.width < 768) {
47965    deviceCustomType = 'mobile';
47966}
47967
47968if (document.documentElement) document.documentElement.className += ' device-custom-type-' + deviceCustomType;
47969
47970
47971function determineImageSize(imageDom) {
47972
47973    if (!imageDom.getAttribute('data-height')) {
47974        if(window.location.pathname == "/") {
47975            return [[800, 450], [2*800, 2*450]];
47976        }
47977
47978        window.console && console.error && console.error('no data-height specified:');
47979        window.console && console.error && console.error(imageDom && imageDom.outerHTML);
47980
47981        
47982        return [[860, 575], [2*860, 2*575]];
47983    }
47984
47985    var imageRelativeDims = [parseInt(imageDom.getAttribute('data-width')) / 860, parseInt(imageDom.getAttribute('data-height')) / 575];
47986
47987    
47988    if (deviceCustomType == 'desktop' && effectivePixelRatio == 1) {
47989        return [
47990            [Math.round(imageRelativeDims[0] * 860), Math.round(imageRelativeDims[1] * 575)],
47991            
47992            
47993            [Math.round(imageRelativeDims[0] * 860), Math.round(imageRelativeDims[1] * 575)]
47994        ];
47995    }
47996
47997    
47998    if (deviceCustomType == 'desktop') {
47999        return [
48000            [Math.round(imageRelativeDims[0] * 860 * effectivePixelRatio), Math.round(imageRelativeDims[1] * 575 * effectivePixelRatio)],
48001            [Math.round(imageRelativeDims[0] * 860 * effectivePixelRatio), Math.round(imageRelativeDims[1] * 575 * effectivePixelRatio)]
48002        ];
48003    }
48004
48005    
48006    if (deviceCustomType == 'tablet') {
48007        return [
48008            [Math.round(imageRelativeDims[0] * 860 * effectivePixelRatio), Math.round(imageRelativeDims[1] * 575 * effectivePixelRatio)],
48009            [Math.round(imageRelativeDims[0] * 860 * Math.max(1.5, effectivePixelRatio)), Math.round(imageRelativeDims[1] * 575 * Math.max(1.5, effectivePixelRatio))]
48010        ];
48011    }
48012
48013    
48014    return [
48015        
48016        [Math.round(imageRelativeDims[0] * 680 * effectivePixelRatio), Math.round(imageRelativeDims[1] * 454 * effectivePixelRatio)],
48017        [Math.round(imageRelativeDims[0] * 680 * effectivePixelRatio), Math.round(imageRelativeDims[1] * 454 * effectivePixelRatio)]
48018    ];
48019
48020}
48021
48022function determineImageSourcesFromPrebuilt(imageDom, imgSizes) {
48023    if (!imageDom || !imageDom.getAttribute || !window.JSON || !JSON.parse) return;
48024
48025    var serializedSources = imageDom.getAttribute('data-prebuilt-responsive-sources');
48026    if (!serializedSources) return;
48027
48028    try {
48029        var responsiveSources = JSON.parse(serializedSources);
48030        var primarySrc = responsiveSources[String(imgSizes[0][0])];
48031        if (!primarySrc) return;
48032
48033        return [primarySrc, responsiveSources[String(imgSizes[1][0])] || primarySrc];
48034    } catch (err) {
48035        window.console && console.error && console.error('bad prebuilt responsive sources:');
48036        window.console && console.error && console.error(serializedSources);
48037    }
48038}
48039
48040
48041function determineImageSources(imageDom) {
48042    
48043    if (!imageDom || !imageDom.getAttribute || !imageDom.getAttribute('data-src')) {
48044        window.console && console.error && console.error('cannot get image source, no data-src specified:');
48045        window.console && console.error && console.error(imageDom);
48046        return;
48047    }
48048
48049    var imgSrc = imageDom.getAttribute('data-src');
48050    var qaOverride = getParameterByName('qa');
48051    if (qaOverride) {
48052        imgSrc = imgSrc.replace(/@qa=85/, '@qa='+qaOverride);
48053    }
48054
48055    
48056    if(imgSrc.indexOf('overrideW')===-1) {
48057        imgSrc = imgSrc.replace(/@w=[0-9\.]+/, '');
48058    }
48059    imgSrc = imgSrc.replace(/@h=[0-9\.]+/, '');
48060
48061                
48062    var imgSizes = determineImageSize(imageDom);
48063    var prebuiltSources = determineImageSourcesFromPrebuilt(imageDom, imgSizes);
48064    if (prebuiltSources) return prebuiltSources;
48065
48066    if (imgSrc.match(/cropfit@/)) {
48067        return [imgSrc.replace(/cropfit@/, 'cropfit@w=' + imgSizes[0][0] + '@'), imgSrc.replace(/cropfit@/, 'cropfit@w=' + imgSizes[1][0] + '@')];
48068    } else if (imgSrc.match(/cropfit/)) {
48069        return [imgSrc.replace(/cropfit/, 'cropfit@w=' + imgSizes[0][0]), imgSrc.replace(/cropfit/, 'cropfit@w=' + imgSizes[1][0])];
48070    } else {
48071        window.console && console.error && console.error('non-cropfit image: ' + imgSrc);
48072        return [imgSrc, imgSrc.replace(/temp-color-tests/, 'temp-color-tests/retina')];
48073    }
48074
48075}
48076
48077
48078
48079function slideshowPreloadFirstSlide() {
48080
48081    
48082    
48083
48084    
48085    document.querySelector && new function() {
48086    
48087        var firstImage = document.querySelector('slide img[data-src]');
48088        var firstSlide = document.querySelector('slide');
48089
48090        if (window.responsiveSliderDetermineFirstSlide) {
48091            var firstSlideNum = responsiveSliderDetermineFirstSlide();
48092            firstSlide = document.querySelector('slide:nth-child(' + (firstSlideNum+1) + ')');
48093            firstImage = document.querySelector('slide:nth-child(' + (firstSlideNum+1) + ') img[data-src]');
48094        }
48095
48096        
48097        if (firstSlide) firstSlide.className += ' fso-slide-active ';
48098        
48099        if (firstImage) {
48100
48101            if (firstSlide.querySelector('.image-holder') && window.determineImageSources) {
48102
48103                firstSlide.className += ' js-starting-slide';
48104
48105                [].forEach.call(firstSlide.querySelectorAll('.image-holder'), function(imgHolder) {
48106
48107                    
48108                    
48109                    
48110
48111                    imgHolder.className += ' js-dynamic-size-set';
48112                    imgHolder.style.height = (Math.ceil(parseFloat(imgHolder.getAttribute('data-height')) / 575 * 1000000) / 10000) + '%';
48113                    imgHolder.style.width = (Math.ceil(parseFloat(imgHolder.getAttribute('data-width')) / 860 * 1000000) / 10000) + '%';
48114
48115                    
48116                    var theImage = imgHolder.querySelector('img');
48117                    theImage.addEventListener && theImage.addEventListener('load', function() {
48118                        imgHolder.classList && imgHolder.classList.remove('js-preview');
48119                    });
48120                    theImage.src = determineImageSources(theImage)[0];
48121                    theImage.className += ' loaded';
48122
48123                    
48124
48125                });
48126
48127                if (firstSlide.querySelectorAll('.image-holder') && firstSlide.querySelectorAll('.image-holder').length == 1) firstSlide.className += ' js-single-image-slide';
48128
48129                document.querySelector('.slideshow-wrapper').className += ' js-slideshow-preinited';
48130
48131            } else {
48132                [].forEach.call(firstSlide.querySelectorAll('img'), function(theImage) {
48133                    theImage.src = theImage.getAttribute('data-src');
48134 
48135                    
48136                    
48137                    
48138                });
48139
48140            }                        
48141        }
48142    }
48143
48144}
48145
48146
48147
48148
48149
48150
48151function slideshowPrepare() {
48152
48153    
48154    if (document.querySelectorAll && document.querySelectorAll('.slide-holder slide').length == 1)
48155        document.getElementById('header_slideshow_wraper').classList.add('slideshow-only-one-slide');
48156
48157    
48158    if (window.responsiveSliderDetermineFirstSlide) {
48159        var firstSlide = responsiveSliderDetermineFirstSlide();
48160        _slideToSlideId(firstSlide);
48161    }
48162
48163    
48164    if (document.querySelector && !document.querySelector('.slide-holder slide'))
48165        document.querySelector('.slideshow-wrapper.slideshow-main').parentNode.removeChild(document.querySelector('.slideshow-wrapper.slideshow-main'));
48166
48167    
48168    if (
48169            window.deviceCustomType == 'desktop' &&
48170            document.body.className.match(/templated-slider-build-2-1/) && 
48171            (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) > 767 &&
48172            (
48173                (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) < 1025 ||
48174                !document.body.className.match(/locale-en/) ||
48175                document.body.className.match(/path-scientology-today-church-openings/)
48176                || document.body.className.match(/path-inside-our-church/)
48177            ) &&
48178            window.slideshowCaptionsOverflow
48179       ) {
48180        slideshowCaptionsOverflow();
48181    }
48182
48183}
48184function getParameterByName(name, url) {
48185    if (!url) url = window.location.href;
48186    name = name.replace(/[\[\]]/g, "\\$&");
48187    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
48188        results = regex.exec(url);
48189    if (!results) return null;
48190    if (!results[2]) return '';
48191    return decodeURIComponent(results[2].replace(/\+/g, " "));
48192}
48193
48194
48195//</script>
48196
48197
48198// polyfill
48199if (!window.logger) {
48200    logger = function(){};
48201    logger.debug = function(){};
48202}
48203
48204// @from http://stackoverflow.com/questions/5227909/get-element-padding-value-using-javascript
48205if (!window.getStyle) {
48206    function getStyle(oElm, strCssRule) {
48207        var strValue = "";
48208        if (document.defaultView && document.defaultView.getComputedStyle){
48209            strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
48210        }
48211        else if (oElm.currentStyle){
48212            strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
48213                return p1.toUpperCase();
48214            });
48215            strValue = oElm.currentStyle[strCssRule];
48216        }
48217        return strValue;
48218    }
48219}
48220
48221// wire up the total control over touches for an element (class)
48222// Note: can be called before $(document).ready and doesn't require jQuery
48223if (!window.wireupTotalTouchControl) {
48224    function wireupTotalTouchControl(aClass, aCallback, aTransparent) {
48225        // console.log("Hey, 2");
48226
48227        // if (!globalIsIOS) return;
48228        if (!globalIsMobile) return;
48229        for (var elem in {'touchstart': 1, 'touchmove': 1, 'touchcancel': 1}) {
48230            document.addEventListener(elem, function(e) {
48231
48232                if (e && e.target && e.target.classList &&
48233                    (e.target.classList.contains(aClass) || e.target.parentNode.classList.contains(aClass))) {
48234                    if (!aTransparent) {
48235                        e.stopPropagation();
48236                        e.stopImmediatePropagation();
48237                        e.preventDefault();
48238                        return false;
48239                    } else {
48240                        return true;
48241                    }
48242                }
48243
48244                return true;
48245
48246            }, true);
48247        }
48248
48249        document.addEventListener('touchend', function(e) {
48250
48251            if (e && e.target && e.target.classList &&
48252                (e.target.classList.contains(aClass) || e.target.parentNode.classList.contains(aClass))) {
48253                if (!aTransparent) {
48254                    aCallback(e);
48255                    e.stopPropagation();
48256                    e.stopImmediatePropagation();
48257                    e.preventDefault();
48258                    return false;
48259                } else {
48260                    return aCallback(e);
48261                }
48262            }
48263
48264            return true;
48265
48266        }, true);
48267
48268    }
48269}
48270
48271
48272
48273
48274
48275//<script>
48276
48277
48278
48279
48280
48281
48282
48283
48284
48285
48286
48287
48288
48289
48290
48291function _next_elem(that) {
48292    var nextElem = $(that).next();
48293
48294    if ($.Q && $.Q.widows) {
48295        
48296    }
48297
48298    
48299    
48300    if ($(nextElem).attr('tagName') == null) {
48301        return null;
48302    }
48303
48304    if ($(nextElem).attr('tagName').toLowerCase() != 'p') {
48305        return null;
48306    }
48307
48308    
48309    
48310    if (nextElem.css('clear') == 'both' ||
48311        (nextElem.css('clear') == 'left')  ) {
48312        return null;
48313
48314    }
48315
48316    return nextElem;
48317
48318}
48319
48320
48321
48322function _is_para_empty(that) {
48323
48324    var myTrimmedContent = $(that).html();
48325    var regExp = new RegExp("\\n", "g");
48326    myTrimmedContent = myTrimmedContent.replace(regExp, '');
48327    myTrimmedContent = myTrimmedContent.replace("/ */", '');
48328
48329    if (myTrimmedContent == '') {
48330        return true;
48331    }
48332
48333    if (myTrimmedContent == '&nbsp;') {
48334        return true;
48335    }
48336
48337    return false;
48338
48339}
48340
48341
48342
48343function _gcui_pwidow_nuke() {
48344
48345    var minParaWidth = 100;
48346    var minLineLength = 30;
48347    var maxWordLength = 30;
48348    var pElemTypes = ['.content p', '.slide-holder .text-item'];
48349
48350    for (var j in pElemTypes) {
48351
48352        
48353        if ($(pElemTypes[j]).length == 0) {
48354            continue;
48355        }
48356        $(pElemTypes[j]).each(function() {
48357
48358            if ($(this).hasClass('skip-widows') || $(this).parents('.skip-widows').length) return;
48359
48360            var initWidth = $(this).width();
48361            var myContent = $(this).html();
48362            
48363            myContent = myContent.replace(/[ \n\r]*$/g, '');
48364            if (initWidth > minParaWidth && myContent.length > minLineLength) {
48365
48366                
48367                var lastSpace = myContent.lastIndexOf(' ');
48368                var lastWord = myContent.substr(lastSpace + 1);
48369                var contBeforeBR = '';
48370
48371                
48372                
48373
48374
48375                var beforeLastWord = '';
48376                var oneBeforeLastSpace = myContent.substr(1, lastSpace-1).lastIndexOf(' ');
48377                if (oneBeforeLastSpace != -1) {
48378                    beforeLastWord = myContent.substr(oneBeforeLastSpace + 2, lastSpace - oneBeforeLastSpace - 1);
48379                }
48380
48381                if (lastWord.length <= maxWordLength && lastWord.length + beforeLastWord.length <= maxWordLength) {
48382                    
48383                    
48384                    if (lastWord.indexOf('&nbsp;') == -1 && lastWord.indexOf('>') == -1 && lastWord.indexOf('>') == -1) {
48385                        var newString = myContent.substr(0, lastSpace) + '&nbsp;' + myContent.substr(lastSpace+1);
48386                        $(this).html(newString);
48387
48388                        
48389                        if ($(this).width() > initWidth) {
48390                            $(this).html(myContent);
48391                        }
48392
48393                    }
48394                }
48395
48396            }
48397        });
48398    }
48399
48400}
48401
48402$(window).ready(function() {
48403    _gcui_pwidow_nuke();
48404});
48405
48406$(window).load(function() {
48407
48408         
48409
48410        
48411
48412        var elemTypes = [ ['.gcui-inline-image', 100] ];
48413
48414        var widowCount = 0;
48415        for (var i in elemTypes) {
48416
48417            
48418            if ($(elemTypes[i][0]).length == 0) {
48419                continue;
48420            }
48421
48422            $(elemTypes[i][0]).each(function() {
48423
48424                if (window.globalGetParams && globalGetParams.widows) {
48425                    $(this).css('border', '1px dashed red');
48426                }
48427
48428                
48429                var myBottom = $(this).position().top + $(this).outerHeight(true);
48430
48431                
48432                var nextElem = _next_elem(this);
48433                if (nextElem != null) {
48434                    var nextBottom = $(nextElem).position().top + $(nextElem).outerHeight(true);
48435                }
48436                while (nextElem != null && nextBottom <= myBottom) {
48437
48438                    if (window.globalGetParams && globalGetParams.widows && $(nextElem).css('border') == '1px solid green') {
48439                        $(nextElem).css('border', 'none');
48440                    }
48441                    nextElem = _next_elem(nextElem);
48442                    if (nextElem == null) {
48443                        break;
48444                    }
48445                    nextBottom = nextElem.position().top + nextElem.outerHeight(true);
48446                }
48447
48448                
48449                
48450                if (nextElem != null) {
48451                    if (window.globalGetParams && globalGetParams.widows) {
48452                        $(this).css('border', '1px dashed yellow');
48453                    }
48454                    if (nextBottom - myBottom < elemTypes[i][1] && !_is_para_empty(nextElem) ) {
48455                        
48456                        
48457                        if ($(this).attr('class').indexOf('widowfix') == -1) {
48458                            $(nextElem).addClass('auto-widow-' + widowCount);
48459                            $(this).addClass('widowfix[.' + 'auto-widow-' + widowCount + ']');
48460                            widowCount++;
48461                        }
48462                        
48463                        if (window.globalGetParams && globalGetParams.widows) {
48464                            $(this).css('border', '1px dashed blue');
48465                        }
48466                    }
48467                }
48468
48469            });
48470
48471        }
48472
48473         
48474
48475        var doAdjust = function() {
48476
48477            var isIE6 = navigator.userAgent.toLowerCase().indexOf('msie 
484776') != -1;
48478
48479            $("*[class*=widowfix]").each(function() {
48480
48481                var myClass = $(this).attr('class');
48482
48483                
48484                
48485                if (myClass.indexOf('widowfix[') < 0) { return; }
48486
48487                var myTargetSelector = myClass.split('[')[1].split(']')[0];
48488                var myTarget = $(myTargetSelector);
48489                var myTargetY = myTarget.position().top + myTarget.outerHeight();
48490                if ($(this).css('margin-top') == 'auto' || $(this).css('margin-top') == 'default') {
48491                    var myMarginTop = 0;
48492                } else {
48493                    var myMarginTop = parseInt($(this).css('margin-top').replace(/px/, '')) + 0;
48494                }
48495                if ($(this).css('margin-bottom') == 'auto' || $(this).css('margin-bottom') == 'default') {
48496                    var myMarginBottom = 0;
48497                } else {
48498                    var myMarginBottom = parseInt($(this).css('margin-bottom').replace(/px/, '')) + 0;
48499                }
48500                var myHeightProperty = 'min-height';
48501                
48502                if (isIE6 || $(this).attr('tagName').toLowerCase() == 'table') {
48503                    myHeightProperty = 'height';
48504                }
48505                if ((myTargetY - $(this).position().top - myMarginTop - myMarginBottom) > 0) {
48506                    $(this).css(myHeightProperty, (myTargetY - $(this).position().top - myMarginTop - myMarginBottom) + 'px');
48507                }
48508
48509            });
48510        }
48511
48512        
48513        
48514        setTimeout(doAdjust, 50);
48515        setTimeout(doAdjust, 100);
48516        setTimeout(doAdjust, 150);
48517        setTimeout(doAdjust, 200);
48518
48519});
48520
48521
48522
48523
48524//</script>
48525
48526
48527
48528var VideoController = function(opts) {
48529    // mix in the opts
48530    if (opts) for (var key in opts) this[key] = opts[key];
48531}
48532
48533VideoController.prototype = (function() {
48534
48535    var me = {};
48536
48537    var autogeneratedId = 0;
48538
48539    /**
48540     * Initialize the video player (videoJS element). Starts to download the video and
48541     * starts to play it as well if `aVideoId` == true.
48542     *
48543     * @param aDomElem
48544     *   DOM element to use for the video player (jQuery object is OK as well).
48545     * @param aOpts
48546     *   Video.js options (e.g. autoplay, controls, good defaults: { controls: true, autoplay: true }
48547     * @return
48548     *   videoJS object (which has methods like .on(...) and stuff like that)
48549     */
48550    me.init = function(aDomElem, aOpts) {
48551
48552        // spare casperjs from our videos ...
48553        if (globalGetParams && globalGetParams.headless) return {
48554            on: function() {},
48555            one: function() {},
48556            trigger: function() {},
48557            el: function() {},
48558            posterImage: {
48559                show: function(){}
48560            }
48561        };
48562
48563        var $elem = (aDomElem instanceof jQuery) ? aDomElem : $(aDomElem),
48564            vid = (aDomElem instanceof jQuery) ? aDomElem[0] : $elem[0];
48565
48566        var domElemId = vid.id;
48567
48568        // if DOM elem has no ID, auto-genereate one for it
48569        if (!domElemId) {
48570            domElemId = 'gsc_video_controller_' + autogeneratedId++;
48571            vid.id = domElemId;
48572        }
48573
48574        logger.debug('videoJS DOM elem ID: ' + domElemId);
48575
48576        // HACK android hack
48577        if ($('html').hasClass('device-android')) {
48578
48579            $elem.attr('controls', 'controls');
48580            
48581            // polyfill some of the event listeners
48582            vid.on = vid.addEventListener;
48583            vid.one = function(aEvent, aFunc) {
48584                var theFunc = function() {
48585                    aFunc.apply(this, arguments);
48586                    vid.removeEventListener(aEvent, theFunc);   
48587                };
48588                vid.addEventListener(aEvent, theFunc);
48589            }
48590            vid.trigger = function () {
48591                $elem.trigger.apply($elem, arguments);
48592            }
48593            vid.el = function() {
48594                return vid;
48595            }
48596            vid.posterImage = {
48597                show: function(){
48598                    vid.load();
48599                }
48600            }
48601
48602        } else {
48603
48604            var opts = aOpts || { controls: true, autoplay: false };
48605
48606            // Temporary fix for broken mp4 files in Firefox's HTML5 player
48607            if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && 
48608                navigator.platform.indexOf("Win") > -1 &&
48609                $elem.find('source').eq(0).attr('type') != 'video/webm') {
48610                opts.techOrder = ["hls", "html5", "flash"];
48611            }
48612
48613            vid = videojs(domElemId, opts);
48614
48615            if (opts.showPosterOnVideoEnnd) {
48616
48617                vid.on('ended', function() {
48618
48619                    // cancel out fullscreen
48620                    try { vid.cancelFullScreen(); } catch (swallow) { } // HACK errors on iPhone and iPad
48621                    
48622                    // show the poster image
48623                    vid.posterImage.show();
48624
48625                    // reset the video to the beginning
48626                    if (typeof vid.currentTime === 'function') vid.currentTime(0);
48627
48628                });
48629
48630            }
48631
48632        }
48633
48634        return vid;
48635
48636    }
48637
48638    return me;
48639
48640})();
48641
48642// set the videoJS strings once
48643$(document).ready(function() {
48644
48645    videojs.options.strings = {
48646        'es_ES': {
48647            'Play': 'Reproducir',
48648            'Pause': 'Pausa',
48649            'Mute': 'Sin sonido',
48650            'Unmute': 'Sin sonido',
48651            'Current Time': 'Hora Actual',
48652            'Duration Time': 'Duración',
48653            'Fullscreen': 'Pantalla Completa',
48654            'Non-Fullscreen': 'Pantalla Reducida'
48655        }
48656    };
48657
48658    videojs.options.language = 'es_ES';
48659    videojs.options.flash.swf = '/theme/swf/video-js.swf';
48660
48661    if (!$('html').hasClass('device-ipad')) {
48662        $('[data-gsc-setup]').each(function() {
48663            //globalVideoController.init($(this), $(this).data('gscSetup'));
48664        });
48665    }
48666
48667});
48668
48669
48670globalVideoController = new VideoController();
48671
48672
48673
48674//<script>
48675
48676
48677
48678
48679if (!window.loadJS) {
48680    
48681    
48682    function loadJS(src, cb) {
48683        var ref = window.document.getElementsByTagName( "script" )[ 0 ];
48684        var script = window.document.createElement( "script" );
48685        script.src = src;
48686        script.async = true;
48687        ref.parentNode.insertBefore( script, ref );
48688        if (cb && typeof(cb) === "function") {
48689            script.onload = cb;
48690        }
48691        return script;
48692    }
48693}
48694
48695var GscResponsiveSlider = function(opts) {
48696    
48697    for (var key in opts) this[key] = opts[key];
48698}
48699
48700GscResponsiveSlider.prototype = (function() {
48701
48702    var me = {};
48703
48704    
48705
48706    
48707
48708    me.domParent = '#header'; 
48709    me.fsoSliderZoomHeight = 575;
48710    var fsoSlideWidth = 860;
48711
48712    
48713    
48714    
48715    
48716    
48717    me.addControls = true; 
48718    me.autoplayVideos = true; 
48719    me.circularClone = false; 
48720    me.slidesMax860 = false; 
48721    me.animationGracePeriod = 1000; 
48722
48723    
48724    
48725
48726    
48727    var $mySlides,
48728        animationGracePeriod,
48729        totalSlides,
48730        fsoSliderTop,
48731        slideholderDelta = 0;
48732
48733    var ipAnimation = 0;
48734    var $mySlide,
48735        
48736        myDirection,
48737        extraMotion;
48738
48739    var fsoSlideWidth2; 
48740
48741    var fsoSliderZoomTimeout = 0;
48742    var fsoSliderZoomedIn = false;
48743
48744    var fsoSliderResizeTimer = 0;
48745
48746    var $allNonImageElems,
48747        $allImageElems;
48748    var xRatio = 1;
48749    var attrs = ['top', 'bottom', 'left', 'right', 'width', 'height'];
48750    var dotHolderWidth;
48751
48752    var currentActiveSlideIdx = 0;
48753    var slideshowScrollTop,
48754        fsoSliderZoomedIn,
48755        lastSlideOffset,
48756        containerWideEnoughForNoSliding;
48757
48758    var allZoomedInAppleDots,
48759        allNormalAppleDots,
48760        myTransform,
48761        mySlideholderElem,
48762        tooManyAppleDots,
48763        midwaySlideNumLow = 0,
48764        midwaySlideNum = 0;
48765
48766    var isIpad;
48767
48768    var textAnimationQueue = [];
48769
48770    
48771    var $slideshowMainElem,
48772        slideshowMainElem,
48773        $slideSelectorElem,
48774        slideSelectorElem,
48775        $slideArrowHolder,
48776        slideArrowHolder,
48777        $slideArrowLeft,
48778        slideArrowLeft,
48779        $slideHolderDom,
48780        slideHolderDom;
48781
48782    var customLeftPanel = false;
48783
48784    var isCloned = false;
48785
48786    var $mySlideshowHolder,
48787        $mySlideshowWrapper,
48788        plusOne,
48789        minusOne;
48790
48791    
48792
48793    
48794    me.init = function() {
48795
48796        
48797        
48798
48799        if (window.globalLang && globalLang == "he") {
48800            plusOne = -1;
48801            minusOne = 1;
48802        } else {
48803            plusOne = 1;
48804            minusOne = -1;
48805        }
48806
48807        var that = this;
48808
48809        if (!(this.domParent instanceof jQuery)) {
48810            this.domParent = $(this.domParent);
48811        }
48812
48813        
48814        $slideshowMainElem = this.domParent.find('.slideshow-main');
48815        slideshowMainElem = $slideshowMainElem[0];
48816        if (!slideshowMainElem) return logger.error('There is no ".slideshow-main"!');
48817        if (!(this.domParent.find('.slide-wrapper')[0])) return logger.error('There is no ".slide-wrapper" on ".slideshow-main"!');
48818
48819        
48820        if (this.touchMode === void 0 && this.domParent.find('.video-slide').length) {
48821            this.touchMode = 'default';
48822            if (window.deviceCustomType != 'desktop') this.zoomEnabled = false;
48823        }
48824
48825        if (this.touchMode === void 0) this.touchMode = 'default';
48826
48827        
48828        if (window.deviceCustomType != 'desktop' && this.touchMode == 'photoswipe') this.zoomEnabled = false;
48829
48830        if (this.zoomEnabled && !this.addControls) return logger.error('Conflicting options (zoomEnabled && !addControls): how am I supposed to enable zoom without adding controls?', 'error');
48831
48832        
48833        if (this.zoomOnClick === void 0) {
48834            if ($slideshowMainElem.find('slide .video-js').length) {
48835                this.zoomOnClick = false;
48836                logger.debug('setting zoomOnClick to false');
48837            } else {
48838                this.zoomOnClick = true;
48839                logger.debug('setting zoomOnClick to true');
48840            }
48841        }
48842        if (this.hasLeftSidebar === void 0) {
48843            if (!this.domParent.find('.slideshow-left-nav').length) {
48844                this.hasLeftSidebar = false;
48845                logger.debug('setting hasLeftSidebar to false');
48846            } else {
48847                this.hasLeftSidebar = true;
48848                logger.debug('setting hasLeftSidebar to true');
48849            }
48850        }
48851        if (this.useSimpleSliding === void 0) {
48852            if ($slideshowMainElem.find('slide .item:not(.left-panel-mobile-caption)').length) {
48853                this.useSimpleSliding = false;
48854                this.slidesMax860 = (this.slidesMax860 === void 0 ? true : this.slidesMax860);
48855                logger.debug('setting useSimpleSliding to false');
48856            } else {
48857                this.useSimpleSliding = true;
48858                logger.debug('setting useSimpleSliding to true');
48859            }
48860        }
48861        if (this.zoomEnabled === void 0) {
48862            if (!$slideshowMainElem.find('slide .item:not(.left-panel-mobile-caption)').length) {
48863                this.zoomEnabled = false;
48864                logger.debug('setting zoomEnabled to false');
48865            } else {
48866                this.zoomEnabled = true;
48867                logger.debug('setting zoomEnabled to true');
48868            }
48869        }
48870
48871        $mySlideshowHolder = this.domParent.find('.slideshow-holder');
48872        $mySlideshowWrapper = this.domParent.find('.slideshow-wrapper');
48873
48874        $slideHolderDom = this.domParent.find('.slide-holder');
48875        slideHolderDom = $slideHolderDom[0];
48876        if (!slideHolderDom) return logger.error('There is no ".slide-holder"!');
48877
48878        if (this.domParent.find('slide').length === 1) {
48879            $mySlideshowWrapper.addClass('slideshow-single-slide');
48880        }
48881
48882        var tempThis = this;
48883
48884        
48885
48886        
48887        
48888        if (window.deviceCustomType != 'desktop' && this.touchMode == 'photoswipe') {
48889
48890            
48891            loadJS('/theme/photoswipe/photoswipe.min.js?_=9d8f7badc');
48892            loadJS('/theme/photoswipe/photoswipe-ui-default.min.js?_=9d8f7badc');
48893            
48894            
48895            window.galleryItems = [];
48896
48897            $('slide').each(function() {
48898
48899                
48900
48901
48902                var $clone = $(this).clone();
48903                $clone.find('.image-holder').each(function() {
48904                    
48905                    $(this).css('width', (Math.round(parseFloat($(this).attr('data-width')) / 860 * 1000000) / 10000) + '%');
48906                    $(this).css('height', (Math.round(parseFloat($(this).attr('data-height')) / 575 * 1000000) / 10000) + '%');
48907                });
48908
48909                if ($clone.find('.image-holder').length == 1) {
48910                    $clone.addClass('js-single-image-slide');
48911                    var $imgHolder = $clone.find('.image-holder').eq(0);
48912                    var slideDims = [window.innerWidth, window.innerWidth * 0.6686];
48913                    var imageDims = [window.innerWidth * 0.6686 * parseFloat($imgHolder.attr('data-width')) / parseFloat($imgHolder.attr('data-height')), window.innerWidth * 0.6686];
48914                    
48915                    
48916                    if (imageDims[0] > $imgHolder.attr('data-width') ) {
48917                        imageDims[0] = $imgHolder.attr('data-width');
48918                    }
48919
48920                        if(window.location.pathname != "/scientology-today/church-openings/grand-opening-scientology-media-productions.html" && window.location.pathname != "/churches/bringing-scientology-world/scientology-media-productions.html") {
48921                             $imgHolder.css('min-width', Math.floor(imageDims[0]) + 'px');
48922                    }
48923
48924                }
48925
48926                $clone.find('img[data-src]').each(function() {
48927                    var imgSrc = determineImageSources(this);
48928                    
48929                    if (imgSrc) $(this).attr('srca', imgSrc[1]).removeAttr('data-src').removeAttr('src');
48930                });
48931
48932                
48933                var theSlideHtml = $clone[0].outerHTML;
48934                if (!theSlideHtml.match(/js-preview/)) theSlideHtml = theSlideHtml.replace(/image-holder/g, 'image-holder js-preview');
48935
48936                var slideObj = {
48937                    html: theSlideHtml.replace(/srca=/g, 'src='),
48938                }
48939                if (deviceCustomType == 'mobile') slideObj.title = $clone.find('.text-item').html();
48940                galleryItems.push(slideObj);
48941
48942            });
48943
48944            $('.pswp')[0].className += ' zoomedIn slide-wrapper bs-slideshow';
48945            document.body.className += ' photoswipe-on slideshow-zoomed-in';
48946            $('.pswp .pswp__container').html('<div class="pswp__item"></div> <div class="pswp__item"></div> <div class="pswp__item"></div>');
48947
48948        }
48949
48950        
48951        if (
48952                document.body.className.match(/templated-slider-build-2-1/) && 
48953                (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) > 767 &&
48954                (
48955                    (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) < 1025 ||
48956                    !document.body.className.match(/locale-en/)
48957                ) &&
48958                window.slideshowCaptionsOverflow
48959           ) {
48960            slideshowCaptionsOverflow();
48961        }
48962
48963        if (this.domParent.find('slide').length === 0) window.console && console.error && console.error('ERROR: slideshow has no slides!');
48964
48965        
48966        
48967        
48968        if (this.addControls) {
48969            $mySlideshowHolder.append('\
48970                <div class="slide-controls">\
48971                    <div class="slide-arrow-holder slide-left-arrow2">\
48972                        <div class="arrow-bg"></div>\
48973                        <arrow></arrow>\
48974                    </div>\
48975                    <div class="slide-arrow-holder slide-right-arrow2">\
48976                        <div class="arrow-bg"></div>\
48977                        <arrow></arrow>\
48978                    </div>\
48979                </div>\
48980                <div class="slide-selectors"></div>\
48981                ');
48982            if (this.zoomEnabled) {
48983                $mySlideshowHolder.append('\
48984                    <div class="slide-zoomer">\
48985                        <span class="click-to-expand">Expandir </span>\
48986                    </div>\
48987                    ');
48988                $mySlideshowWrapper.before('\
48989                    <div class="fso-custom-slider-overlay fso-custom-slider-fader"></div>\
48990                    <div class="fso-slide-upper-bg fso-custom-slider-fader">\
48991                        <a href="#" class="closebtn"><span class="glyphicon glyphicon-remove-circle"></span></a>\
48992                    </div>\
48993                    <div class="fso-slide-lower-bg fso-custom-slider-fader">\
48994                        <div class="fso-slide-selectors slide-selectors"></div>\
48995                    </div>\
48996                    <div class="fso-custom-zoomer">\
48997                        <div class="slide-zoomer">\
48998                            <span class="click-to-expand">Cerrar</span>\
48999                        </div>\
49000                    </div>\
49001                    ');
49002            }
49003            $slideHolderDom.after('\
49004                <div class="fso-slide-mobile-numbers">\
49005                    <span class="slide-num"></span> / <span class="slide-total"></span>\
49006                </div>\
49007                ');
49008        }
49009
49010        $slideSelectorElem = this.domParent.find('.slide-selectors');
49011        slideSelectorElem = $slideSelectorElem[0];
49012        
49013        if (!slideSelectorElem && this.addControls) return logger.error('There is no ".slide-selectors"!');
49014
49015        $slideArrowHolder = this.domParent.find('.slide-arrow-holder');
49016        slideArrowHolder = $slideArrowHolder[0];
49017        if (!slideArrowHolder) return logger.error('There is no ".slide-arrow-holder"!');
49018
49019        $slideArrowLeft = this.domParent.find('.slide-left-arrow2');
49020        slideArrowLeft = $slideArrowLeft[0];
49021        if (!slideArrowLeft) return logger.error('There is no left arrow: ".slide-left-arrow2"!');
49022
49023        if (!(this.domParent.find('.slide-controls')[0])) return logger.error('There is no ".slide-controls"!');
49024        if (!(this.domParent.find('.slide-right-arrow2')[0])) return logger.error('There is no ".slide-right-arrow2"!');
49025
49026        $mySlides = this.domParent.find('.slide-holder slide');
49027        animationGracePeriod = this.animationGracePeriod;
49028        totalSlides = this.domParent.find('slide').length;
49029        $allNonImageElems = $mySlides.find('div.item,h3.item,.inactive-dot');
49030        $allImageElems = $mySlides.find('img.item');
49031        myMinSlideLeft = -10 - (fsoSlideWidth * (totalSlides - 1));
49032        slideshowScrollTop = slideshowMainElem.offsetTop;
49033
49034        myTransform = Modernizr.prefixed('transform');
49035        mySlideholderElem = this.domParent.find('.slide-holder')[0];
49036
49037        isIpad = $('html').hasClass('device-ipad');
49038        simpleAnimation = this.useSimpleSliding;
49039
49040        isCloned = this.circularClone;
49041
49042        
49043        if ($('html').hasClass('device-iphone') || globalIsIE) isCloned = this.circularClone = false;
49044        if (globalIsIOS) isCloned = this.circularClone = false;
49045
49046        if (isCloned) {
49047            $mySlideshowWrapper.addClass('slideshow-been-cloned');
49048        } else {
49049            $mySlideshowWrapper.addClass('slideshow-not-cloned');
49050        }
49051
49052        customLeftPanel = !! this.domParent.find('.custom-slide-leftnav').length;
49053
49054        
49055        
49056        
49057        
49058
49059        
49060        if (this.domParent.find('.slide-stretcher').length) {
49061            var paddingBottom = getStyle(this.domParent.find('.slide-stretcher')[0], "padding-bottom");
49062            if (paddingBottom) {
49063                var stretcherPaddingBottom = parseInt(paddingBottom.replace(/px/, ''));
49064                if (!isNaN(stretcherPaddingBottom)) {
49065                    var stretchPercent = stretcherPaddingBottom / this.domParent.find('.slide-stretcher').width() * 100;
49066                    this.fsoSliderZoomHeight = fsoSlideWidth * stretchPercent / 100;
49067                    
49068                }
49069            }
49070        }
49071
49072        
49073        $(document).on('click', '.new-age-caption-overlay,.video-slide-overlay.center-playbutton-overlay', function(e) {
49074            var videlem = $(this).siblings('.video-js');
49075            playVideoJS(videlem);
49076            fireEvent('userInteraction', 'video-play');
49077        });
49078
49079        if (!this.domParent.find('.fso-slide-active')) $mySlides.eq(0).addClass('fso-slide-active');
49080
49081        
49082        if (totalSlides > 30 && this.domParent.find('.slide-selectors').length) {
49083            tooManyAppleDots = true;
49084            $('body').addClass('fso-slider-too-many-apple-dots');
49085        } else {
49086            tooManyAppleDots = false;
49087            $('body').addClass('fso-slider-not-too-many-apple-dots');
49088        }
49089
49090        
49091        
49092        
49093        
49094
49095        
49096        for (var i = 0; i < totalSlides; i++) {
49097            (function() {
49098
49099                var $thisSlide = $mySlides.eq(i);
49100
49101                $thisSlide.find('.image-holder').each(function() {
49102
49103                    if ($(this).hasClass('js-dynamic-size-set')) return;
49104                    $(this).addClass('js-dynamic-size-set').css('width', (Math.round(parseFloat($(this).attr('data-width')) / 860 * 1000000) / 10000) + '%');
49105                    $(this).css('height', (Math.round(parseFloat($(this).attr('data-height')) / 575 * 1000000) / 10000) + '%');
49106
49107                });
49108
49109                if (window.deviceCustomType == 'desktop' || tempThis.touchMode != 'photoswipe') {
49110                    $thisSlide.find('.image-holder img[data-src]').each(function() {
49111                        var tempSize = determineImageSources(this);
49112                        if (tempSize && tempSize[1] != tempSize[0]) {
49113                            $(this).after($(this).clone().removeAttr('src').removeAttr('data-src').attr('data-double-src', tempSize[1]).addClass('zoomer-image'));
49114                        }
49115                    });
49116
49117                    
49118                    if ($thisSlide.hasClass('js-starting-slide')) {
49119                        $thisSlide.addClass('double-loaded').find('.zoomer-image').each(function() {
49120                            $(this).attr('src', $(this).attr('data-double-src')).addClass('loaded');
49121                        });
49122                    }
49123
49124                } else {
49125
49126                    if ($thisSlide.find('.image-holder').length == 1) $thisSlide.addClass('js-single-image-slide');
49127
49128                }
49129
49130            })();
49131        }
49132
49133        
49134
49135
49136        var tempFirstSlide = this.determineFirstSlide();
49137        if (window.deviceCustomType == 'desktop' || tempThis.touchMode != 'photoswipe') loadSurroundingSlides(Math.max(0, tempFirstSlide-1));
49138
49139        
49140        if (!globalIsIOS && !globalIsSafari) {
49141            for (var i = 0; i < totalSlides; i++) {
49142                (function() {
49143
49144                    if (window.deviceCustomType != 'desktop' && tempThis.touchMode == 'photoswipe') return;
49145
49146                    var $thisSlide = $mySlides.eq(i);
49147                    setTimeout(function() {
49148                        $thisSlide.find('.image-item[data-src]:not(.loaded),.image-holder img[data-src]:not(.loaded)').each(function() {
49149                            
49150                            var $myThisSlide = $thisSlide;
49151                            var $this = $(this);
49152                            var imgSrc = $this.attr('data-src');
49153
49154                            
49155                            if ($this.attr('data-height')) imgSrc = determineImageSources(this)[0];
49156
49157                            logger.debug('preloading #1: ' + imgSrc);
49158
49159                            if ($this.attr('src') != imgSrc) {
49160                                $this.on('load', function() {
49161                                    $this.parents('.image-holder').removeClass('js-preview');    
49162                                });
49163                                $this.css('background', 'none').addClass('loading-image-hide')
49164                                    .attr('src', imgSrc).addClass('loaded');
49165                            } else {
49166                                
49167                                
49168                                $this.css('background', 'none')
49169                                    .addClass('loaded');
49170                                $this.parents('.image-holder').removeClass('js-preview');
49171                            }
49172
49173                            $this.load(function() {
49174                                $this.removeClass('loading-image-hide');
49175                            });
49176                        });
49177                    }, 500 * i);
49178                })();
49179            }
49180        }
49181
49182        
49183
49184
49185        
49186        if (this.circularClone) {
49187
49188            logger.debug('cloning slides and sheep');
49189            var slideRefs = [];
49190
49191            $mySlides.each(function() {
49192
49193                slideRefs.push(this);
49194                var $cloned = $(this).clone();
49195
49196                
49197                
49198                $cloned.find('video').each(function() {
49199                    var myPoster = $(this).attr('poster');
49200                    if (!myPoster) return;
49201                    var posterDom = document.createElement("img");
49202                    posterDom.src = myPoster;
49203                    posterDom.style.position = 'absolute';
49204                    this.parentNode.replaceChild(posterDom, this);
49205                    if (this.parentNode && this.parentNode.tagName && this.parentNode.tagName.toLowerCase() === 'div') this.parentNode.style.position = 'absolute';
49206                });
49207
49208                
49209                $cloned.find('[id]').each(function() {
49210                    $(this).attr('id', $(this).attr('id') + '_cloned_after');
49211                });
49212                if ($cloned.attr('id')) $cloned.attr('id', $cloned.attr('id') + '_cloned_after');
49213
49214                
49215                if ($cloned.attr('class')) {
49216                    $cloned.attr('class', $cloned.attr('class').replace(/fso-slide-([0-9]*)/, function(match1) {
49217                        return match1 + '_cloned_after';
49218                    }));
49219                }
49220
49221                
49222                if ($cloned.attr('data-slide-id')) {
49223                    $cloned.attr('data-slide-id', $cloned.attr('data-slide-id') + '_cloned_after');
49224                }
49225
49226                $cloned.appendTo($slideHolderDom);
49227
49228            });
49229
49230            for (var i = slideRefs.length - 1; i >= 0; i--) {
49231
49232                var $cloned = $(slideRefs[i]).clone();
49233
49234                
49235                
49236
49237                $cloned.find('video').each(function() {
49238                    var myPoster = $(this).attr('poster');
49239                    if (!myPoster) return;
49240                    var posterDom = document.createElement("img");
49241                    posterDom.src = myPoster;
49242                    posterDom.style.position = 'absolute';
49243                    this.parentNode.replaceChild(posterDom, this);
49244                });
49245
49246                
49247                $cloned.find('[id]').each(function() {
49248                    $(this).attr('id', $(this).attr('id') + '_cloned_before');
49249                });
49250                if ($cloned.attr('id')) $cloned.attr('id', $cloned.attr('id') + '_cloned_before');
49251
49252                
49253                if ($cloned.attr('class')) {
49254                    $cloned.attr('class', $cloned.attr('class').replace(/fso-slide-([0-9]*)/, function(match1) {
49255                        return match1 + '_cloned_before';
49256                    }));
49257                }
49258
49259                
49260                if ($cloned.attr('data-slide-id')) {
49261                    $cloned.attr('data-slide-id', $cloned.attr('data-slide-id') + '_cloned_before');
49262                }
49263
49264                $cloned.prependTo($slideHolderDom);
49265
49266            };
49267
49268        }
49269
49270        
49271        
49272        
49273        
49274        
49275        
49276
49277        
49278
49279
49280        
49281        var dots_html = '', thumb_class;
49282        for (var i = 0; i < totalSlides; i++) {
49283            dots_html += '<a class="slide-link" href="#slide' + (i+1) + '"><div class="slide-thumb';
49284            if (thumb_class = $mySlides.eq(i).attr('data-slide-thumb')) {
49285                dots_html += ' ' + thumb_class;
49286            }
49287            if (thumb_class = $mySlides.eq(i).attr('data-slide-thumb-style')) {
49288                dots_html += '" style="' + thumb_class;
49289            }
49290            dots_html += '"><div class="slide-thumb-image"></div></div></a> ';
49291        }
49292        $slideSelectorElem.addClass('scrolling-dots').html('\
49293        <div class="slide-dot-over slide-dot-over-left">\
49294            <a class="slide-first-link"></a>\
49295            <a class="slide-prev-next slide-prev" href="#">Previo</a>\
49296        </div>\
49297        <div class="slide-dots-holder">\
49298            <div class="slide-dots-holder-outer">\
49299                <div class="slide-dots-holder-inner">' + dots_html + '</div>\
49300            </div>\
49301        </div>\
49302        <div class="slide-dot-over slide-dot-over-right">\
49303            <a class="slide-prev-next slide-next" href="#">Siguiente</a>\
49304            <a class="slide-last-link"></a>\
49305        </div>\
49306        ');
49307
49308        $('.slide-dot-over.slide-dot-over-left').eq(1).width($('.slide-prev-next.slide-prev').eq(1).width() + 27);
49309        $('.slide-dot-over.slide-dot-over-right').eq(1).width($('.slide-prev-next.slide-next').eq(1).width() + 37);
49310
49311        if (this.zoomEnabled) {
49312            allZoomedInAppleDots = this.domParent.find('.slide-dots-holder').eq(0).find('.slide-link');
49313            allNormalAppleDots = this.domParent.find('.slide-dots-holder').eq(1).find('.slide-link');
49314        } else {
49315            allNormalAppleDots = this.domParent.find('.slide-dots-holder').eq(0).find('.slide-link');
49316        }
49317
49318        var tempPos = allNormalAppleDots.eq(totalSlides - 1).position();
49319        if (!tempPos) {
49320            
49321            if (this.addControls)
49322                window.console && console.error && console.error('ERROR: slider dot error!');
49323        } else {
49324            lastSlideOffset = allNormalAppleDots.eq(totalSlides - 1).position().left;
49325            if (isRTL) lastSlideOffset = allNormalAppleDots.eq(0).position().left - lastSlideOffset;
49326        }
49327
49328        
49329        this.domParent.find('.slide-link').on('click', function() {
49330            fireEvent('userInteraction', 'click-apple-dot');
49331            var myLink = $(this).attr('href');
49332            if (myLink[0] != '#') return true;
49333            replaceHash(myLink.substring(1));
49334            return false;
49335        });
49336
49337        $slideArrowHolder.on('click', function(e) {
49338
49339            e.preventDefault();
49340            e.stopPropagation();
49341
49342            var isLeftArrow = $(this).hasClass('slide-left-arrow2');
49343
49344            if (isLeftArrow) {
49345                sliderMovePrev();
49346            }
49347            if (!isLeftArrow) {
49348                that.sliderMoveNext();
49349            }
49350
49351            
49352            
49353
49354            fireEvent('userInteraction', 'arrow-click');
49355
49356            return false;
49357        });
49358
49359        this.domParent.find('.fso-slide-mobile-numbers .slide-total').text(totalSlides);
49360        this.domParent.find('.fso-slide-mobile-numbers .slide-num').text(1);
49361
49362        $(window).on('hashchange', function() {
49363            fsoSliderHashChange();
49364        });
49365
49366        
49367
49368
49369        var myFirstSlide = this.determineFirstSlide();
49370        if (myFirstSlide === 1) {
49371
49372            
49373            $mySlideshowHolder.addClass('slider-first-slide');
49374            $slideshowMainElem.attr('data-slide-active', 0);
49375            this.slideHasChanged();
49376
49377            
49378            if (this.autoplayVideos && $mySlides.eq(0).find('.video-js').length) startVideoForSlide(0);
49379
49380        } else {
49381
49382            if (!isIpad) {
49383
49384                fsoSliderGotoSlide(myFirstSlide - 1, !($slideshowMainElem.hasClass('js-slideshow-preinited')));
49385
49386                
49387                if (this.autoplayVideos && $mySlides.eq(myFirstSlide - 1).find('.video-js').length) startVideoForSlide(myFirstSlide - 1);
49388
49389            } else {
49390                fsoSliderGotoSlide(myFirstSlide - 1, false);
49391                sliderPositionSlides(true);
49392            }
49393
49394        }
49395
49396        this.domParent.find('.fso-slide-mobile-numbers').css('opacity', 1);
49397
49398        this.domParent.find('.slide-prev').on('click', function(e) {
49399            e.preventDefault();
49400            sliderMovePrev();
49401            fireEvent('userInteraction', 'prev-click');
49402        });
49403
49404        this.domParent.find('.slide-next').on('click', function(e) {
49405            e.preventDefault();
49406            that.sliderMoveNext();
49407            fireEvent('userInteraction', 'next-click');
49408        });
49409
49410        
49411
49412
49413        
49414        
49415        
49416
49417        if (this.zoomEnabled) {
49418
49419            $('#pre_banner_wrapper').addClass('fso-zoomer');
49420            $('#addthis').addClass('fso-zoomer');
49421            $('#banner').addClass('fso-zoomer');
49422            $('#content_container').addClass('fso-zoomer');
49423            $('#admin-menu').addClass('fso-zoomer');
49424
49425            if (this.zoomOnClick) {
49426                $slideHolderDom.on('click', function(e) {
49427                    if ($('body').hasClass('editing')) return true;
49428                    if ($('body').hasClass('slide-captions-only')) return true;
49429
49430                    
49431                    if (!globalIsMobile && e && e.target && $(e.target).attr('class') && ($(e.target).attr('class').indexOf('vjs') >= 0 || $(e.target).parent().attr('class').indexOf('templated-video-slide') >= 0 ) ) return true;
49432                    if (e && e.target && $(e.target).hasClass('ignore-zoom')) return true;
49433                    if (e && e.target && $(e.target).parents('.ignore-zoom').length) return true;
49434                    if (!fsoSliderZoomedIn) {
49435                        that.fsoSliderZoomIn();
49436                        fireEvent('userInteraction', 'zoom-in');
49437                    } else {
49438                        that.fsoSliderZoomOut();
49439                        fireEvent('userInteraction', 'zoom-out');
49440                    }
49441                });
49442            }
49443
49444            this.domParent.find('.slide-zoomer').on('click', function(e) {
49445                
49446                if (!fsoSliderZoomedIn) {
49447                    that.fsoSliderZoomIn();
49448                    fireEvent('userInteraction', 'zoom-in');
49449                } else {
49450                    that.fsoSliderZoomOut();
49451                    fireEvent('userInteraction', 'zoom-out');
49452                }
49453            });
49454
49455            
49456            
49457            
49458            
49459            
49460            
49461            
49462
49463            this.domParent.find('.fso-slide-upper-bg .closebtn').on('click', function(e) {
49464                fireEvent('userInteraction', 'zoom-out');
49465                that.fsoSliderZoomOut();
49466            });
49467
49468            $(window).on('scroll', function(e) {
49469                if (fsoSliderZoomedIn) that.fsoSliderZoomOut();
49470                
49471            });
49472
49473            $(window).on('resize', function(e) {
49474
49475                if (fsoSliderZoomedIn) {
49476                    
49477                    if (fsoSliderResizeTimer > 0) clearTimeout(fsoSliderResizeTimer);
49478                    fsoSliderResizeTimer = setTimeout(function() {
49479
49480                        $('.fso-slide-lower-bg .slide-selectors').css('left', $(window).width() / 2 - fsoSlideWidth / 2)
49481                        var zoomRatio = that.fsoSliderCalculateZoomRatio();
49482                        $slideshowMainElem
49483                            .css('-moz-transform', '-moz-translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ', 1.0)')
49484                            .css('-ms-transform', '-ms-translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ', 1.0)')
49485                            .css('-o-transform', '-o-translate(0px, ' + -zoomRatio.verticalDelta + 'px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ', 1.0)')
49486                            .css('transform', 'translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ', 1.0)')
49487                            .css('-webkit-transform', 'translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ', 1.0)');
49488                        $('.additional-zoomer-elem')
49489                            .css('-moz-transform', '-moz-translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ', 1.0)')
49490                            .css('-ms-transform', '-ms-translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ', 1.0)')
49491                            .css('-o-transform', '-o-translate(0px, ' + -zoomRatio.verticalDelta + 'px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ', 1.0)')
49492                            .css('transform', 'translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ', 1.0)')
49493                            .css('-webkit-transform', 'translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ', 1.0)');
49494                    }, 300);
49495                }
49496            });
49497
49498        }
49499
49500        
49501        
49502        if ((document.location.host.match(/hotline.org/) || document.location.host.match(/firechrome.org/)) &&
49503            navigator.userAgent.match(/Autoscreencapper/) && document.location.hash.match(/slide/)) {
49504            $('#content_container,#wide_footer,#footer').css('display', 'none');
49505            $('#header').css('overflow', 'hidden');
49506        }
49507
49508        
49509
49510
49511        
49512
49513
49514        
49515
49516
49517        
49518        $(document).on('keydown', function(e) {
49519
49520            if ($('body').hasClass('editing-ip') || $('body').hasClass('editing') || $('body').hasClass('slide-captions-only')) return;
49521            
49522            var d = e.srcElement || e.target;
49523
49524            
49525            if ((d.tagName.toUpperCase() === 'INPUT' && (d.type.toUpperCase() === 'TEXT' || d.type.toUpperCase() === 'PASSWORD' || d.type.toUpperCase() === 'FILE')) || d.tagName.toUpperCase() === 'TEXTAREA') {
49526                return;
49527            }
49528
49529            
49530            if ((e.which == 37 && !isRTL) || (e.which == 39 && isRTL)) {
49531                e.preventDefault();
49532                sliderMovePrev();
49533                fireEvent('userInteraction', 'key-prev');
49534            }
49535            
49536            else if ((e.which == 39 && !isRTL) || (e.which == 37 && isRTL)) {
49537                e.preventDefault();
49538                that.sliderMoveNext();
49539                fireEvent('userInteraction', 'key-next');
49540            }
49541            
49542            else if (that.zoomOnClick && e.which == 27) {
49543                e.preventDefault();
49544                if (fsoSliderZoomedIn) that.fsoSliderZoomOut();
49545                fireEvent('userInteraction', 'zoom-out');
49546            }
49547            
49548            else if (that.zoomOnClick && e.which == 32) {
49549                e.preventDefault();
49550                if (fsoSliderZoomedIn) {
49551                    that.fsoSliderZoomOut();
49552                    fireEvent('userInteraction', 'zoom-out');
49553                } else {
49554                    that.fsoSliderZoomIn();
49555                    fireEvent('userInteraction', 'zoom-in');
49556                }
49557            }
49558
49559        });
49560
49561        this.domParent.find('.slide-first-link').on('click', function(e) {
49562            
49563            replaceHash('slide1');
49564            fireEvent('userInteraction', 'click-first');
49565            return false;
49566        });
49567
49568
49569
49570        this.domParent.find('.slide-last-link').on('click', function(e) {
49571            
49572            replaceHash('slide' + totalSlides);
49573            fireEvent('userInteraction', 'click-last');
49574            return false;
49575        });
49576
49577        
49578
49579
49580
49581        
49582
49583
49584        
49585        if ($('html').hasClass('device-iphone')) {
49586
49587
49588            setTimeout(function() {
49589
49590                var videoStartTime,
49591                    videoInitialX;
49592
49593                
49594                
49595                $('.vjs-poster').each(function() {
49596                    var clone = this.cloneNode(true);
49597                    this.parentNode.replaceChild(clone, this);
49598                });
49599
49600                document.addEventListener('touchstart', function(e) {
49601                    if (e && e.target && e.target.classList && e.target.classList.contains('vjs-poster')) {
49602                        videoStartTime = (new Date()).getTime();
49603                        videoInitialX = e.changedTouches[0].pageX;
49604                    }
49605                }, true);
49606
49607                document.addEventListener('touchend', function(e) {
49608                    
49609                    if (e && e.target && e.target.classList && e.target.classList.contains('vjs-poster')) {
49610
49611                        
49612                        
49613
49614                        if ( ((new Date()).getTime() - videoStartTime < 200) &&
49615                             (Math.abs(videoInitialX - e.changedTouches[0].pageX) < 20) ) {
49616
49617                            e.preventDefault();
49618                            e.stopPropagation();
49619                            e.stopImmediatePropagation();
49620
49621                            var thisVideo = $(e.target).parents('slide').removeClass('paused')
49622                                .addClass('playing').find('video')[0];
49623                            if (!thisVideo) return false;
49624
49625                            thisVideo.play();
49626                            
49627                            
49628                            
49629                            if (!thisVideo.classList.contains('suspend-wired')) {
49630                                thisVideo.addEventListener('suspend', function(e) {
49631                                    setTimeout(function() {
49632                                        $(thisVideo).parents('slide').addClass('paused');
49633                                    }, 500);
49634                                });
49635                                thisVideo.classList.add('suspend-wired');
49636                            }
49637
49638                            return false;
49639
49640                        }
49641                    }
49642                }, true);
49643
49644            }, 3000);
49645
49646        }
49647
49648        
49649
49650
49651        
49652        if ($('html').hasClass('device-ipad')) {
49653
49654            new function() {
49655
49656                
49657
49658                    document.addEventListener('touchstart', function(e) {
49659                       if (e && e.target && (e.target.tagName === 'VIDEO' || e.target.classList.contains('vjs-poster'))) {
49660
49661                           e.target.onplay = function() {
49662                               var all = document.getElementsByClassName('new-age-caption-overlay new-age-caption-overlay-reverse');
49663
49664                               for (var i = 0, max = all.length; i < max; i++) {
49665                                   all[i].style.visibility = 'hidden';
49666                               }
49667                           };
49668
49669                           e.target.onpause = function() {
49670                               var all = document.getElementsByClassName('new-age-caption-overlay new-age-caption-overlay-reverse');
49671
49672                               for (var i = 0, max = all.length; i < max; i++) {
49673                                   all[i].style.visibility = 'visible';
49674                               }
49675                           };
49676                       }
49677                   }, true);
49678
49679                
49680                
49681
49682                return;
49683
49684                var videoStartTime,
49685                    videoInitialX;
49686
49687                document.addEventListener('touchstart', function(e) {
49688                    if (e && e.target && (e.target.tagName === 'VIDEO' || e.target.classList.contains('vjs-poster'))) {
49689                        videoStartTime = (new Date()).getTime();
49690                        videoInitialX = e.changedTouches[0].pageX;
49691                    }
49692                }, true);
49693
49694                document.addEventListener('touchend', function(e) {
49695
49696                    if (e && e.target && e.target.tagName === 'VIDEO') {
49697
49698                        
49699                        
49700
49701                        if ( ((new Date()).getTime() - videoStartTime < 200) &&
49702                             (Math.abs(videoInitialX - e.changedTouches[0].pageX) < 20) ) {
49703                    
49704                            e.target.controls = true;
49705                            e.target.play();
49706                            e.target.parentNode.classList.add('ios-video-playing');
49707                            e.target.parentNode.parentNode.parentNode.classList.add('ios-video-playing');
49708
49709                            var thisVideo = e.target;
49710                            e.target.addEventListener('pause', function(e) {
49711                                thisVideo.controls = false;
49712                                thisVideo.parentNode.classList.remove('ios-video-playing');
49713                                thisVideo.parentNode.parentNode.parentNode.classList.remove('ios-video-playing');
49714                            });
49715
49716                        }
49717
49718                    } else {
49719
49720                        if (e && e.target && e.target.classList.contains('vjs-poster')) {
49721
49722                            if ( ((new Date()).getTime() - videoStartTime < 200) &&
49723                             (Math.abs(videoInitialX - e.changedTouches[0].pageX) < 20) ) {
49724
49725                                var thisVideo = $(e.target).parent().find('video')[0];
49726
49727                                $(thisVideo).parent().addClass('ios-video-playing');
49728                                $(thisVideo).parent().parent().parent().addClass('ios-video-playing');
49729                                
49730                                thisVideo.addEventListener('pause', function(e) {
49731                                    thisVideo.controls = false;
49732                                    $(thisVideo).parent().removeClass('ios-video-playing');
49733                                    $(thisVideo).parent().parent().parent().removeClass('ios-video-playing');
49734                                });
49735                                
49736                            }
49737
49738                        }
49739                    }
49740
49741                }, true);
49742
49743            }();
49744
49745        }
49746
49747        
49748
49749
49750        
49751        $mySlides.find('.item,.inactive-dot').each(function() {
49752
49753            var $this = $(this);
49754
49755            
49756            if ($this.attr('width')) {
49757                $this.css('width', $this.attr('width'));
49758                $this.removeAttr('width');
49759            }
49760
49761            if ($this.attr('height')) {
49762                $this.css('height', $this.attr('height'));
49763                $this.removeAttr('height');
49764            }
49765
49766            var myElem = $(this)[0];
49767            for (var a in attrs) {
49768                var myVal = myElem.style[attrs[a]];
49769                if (!myVal) continue;
49770                myVal = myVal.replace(/px/, '');
49771                if (attrs[a] == 'width' && myVal == 0) continue;
49772                if (attrs[a] == 'height' && myVal == 0) continue;
49773                if (myVal == 'auto' || parseInt(myVal) == NaN) continue;
49774                $this.attr('data-' + attrs[a], parseInt(myVal));
49775            }
49776
49777        });
49778
49779        
49780        
49781        if (globalHas3d)
49782            $slideshowMainElem.css(Modernizr.prefixed('transform'), 'none');
49783
49784        this.resize();
49785
49786        if (window.deviceCustomType == 'desktop') {
49787            $(window).on('resize', function() {
49788                that.resize();
49789            });
49790        }
49791
49792
49793        $active = $('.fso-slide-active .video-js:not(.video-js-inited)');
49794        if($active.length > 0) {
49795            initVideoJS($active[0]);
49796        }
49797        
49798        setTimeout(function(){
49799
49800            $('slide .video-js:not(.video-js-inited)').each(function() {
49801                initVideoJS(this);
49802            });
49803        }, 3000);
49804
49805
49806        
49807        $(window).on('orientationchange', function() {
49808            setTimeout(
49809                function() {
49810                    that.resize();
49811                }, 500);
49812
49813        });
49814
49815        if (globalHas3d && Modernizr.csstransitions)
49816            $slideshowMainElem.css(Modernizr.prefixed('transition'), globalTransitionTransformProps[Modernizr.prefixed('transform')] + ' 1s cubic-bezier(0.165, 0.840, 0.440, 1.000)');
49817
49818        $slideshowMainElem.css('opacity', 1);
49819
49820        var hammertime;
49821
49822        if (Modernizr.touch) {
49823
49824            if (window.deviceCustomType != 'desktop' && this.touchMode == 'photoswipe') {
49825
49826                loadJS('/theme/js/hammer-v2.0.4.min.js', function() {
49827
49828                    
49829                    hammertime = new Hammer($mySlideshowWrapper[0]);
49830                    
49831                    
49832                    hammertime.on('tap doubletap press swipe', function(e) {
49833                        
49834
49835                         
49836
49837                        if (e.target && e.target.classList) {
49838
49839                            if (e.target.classList.contains('menu-label') && !e.target.classList.contains('no-mobile-interaction')) {
49840                                var $mySlideParent = $(e.target).parents('slide').addClass('show');
49841                                openLightbox($mySlideParent, '<div class="mobile-pac-menu"><ul></ul></div>');
49842                                $('.mobile-caption-lightbox-overlay').addClass('menu-lightbox');
49843                                $('.menu-bar-wrapper .menu-bar-item').each(function() {
49844                                    $('.mobile-pac-menu ul').append('<li class="mobile-menu-link" data-class="' +
49845                                        $(this).attr('data-class') + '">' + $(this).html() + '</li>');
49846                                });
49847                                
49848
49849                                e.preventDefault();
49850                                
49851                                
49852                                return false;
49853                            }
49854
49855                            if (e.target.classList.contains('mobile-menu-link')) {
49856                                switch ($(e.target).attr('data-class')) {
49857                                    case 'menu-show':
49858                                        if (currentActiveSlideIdx != 8) {
49859                                            inTouch = false;
49860                                            fsoSliderGotoSlide(7, false);
49861                                            sliderPositionSlides(true);
49862                                        }
49863                                        break;
49864                                    case 'lad-show':
49865                                        if (currentActiveSlideIdx != 10) {
49866                                            inTouch = false;
49867                                            fsoSliderGotoSlide(9, false);
49868                                            sliderPositionSlides(true);
49869                                        }
49870                                        break;
49871                                    case 'hi-show':
49872                                        if (currentActiveSlideIdx != 24) {
49873                                            inTouch = false;
49874                                            fsoSliderGotoSlide(23, false);
49875                                            sliderPositionSlides(true);
49876                                        }
49877                                        break;
49878                                    case 'aola-show':
49879                                        if (currentActiveSlideIdx != 53) {
49880                                            inTouch = false;
49881                                            fsoSliderGotoSlide(52, false);
49882                                            sliderPositionSlides(true);
49883                                        }
49884                                        break;
49885                                    case 'asho-show':
49886                                        if (currentActiveSlideIdx != 34) {
49887                                            inTouch = false;
49888                                            fsoSliderGotoSlide(33, false);
49889                                            sliderPositionSlides(true);
49890                                        }
49891                                        break;
49892                                }
49893                                
49894
49895                                return;
49896                            }
49897                            
49898                        }
49899
49900                        
49901
49902
49903                        if (!window.galleryItems) return console.error('we are too early');
49904                        if ($(e.target).hasClass('cancel-photoswipe-zoom') || $(e.target).parents('.cancel-photoswipe-zoom').length) return;
49905
49906                        
49907
49908                        
49909                        
49910                        
49911
49912                        
49913
49914                        
49915                        
49916                        
49917                        
49918                        
49919                        window.gallery = new PhotoSwipe(document.querySelectorAll('.pswp')[0], PhotoSwipeUI_Default, galleryItems, {
49920                            index: Math.max(0, currentActiveSlideIdx),
49921                            history: false,
49922                        });
49923                        
49924                        gallery.listen('afterChange', function() {
49925
49926                            
49927
49928
49929                            currentActiveSlideIdx = gallery.getCurrentIndex();
49930                            
49931                            replaceHash('slide' + (currentActiveSlideIdx+1));
49932                            
49933                            var captionLength = $mySlides.eq(currentActiveSlideIdx).find('.text-item').text();
49934                            if (captionLength && captionLength.length > 500) {
49935                                $('.pswp .pswp__caption__center').addClass('small-captions');
49936                            } else {
49937                                $('.pswp .pswp__caption__center').removeClass('small-captions');
49938                            }
49939                         
49940                            
49941
49942                            if($( document ).width() <= 768 && currentActiveSlideIdx != 0 && window.location.href  != "/churches/bringing-scientology-world/scientology-media-productions.html" ) {
49943                                $('.pswp__caption__center').html( $mySlides.eq(currentActiveSlideIdx).find('.text-item').html() );
49944                                $('.pswp__caption').removeClass('pswp__caption--empty');
49945                                $mySlides.eq(currentActiveSlideIdx).find('.text-item').addClass('pswp__caption--empty');
49946                            }
49947
49948                            
49949                            if($( document ).width() <= 768 && currentActiveSlideIdx == 0 && $mySlides.eq(currentActiveSlideIdx).find('.single-video-slide-caption').length > 0 ) {
49950                                $('.pswp__caption__center').html('');
49951                            }
49952                           
49953                        });
49954
49955                        gallery.listen('close', function() {
49956                            
49957                            $('.fso-slide-mobile-numbers').html($('.pswp__counter').text());
49958
49959                            $slideshowMainElem.addClass('force-show-spinner');
49960                            $slideshowMainElem.find('.slide-stretcher-outer').removeClass('invisible');
49961
49962                            
49963
49964                            currentActiveSlideIdx = gallery.getCurrentIndex();
49965                            $('slide.fso-slide-active').removeClass('fso-slide-active');
49966                            $mySlides.eq(currentActiveSlideIdx).addClass('fso-slide-active');
49967
49968                            
49969
49970                            $mySlides.eq(currentActiveSlideIdx).find('img[data-src]:not([src])').each(function() {
49971                                var $this = $(this);
49972                                var imgSrc = $this.attr('data-src');
49973
49974                                
49975                                if ($this.attr('data-height') && window.determineImageSources) imgSrc = determineImageSources(this)[0];
49976
49977                                $this.attr('src', imgSrc);
49978                            });
49979
49980                            setTimeout(function() {
49981                                $slideshowMainElem.removeClass('force-show-spinner');
49982                            }, 500);
49983
49984                            
49985                            
49986                            
49987
49988                            hammertime.options.enable = true;
49989
49990                        });
49991
49992                        
49993                        
49994
49995                        $slideshowMainElem.find('.slide-stretcher-outer').addClass('invisible');
49996
49997                        
49998                        hammertime.options.enable = false;
49999                        
50000                        
50001                        gallery.init();
50002
50003                        
50004
50005
50006                        return false;
50007
50008                    });
50009                });
50010
50011            } else {
50012
50013                $slideHolderDom.find('slide').each(function() {
50014                    if ($(this).find('.text-item').length) {
50015                        $(this).append('<div class="text-info-mobile glyphicon-info-sign"></div>');
50016                    }
50017                    if ($(this).hasClass('slide-template-new-c-with-band') && $(this).find('.floater-texter.editable').length) {
50018                        $(this).append('<div class="text-info-mobile glyphicon-info-sign"></div>');
50019                    }
50020                });
50021
50022                slideshowMainElem.addEventListener('touchstart', function(e) {
50023                    onTouchStart(e);
50024                    fireEvent('userInteraction', 'touch-start');
50025                    return false;
50026                }, true);
50027
50028                slideshowMainElem.addEventListener('touchmove', function(e) {
50029                    onTouchMove(e);
50030                    return false;
50031                }, true);
50032
50033                slideshowMainElem.addEventListener('touchend', function(e) {
50034                    onTouchEnd(e);
50035                    return false;
50036                }, true);
50037
50038                slideshowMainElem.addEventListener('touchcancel', function(e) {
50039                    onTouchEnd(e);
50040                    return false;
50041                }, true);
50042
50043                
50044                document.addEventListener('touchend', function(e) {
50045
50046                    if (Math.abs(window.scrollY - slideshowScrollTop) < 20) {
50047                        window.scrollTo(window.scrollX, slideshowScrollTop);
50048                    }
50049
50050                    
50051                    if (!e || !e.target || !e.target.classList) return;
50052
50053                    if (isIpad) {
50054
50055                        if (inTouch && $(e.target).parents('slide').length) {
50056                            onTouchEnd(e);
50057                            return;
50058                        }
50059
50060                        if (e.target.classList.contains('slide-arrow-holder') ||
50061                            $(e.target).parents('.slide-arrow-holder').length) {
50062
50063                            var $me = $(e.target);
50064                            if ($me.hasClass('slide-left-arrow2') || $me.parents('.slide-left-arrow2').length) {
50065                                sliderMovePrev();
50066                            } else {
50067                                that.sliderMoveNext();
50068                            }
50069
50070                            e.preventDefault();
50071                            e.stopPropagation();
50072                            e.stopImmediatePropagation();
50073                            return false;
50074                        }
50075
50076                        if (e.target.classList.contains('menu-label') && !e.target.classList.contains('no-mobile-interaction')) {
50077                            $slideshowMainElem.addClass('always-show');
50078                            e.preventDefault();
50079                            e.stopPropagation();
50080                            e.stopImmediatePropagation();
50081                            return;
50082                        }
50083
50084                    }
50085
50086                    if (e.target.classList.contains('menu-label') && !e.target.classList.contains('no-mobile-interaction')) {
50087                        var $mySlideParent = $(e.target).parents('slide').addClass('show');
50088                        openLightbox($mySlideParent, '<div class="mobile-pac-menu"><ul></ul></div>');
50089                        $('.mobile-caption-lightbox-overlay').addClass('menu-lightbox');
50090                        $('.fso-slide-imagemap.show-overlay-mobile-menu .active-dot.active-dot-slider').each(function() {
50091                            $('.mobile-pac-menu ul').append('<li class="mobile-menu-link" data-class="' +
50092                                $(this).attr('data-class') + '">' + $(this).html() + '</li>');
50093                        });
50094                        $('.mobile-pac-menu ul').append('<li class="mobile-menu-link" data-class="menu-show">Menu</li>');
50095
50096                        e.preventDefault();
50097                        e.stopPropagation();
50098                        e.stopImmediatePropagation();
50099                        return false;
50100                    }
50101
50102                    if (e.target.classList.contains('mobile-menu-link')) {
50103                        closeLightbox($('slide.show').removeClass('show'));
50104                        switch ($(e.target).attr('data-class')) {
50105                            case 'menu-show':
50106                                if (currentActiveSlideIdx != 8) {
50107                                    inTouch = false;
50108                                    fsoSliderGotoSlide(7, false);
50109                                    sliderPositionSlides(true);
50110                                }
50111                                break;
50112                            case 'lad-show':
50113                                if (currentActiveSlideIdx != 10) {
50114                                    inTouch = false;
50115                                    fsoSliderGotoSlide(9, false);
50116                                    sliderPositionSlides(true);
50117                                }
50118                                break;
50119                            case 'hi-show':
50120                                if (currentActiveSlideIdx != 24) {
50121                                    inTouch = false;
50122                                    fsoSliderGotoSlide(23, false);
50123                                    sliderPositionSlides(true);
50124                                }
50125                                break;
50126                            case 'aola-show':
50127                                if (currentActiveSlideIdx != 53) {
50128                                    inTouch = false;
50129                                    fsoSliderGotoSlide(52, false);
50130                                    sliderPositionSlides(true);
50131                                }
50132                                break;
50133                            case 'asho-show':
50134                                if (currentActiveSlideIdx != 34) {
50135                                    inTouch = false;
50136                                    fsoSliderGotoSlide(33, false);
50137                                    sliderPositionSlides(true);
50138                                }
50139                                break;
50140                        }
50141                        
50142
50143                        return;
50144                    }
50145
50146                    if (e.target.classList.contains('text-info-mobile')) {
50147                        var $mySlideParent = $(e.target).parents('slide').addClass('show');
50148                        if (true || $mySlideParent.find('div.text-item').text().length > 200) {
50149                            if ($mySlideParent.hasClass('slide-template-new-c-with-band') && $mySlideParent.find('.floater-texter.editable').length) {
50150                                openLightbox($mySlideParent, $mySlideParent.find('.floater-texter.editable').html());
50151                            } else {
50152                                openLightbox($mySlideParent, $mySlideParent.find('div.text-item').html());
50153                            }
50154                        } else {
50155                            $('body').addClass('mobile-text-info-showing');
50156                        }
50157                        e.preventDefault();
50158                        e.stopPropagation();
50159                        e.stopImmediatePropagation();
50160                        return false;
50161                    }
50162
50163                    if (e.target.classList.contains('text-item') ||
50164                        e.target.classList.contains('mobile-caption-lightbox-overlay') ||
50165                        $(e.target).parents('.mobile-caption-lightbox-overlay').length) {
50166                        closeLightbox($('slide.show').removeClass('show'));
50167                        $('body').removeClass('mobile-text-info-showing');
50168                        e.preventDefault();
50169                        e.stopPropagation();
50170                        e.stopImmediatePropagation();
50171                        return false;
50172                    }
50173
50174                }, true);
50175
50176            }
50177
50178        }
50179
50180        
50181
50182        
50183        
50184        if (globalIsIOS) {
50185            $slideHolderDom.find('slide video').css('display', 'none');
50186            $slideHolderDom.find('slide .vjs-poster').css('display', 'block');
50187        }
50188
50189        logger.debug('responsive-slider.js end of init()');
50190
50191    }
50192
50193    
50194    
50195    me.determineFirstSlide = function() {
50196
50197        
50198        if (this.startSlide) return this.startSlide;
50199
50200        
50201        if ((globalGetParams.video || globalGetParams['video-play']) &&
50202            $slideshowMainElem.find('slide .video-js').length > 0) {
50203
50204            var myVideoParam = globalGetParams.video || globalGetParams['video-play'];
50205
50206            var slideMatching = _.reduce($slideshowMainElem.find('slide .video-js'), function(m, v) {
50207                if (m != null) return m;
50208                var mySlideId = $mySlides.index($(v).parents('slide'));
50209
50210                var cloned = $(v).parents('slide') && $(v).parents('slide')[0].className && $(v).parents('slide')[0].className.indexOf("clone") != -1;
50211
50212                if (getVideoIdForSlide(mySlideId) == myVideoParam && !cloned) return mySlideId;
50213            }, null);
50214
50215
50216            if (slideMatching !== void 0) {
50217                
50218                if (this.autoplayVideos) startVideoForSlide(slideMatching);
50219                return parseInt(slideMatching) + 1;
50220            }
50221
50222            
50223
50224            
50225            if (globalGetParams.slide) {
50226                replaceVideoSource(globalGetParams.slide - 1, myVideoParam);
50227                if (this.autoplayVideos) startVideoForSlide(globalGetParams.slide - 1);
50228                return globalGetParams.slide;
50229            }
50230
50231            
50232            replaceVideoSource(0, myVideoParam);
50233            return 1;
50234
50235        }
50236
50237        if (location.hash) {
50238            var newSlideIdx = parseInt(location.hash.substring(1).replace(/slide/, '')) - 1;
50239            if (!isNaN(newSlideIdx) && newSlideIdx >= 0 && newSlideIdx <= totalSlides - 1)
50240                return newSlideIdx + 1;
50241        }
50242
50243        
50244        return 1;
50245
50246    }
50247
50248    
50249    
50250
50251    function getVideoIdForSlide(slideId) {
50252        var $myElem = $mySlides.eq(slideId).find('.video-js');
50253        if (!$myElem) return null;
50254        var thisVideo = $myElem.attr('class') && $myElem.attr('class').match(/vjs-vi
50254deo-id-[^ ]*/);
50255        return thisVideo && thisVideo.length ? thisVideo[0].replace(/vjs-video-id-/, '') : null;
50256    }
50257
50258    function startVideoForSlide(slideId) {
50259
50260        
50261        if (globalIsIOS) return;
50262
50263        logger.debug('startVideoForSlide, ' + slideId);
50264
50265        var $myVideoJsElem = $mySlides.eq(slideId).find('.video-js');
50266
50267        if ($myVideoJsElem.length == 0) return; 
50268
50269        
50270        var videosPlayed = (cookieMonster.get('gsc_headers_videos_autoplayed') || '');
50271        var videoId = getVideoIdForSlide(slideId);
50272        if (!globalGetParams['video-play'] && _.contains(videosPlayed.split(','), videoId)) return; 
50273
50274        if (!(_.contains(videosPlayed.split(','), videoId)))
50275            videosPlayed = videosPlayed + (videosPlayed == "" ? "" : ",") + videoId;
50276        
50277        
50278
50279        
50280        
50281        fireEvent('videoAutoplay');
50282        playVideoJS($myVideoJsElem);
50283
50284    }
50285
50286    function stopVideoForSlide(slideId) {
50287
50288        logger.debug('stopVideoForSlide, ' + slideId);
50289
50290        var $myVideoJsElem = $mySlides.eq(slideId).find('.video-js');
50291
50292        if ($myVideoJsElem.length == 0) return; 
50293
50294        var videoInst;
50295        if ($myVideoJsElem.prop('tagName') !== 'VIDEO') {
50296            videoInst = videojs($myVideoJsElem.get(0));
50297        }
50298
50299        if (videoInst) videoInst.pause();
50300    }
50301
50302    
50303    function replaceVideoSource(slideId, videoId) {
50304
50305        if (!window.globalVideoSrc) return;
50306
50307        logger.debug('replaceVideoSource, ' + slideId + ', ' + videoId);
50308
50309        var $myVideoJsElem = $mySlides.eq(slideId).find('.video-js');
50310
50311        var videoInst;
50312        if ($myVideoJsElem.prop('tagName') !== 'VIDEO') {
50313            var videoInst = videojs($mySlides.eq(slideId).find('.video-js').get(0));
50314        }
50315
50316        var oldVideoId = getVideoIdForSlide(slideId);
50317        $mySlides.eq(slideId).find('.video-js').removeClass('vjs-video-id-' + oldVideoId)
50318            .addClass('vjs-video-id-' + videoId);
50319
50320        if (videoInst) {
50321            if (globalVideoSrc.match(/.*\.mp4.*/)) {
50322                videoInst.src({ type: 'video/mp4', src: globalVideoSrc });
50323            } else {
50324                videoInst.src(globalVideoSrc);
50325            }
50326        } else {
50327            if (globalVideoSrc.match(/.*\.mp4.*/)) {
50328                $myVideoJsElem.find('source').eq(0).attr('src', globalVideoSrc).attr('type', 'video/mp4');
50329                $myVideoJsElem.find('source:not([src="' + globalVideoSrc + '"])').remove();
50330            } else {
50331                $myVideoJsElem.find('source').eq(0).attr('src', globalVideoSrc);
50332            }
50333        }
50334
50335        try {
50336            if (videoInst) {
50337                window.globalVideoThumb && videoInst.poster(globalVideoThumb);
50338            } else {
50339                window.globalVideoThumb && $myVideoJsElem.attr('poster', globalVideoThumb);
50340            }
50341        } catch (swallow) {}
50342
50343        if (videoInst) {
50344            $mySlides.eq(slideId).find('.vjs-poster').css('display', 'block');
50345        }
50346
50347        return;
50348    }
50349
50350    
50351    
50352
50353    function openLightbox($aDomParent, aInnards) {
50354        $aDomParent.addClass('show-lightbox');
50355        $('body').addClass('show-lightbox-caption').append('\
50356            <div class="mobile-caption-lightbox-overlay">\
50357                <table class="mobile-caption-lightbox-inner">\
50358                    <tr class="mobile-caption-lightbox-filler"></tr>\
50359                    <tr class="mobile-caption-lightbox"><td></td></tr>\
50360                    <tr class="mobile-caption-lightbox-filler"></tr>\
50361                </table>\
50362            </div>');
50363        $('.mobile-caption-lightbox td').html(aInnards);
50364    }
50365
50366    function closeLightbox($aDomParent) {
50367        $aDomParent.removeClass('show-lightbox');
50368        $('body').removeClass('show-lightbox-caption');
50369        $('.mobile-caption-lightbox-overlay').remove();
50370    }
50371
50372    
50373    
50374    
50375    
50376    
50377
50378
50379    
50380    
50381    var initialX,
50382        
50383        currentX,
50384        
50385        startTime,
50386        
50387        myMinSlideLeft,
50388        borkedTouch = false,
50389        myTextReset = true,
50390        inTouch = false;
50391
50392    
50393    function canTouchThis(e) {
50394        return e.target.tagName == 'SLIDE' || $(e.target).parents('slide').length;
50395    }
50396
50397    
50398    var start_touchx = null,
50399        start_touchy = null,
50400        max_touchx = 0,
50401        max_touchy = 0,
50402        locked_x = false,
50403        locked_y = false;
50404
50405    function onTouchStart(e) {
50406
50407        if (borkedTouch || !canTouchThis(e)) return;
50408        if (e.touches.length > 1) {
50409            borkedTouch = true;
50410            return onTouchEnd(e);
50411        }
50412
50413        
50414        if (inTouch) globalAnimationController.cancelAnimation($('.slide-holder'));
50415
50416        
50417        currentX = initialX = e.changedTouches[0].pageX;
50418        
50419        startTime = (new Date()).getTime();
50420        
50421        borkedTouch = false;
50422        inTouch = true;
50423
50424        
50425
50426        
50427        
50428        
50429        sliderPositionSlides(true);
50430
50431        
50432
50433        
50434
50435        
50436        start_touchx = e.touches[0].clientX;
50437        start_touchy = e.touches[0].clientY;
50438        max_touchx = 0;
50439        max_touchy = 0;
50440        locked_x = false;
50441        locked_y = false;
50442
50443    }
50444
50445    function onTouchMove(e) {
50446
50447        
50448
50449        if (!inTouch || borkedTouch) return;
50450        
50451        if (e.touches.length > 1) return onTouchEnd(e);
50452
50453
50454        
50455        if (locked_y) return true;
50456
50457        max_touchx = Math.max(max_touchx, Math.abs(e.changedTouches[0].clientX - start_touchx));
50458        max_touchy = Math.max(max_touchy, Math.abs(e.changedTouches[0].clientY - start_touchy));
50459
50460        if (!locked_x && !locked_y && max_touchx > 12) {
50461        
50462            locked_x = true;
50463        }
50464
50465        if (!locked_x && !locked_y && max_touchy > 12) {
50466        
50467            locked_y = true;
50468
50469            
50470            mySlideholderElem.style[myTransform] = 'translate3d(' +
50471            ((isRTL ? 1 : -1) * (parseInt(-slideholderDelta / 2) + currentActiveSlideIdx * fsoSlideWidth2 +
50472                (isCloned ? totalSlides * fsoSlideWidth2 : 0))) +
50473            'px,0px,0px)';
50474
50475            return;
50476        }
50477
50478        var myX = e.changedTouches[0].pageX;
50479        
50480
50481        
50482
50483
50484        
50485
50486        currentX = myX;
50487
50488        
50489        
50490        
50491
50492        
50493
50494        
50495        
50496        
50497        var myLeft = myX - initialX;
50498
50499        
50500        if (currentActiveSlideIdx == 0 && ((isRTL && myLeft < 10) || (!isRTL && myLeft > 10))) {
50501            myLeft -= myLeft * 0.7;
50502        }
50503
50504        if (currentActiveSlideIdx == totalSlides - 1 && ((isRTL && myLeft > 10) || (!isRTL && myLeft < 10))) {
50505            myLeft -= myLeft * 0.7;
50506        }
50507
50508        
50509
50510
50511        mySlideholderElem.style[myTransform] = 'translate3d(' +
50512            (myLeft + (isRTL ? 1 : -1) * (parseInt(-slideholderDelta / 2) + currentActiveSlideIdx * fsoSlideWidth2 +
50513                (isCloned ? totalSlides * fsoSlideWidth2 : 0))) +
50514            'px,0px,0px)';
50515
50516        
50517
50518        
50519
50520
50521        if (locked_x) e.preventDefault();
50522
50523    }
50524
50525    function onTouchEnd(e) {
50526
50527        if (!inTouch) return;
50528        
50529        if (e.touches.length == 0) borkedTouch = false;
50530
50531        if (e && e.target && e.target.classList && e.target.classList.contains &&
50532            e.target.classList.contains('skip-touch-handling')) {
50533            return false;
50534        }
50535
50536        var myEndTime = (new Date()).getTime();
50537        var myTotalTime = myEndTime - startTime;
50538
50539        
50540
50541        
50542        
50543        
50544        var myXPitch = currentX - initialX;
50545        
50546
50547        var mySlideNum = currentActiveSlideIdx;
50548
50549        if (myXPitch > fsoSlideWidth2 / 2) {
50550            mySlideNum += (isRTL ? 1 : -1);
50551        } else if (myXPitch < -fsoSlideWidth2 / 2) {
50552            mySlideNum += (isRTL ? -1 : 1);
50553        }
50554
50555        
50556
50557
50558        
50559
50560
50561        
50562        var isSwipe = false;
50563        if (myTotalTime < 400 && Math.abs(myXPitch) > 20) {
50564            isSwipe = true;
50565            if (myXPitch > 20) {
50566                mySlideNum = currentActiveSlideIdx + (isRTL ? 1 : -1);
50567            } else {
50568                mySlideNum = currentActiveSlideIdx + (isRTL ? -1 : 1);
50569            }
50570        }
50571
50572        
50573        if (mySlideNum < 0) {
50574            mySlideNum = 0;
50575        } else if (mySlideNum >= totalSlides) {
50576            mySlideNum = totalSlides - 1;
50577        }
50578
50579        
50580
50581
50582        myNewLeft = (isRTL ? 1 : -1) * (parseInt(-slideholderDelta / 2) + mySlideNum * fsoSlideWidth2);
50583        if (isCloned) myNewLeft += (isRTL ? 1 : -1) * totalSlides * fsoSlideWidth2;
50584
50585        
50586        if (false && isSwipe) {
50587            if (currentActiveSlideIdx != mySlideNum) {
50588                
50589                fsoSliderGotoSlide(mySlideNum, false);
50590            }
50591            sliderPositionSlides(true);
50592        } else {
50593            globalAnimationController.animate2d($('.slide-holder'), {
50594                x: myNewLeft,
50595                y: 0
50596            }, (isSwipe ? '.4s cubic-bezier(0.23, 1, 0.32, 1)' : '.5s cubic-bezier(0.23, 1, 0.32, 1)'), function() {
50597                if (currentActiveSlideIdx != mySlideNum) {
50598                    
50599                    fsoSliderGotoSlide(mySlideNum, false);
50600
50601                   $('.fso-slide-active').removeClass('fso-slide-active');
50602                   $mySlides.eq(mySlideNum).addClass('fso-slide-active');
50603                }
50604                sliderPositionSlides(true);
50605                inTouch = false;
50606            });
50607        }
50608
50609    }
50610
50611    
50612    
50613
50614    
50615    me.resize = function() {
50616
50617        if (!this.hasLeftSidebar) {
50618
50619            fsoSlideWidth = this.slidesMax860 ? Math.min(860, $slideshowMainElem.width()) : $slideshowMainElem.width();
50620            xRatio = fsoSlideWidth / 860;
50621            var fsoSlideWrapperWidth = $slideshowMainElem.width();
50622
50623            
50624            var windowHeight = $(window).height();
50625            if (windowHeight < parseInt(this.fsoSliderZoomHeight * xRatio)) {
50626                xRatio = windowHeight / this.fsoSliderZoomHeight;
50627                fsoSlideWidth = parseInt(xRatio * 860);
50628                fsoSlideWrapperWidth = $(window).width();
50629            }
50630
50631            fsoSlideWidth2 = $mySlides.eq(0).outerWidth(true);
50632            
50633            slideholderDelta = fsoSlideWrapperWidth - fsoSlideWidth;
50634            
50635            if (isIpad) slideholderDelta = 0;
50636
50637        } else {
50638
50639            
50640            var currentWidth = $('#banner').width();
50641            fsoSlideWidth = fsoSlideWidth2 = $mySlides.eq(0).outerWidth(true); 
50642            xRatio = fsoSlideWidth / 860;
50643            slideholderDelta = 0;
50644
50645        }
50646
50647        slideshowScrollTop = slideshowMainElem.offsetTop;
50648
50649        
50650        if (globalIsIE) return;
50651
50652        
50653
50654        
50655        if (!window.getCSSRule || /Trident/.test(navigator.userAgent)) {
50656
50657            
50658
50659            var style = document.createElement('style');
50660            style.appendChild(document.createTextNode(''));
50661            document.head.appendChild(style);
50662            var sheet = style.sheet;
50663            
50664            sheet.insertRule('.slide-wrapper slide.slide-templated-new .text-item.animation-left-hold { ' +
50665                'opacity: 0 !important; ' +
50666                'transform: translate3d(' + ((isRTL ? 1 : -1) * fsoSlideWidth2) + 'px, 30px, 0px) !important; ' +
50667                '}', 0);
50668
50669            if (!window.cancelVerticalCaptionCentering && document.body.className.match(/templated-slider-build-2-1/)) {
50670                sheet.insertRule('.slide-wrapper slide.slide-templated-new .text-item.animation-left-hold.js-vertical-middle { ' +
50671                    'opacity: 0 !important; ' +
50672                    'transform: translate3d(' + ((isRTL ? 1 : -1) * fsoSlideWidth2) + 'px, -25%, 0px) !important; ' +
50673                    '}', 1);
50674            }
50675
50676            sheet.insertRule('.slide-wrapper slide.slide-templated-new .text-item.animation-right-hold { ' +
50677                'opacity: 0 !important; ' +
50678                'transform: translate3d(' + ((isRTL ? -1 : 1) * fsoSlideWidth2) + 'px, 30px, 0px) !important; ' +
50679            '}', 2);
50680            if (!window.cancelVerticalCaptionCentering && document.body.className.match(/templated-slider-build-2-1/)) {
50681                sheet.insertRule('.slide-wrapper slide.slide-templated-new .text-item.animation-right-hold.js-vertical-middle { ' +
50682                    'opacity: 0 !important; ' +
50683                    'transform: translate3d(' + ((isRTL ? -1 : 1) * fsoSlideWidth2) + 'px, -25%, 0px) !important; ' +
50684                '}', 3);
50685            }
50686
50687            sheet.insertRule('.slide-wrapper slide.slide-templated-new .text-item.animation-left-hold2 { ' +
50688                'opacity: 1 !important; ' +
50689                'transform: translate3d(' + ((isRTL ? 1 : -1) * fsoSlideWidth2) + 'px, 0px, 0px) !important; ' +
50690            '}', 4);
50691            if (!window.cancelVerticalCaptionCentering && document.body.className.match(/templated-slider-build-2-1/)) {
50692                sheet.insertRule('.slide-wrapper slide.slide-templated-new .text-item.animation-left-hold2.js-vertical-middle { ' +
50693                    'opacity: 1 !important; ' +
50694                    'transform: translate3d(' + ((isRTL ? 1 : -1) * fsoSlideWidth2) + 'px, -50%, 0px) !important; ' +
50695                '}', 5);
50696            }
50697
50698            sheet.insertRule('.slide-wrapper slide.slide-templated-new .text-item.animation-right-hold2 { ' +
50699                'opacity: 1 !important; ' +
50700                'transform: translate3d(' + ((isRTL ? -1 : 1) * fsoSlideWidth2) + 'px, 0px, 0px) !important; ' +
50701            '}', 6);
50702            if (!window.cancelVerticalCaptionCentering && document.body.className.match(/templated-slider-build-2-1/)) {
50703                sheet.insertRule('.slide-wrapper slide.slide-templated-new .text-item.animation-right-hold2.js-vertical-middle { ' +
50704                    'opacity: 1 !important; ' +
50705                    'transform: translate3d(' + ((isRTL ? -1 : 1) * fsoSlideWidth2) + 'px, -50%, 0px) !important; ' +
50706                '}', 7);
50707            }
50708
50709        } else {
50710            if (!this.useSimpleSliding && !globalIsMobile && globalHas3d && Modernizr.csstransitions) {
50711
50712                var prefixedTransform = globalTransitionTransformProps[Modernizr.prefixed('transform')];
50713
50714                getCSSRule('.slide-wrapper slide .item.text-item.animation-left-hold').style.cssText = 'opacity: 0 !important; ' + prefixedTransform + ': translate3d(' + ((isRTL ? 1 : -1) * fsoSlideWidth2) + 'px, 30px, 0px) !important;';
50715                if (!window.cancelVerticalCaptionCentering && document.body.className.match(/templated-slider-build-2-1/) && getCSSRule('.slide-wrapper slide .item.text-item.animation-left-hold.js-vertical-middle')) getCSSRule('.slide-wrapper slide .item.text-item.animation-left-hold.js-vertical-middle').style.cssText = 'opacity: 0 !important; ' + prefixedTransform + ': translate3d(' + ((isRTL ? 1 : -1) * fsoSlideWidth2) + 'px, -25%, 0px) !important;';
50716
50717                getCSSRule('.slide-wrapper slide .item.text-item.animation-right-hold').style.cssText = 'opacity: 0 !important; ' + prefixedTransform + ': translate3d(' + ((isRTL ? -1 : 1) * fsoSlideWidth2) + 'px, 30px, 0px) !important;';
50718                if (!window.cancelVerticalCaptionCentering && document.body.className.match(/templated-slider-build-2-1/) && getCSSRule('.slide-wrapper slide .item.text-item.animation-right-hold.js-vertical-middle')) getCSSRule('.slide-wrapper slide .item.text-item.animation-right-hold.js-vertical-middle').style.cssText = 'opacity: 0 !important; ' + prefixedTransform + ': translate3d(' + ((isRTL ? -1 : 1) * fsoSlideWidth2) + 'px, -25%, 0px) !important;';
50719
50720                getCSSRule('.slide-wrapper slide .item.text-item.animation-left-hold2').style.cssText = 'opacity: 1 !important; ' + prefixedTransform + ': translate3d(' + ((isRTL ? 1 : -1) * fsoSlideWidth2) + 'px, 0px, 0px) !important;';
50721                if (!window.cancelVerticalCaptionCentering && document.body.className.match(/templated-slider-build-2-1/) && getCSSRule('.slide-wrapper slide .item.text-item.animation-left-hold2.js-vertical-middle')) getCSSRule('.slide-wrapper slide .item.text-item.animation-left-hold2.js-vertical-middle').style.cssText = 'opacity: 1 !important; ' + prefixedTransform + ': translate3d(' + ((isRTL ? 1 : -1) * fsoSlideWidth2) + 'px, -50%, 0px) !important;';
50722
50723                getCSSRule('.slide-wrapper slide .item.text-item.animation-right-hold2').style.cssText = 'opacity: 1 !important; ' + prefixedTransform + ': translate3d(' + ((isRTL ? -1 : 1) * fsoSlideWidth2) + 'px, 0px, 0px) !important;';
50724                if (!window.cancelVerticalCaptionCentering && document.body.className.match(/templated-slider-build-2-1/) && getCSSRule('.slide-wrapper slide .item.text-item.animation-right-hold2.js-vertical-middle')) getCSSRule('.slide-wrapper slide .item.text-item.animation-right-hold2.js-vertical-middle').style.cssText = 'opacity: 1 !important; ' + prefixedTransform + ': translate3d(' + ((isRTL ? -1 : 1) * fsoSlideWidth2) + 'px, -50%, 0px) !important;';
50725
50726            }
50727        }
50728
50729        
50730        fsoSliderRecalculateAppleDots();
50731        fsoSliderFixAppleDots(currentActiveSlideIdx);
50732
50733        
50734        $allNonImageElems.each(function() {
50735            resizeElem($(this));
50736        });
50737
50738        
50739        $allImageElems.each(function() {
50740            if ($(this).hasClass('loaded')) {
50741                
50742                resizeElem($(this));
50743            } else {
50744                
50745                
50746                if (!/Trident/.test(navigator.userAgent)) {
50747                    $(this).load(function() {
50748                        resizeElem($(this));
50749                    });
50750                } else {
50751                    setTimeout(function() {
50752                        resizeElem($(this));
50753                    }, 1000);
50754                    setTimeout(function() {
50755                        resizeElem($(this));
50756                    }, 2000);
50757                    setTimeout(function() {
50758                        resizeElem($(this));
50759                    }, 5000);
50760                }
50761            }
50762        });
50763
50764        
50765        $('.slide-arrow-holder .arrow-bg').width(parseInt(slideholderDelta / 2) + 50);
50766        if (slideholderDelta > 0) {
50767            $('.slide-arrow-holder .arrow-bg').addClass('gradiented');
50768            
50769
50770        } else {
50771            $('.slide-arrow-holder .arrow-bg').removeClass('gradiented');
50772            
50773
50774        }
50775
50776        
50777        sliderPositionSlides();
50778
50779    }
50780
50781    
50782    function resizeElem($elem) {
50783
50784        if ($elem.hasClass('js-dynamic-size-set')) return;
50785
50786        for (var a in attrs) {
50787            var myAttrsName = attrs[a];
50788            var myVal = $elem.attr('data-' + myAttrsName);
50789            if (myVal == null || myVal == 'NaN') continue;
50790            if ($elem.hasClass('dynamically-sized')) {
50791                myVal = Math.floor(myVal / xRatio);
50792                $elem.attr('data-' + myAttrsName, myVal);
50793                setTimeout(function() {
50794                    $elem.removeClass('dynamically-sized');
50795                }, 1000);
50796            }
50797            $elem.css(myAttrsName, Math.floor(myVal * xRatio));
50798        }
50799    }
50800
50801    
50802    
50803
50804    
50805    
50806    function loadSurroundingSlides(aSlideNum) {
50807
50808        if (window.deviceCustomType != 'desktop') return;
50809
50810        logger.debug('loading surround: ' + aSlideNum);
50811
50812        var startNum = Math.min(Math.max(aSlideNum - 2, 0), totalSlides - 5);
50813        sliderReloadCounter = 0;
50814        $slideshowMainElem.removeClass('all-loaded');
50815        for (var i = startNum; i < startNum + 5; i++) {
50816            var $thisSlide = $mySlides.eq(i);
50817            $thisSlide.find('.image-item[data-src]:not(.loaded),.image-holder img[data-src]:not(.loaded)').each(function() {
50818                sliderReloadCounter++;
50819                var $myThisSlide = $thisSlide;
50820                var $this = $(this);
50821                $this.css('background', 'none').css('visibility', 'hidden');
50822
50823                if (!/Trident/.test(navigator.userAgent)) {
50824
50825                    $this.load(function() {
50826                        
50827                        $this.css('visibility', 'visible');
50828                        var $myMyThisSlide = $myThisSlide;
50829                        
50830                        sliderLoaded();
50831                    });
50832
50833                }
50834
50835                
50836
50837                $(this).load(function() {
50838                    $(this).removeClass('loading-image-hide');
50839                    $(this).parents('.image-holder').removeClass('js-preview');    
50840                });
50841
50842                var imgSrc = $this.attr('data-src');
50843
50844                
50845                if ($this.attr('data-height') && window.determineImageSources) imgSrc = determineImageSources(this)[0];
50846
50847                logger.debug('preloading surround: ' + imgSrc);
50848                $this.addClass('loading-image-hide').attr('src', imgSrc).addClass('loaded');
50849
50850                if (/Trident/.test(navigator.userAgent)) {
50851                    setTimeout(function() {
50852                        
50853                        $this.css('visibility', 'visible');
50854                        var $myMyThisSlide = $myThisSlide;
50855                        
50856                        sliderLoaded();
50857                    }, 3000);
50858                }
50859
50860                
50861                if ($this.parents('.image-holder').length) {
50862
50863                    var $double = $this.parents('.image-holder').find('.zoomer-image');
50864
50865                    (function() {
50866                        setTimeout(function() {
50867                            loadImage($double);
50868                        }, (fsoSliderZoomedIn ? 0 : 500) + i * (fsoSliderZoomedIn ? 20 : 100));
50869                    })();
50870
50871                }
50872
50873
50874            });
50875        }
50876        if (sliderReloadCounter == 0) $slideshowMainElem.addClass('all-loaded');
50877
50878    }
50879
50880    function sliderLoaded() {
50881        if (--sliderReloadCounter == 0) $slideshowMainElem.addClass('all-loaded');
50882    }
50883    
50884    
50885
50886    function sliderMovePrev() {
50887
50888        if (currentActiveSlideIdx == 0 && !isCloned) return;
50889
50890        if (currentActiveSlideIdx > 0) {
50891            
50892            return replaceHash('slide' + currentActiveSlideIdx);
50893        }
50894
50895        
50896        globalAnimationController.cancelAnimation($slideHolderDom);
50897
50898        var deltaX = (isRTL ? -2 : 2) * totalSlides * 100;
50899        slideHolderDom.style[Modernizr.prefixed('transition')] = 'none';
50900        slideHolderDom.offsetHeight;
50901        slideHolderDom.style[Modernizr.prefixed('transform')] = 'translate3d(-' + deltaX + '%, 0, 0)';
50902        slideHolderDom.offsetHeight;
50903        
50904        replaceHash('slide' + totalSlides);
50905
50906    }
50907
50908    me.sliderMovePrev = sliderMovePrev;
50909
50910    me.sliderMoveNext = function() {
50911        
50912        if (currentActiveSlideIdx == totalSlides - 1 && !isCloned) return;
50913
50914        if (currentActiveSlideIdx <  totalSlides - 1) {
50915            
50916            return replaceHash('slide' + (currentActiveSlideIdx + 2));
50917        }
50918
50919        
50920        globalAnimationController.cancelAnimation($slideHolderDom);
50921
50922        var deltaX = (isRTL ? -1 : 1) * (totalSlides-1) * 100;
50923        slideHolderDom.style[Modernizr.prefixed('transition')] = 'none';
50924        slideHolderDom.offsetHeight;
50925        slideHolderDom.style[Modernizr.prefixed('transform')] = 'translate3d(-' + deltaX + '%, 0, 0)';
50926        slideHolderDom.offsetHeight;
50927        
50928        replaceHash('slide1');
50929
50930    }
50931
50932    
50933
50934
50935    
50936    function sliderEndAnimation(aForce) {
50937
50938        if (ipAnimation == 0 && !aForce) return;
50939        if (ipAnimation != 0) clearTimeout(ipAnimation);
50940        if (fsoSliderZoomTimeout > 0) clearTimeout(fsoSliderZoomTimeout);
50941
50942        $('.sliding .item').removeClass('move-left-fade-out move-right-fade-out move-left-fade-in move-right-fade-in move-left move-right text-left-effect text-right-effect');
50943
50944        if (globalHas3d && Modernizr.csstransitions)
50945            $('.sliding .item').css(Modernizr.prefixed('transform'), 'none')
50946                .css(Modernizr.prefixed('transition'), 'none');
50947
50948        if (globalHas3d)
50949            $('.sliding').css(Modernizr.prefixed('transform'), 'none');
50950
50951        $('.sliding').removeClass('sliding');
50952
50953        sliderPositionSlides();
50954
50955        ipAnimation = 0;
50956
50957    }
50958
50959    function sliderPositionSlides(mobileOptimize) {
50960
50961        
50962
50963        
50964        if (Modernizr.csstransitions && mySlideholderElem.style[Modernizr.prefixed('transition')] != 'none')
50965            mySlideholderElem.style[Modernizr.prefixed('transition')] = 'none';
50966
50967        
50968
50969        var deltaX = (isRTL ? 1 : -1) * fsoSlideWidth2 * currentActiveSlideIdx;
50970        
50971        
50972        
50973
50974        if (isCloned) {
50975            deltaX += (isRTL ? 1 : -1) * totalSlides * fsoSlideWidth2;
50976        }
50977
50978        
50979        
50980
50981        if (globalHas3d && Modernizr.csstransitions) {
50982            mySlideholderElem.style[Modernizr.prefixed('transform')] =
50983                'translate3d(' + deltaX + 'px,0,0)';
50984        } else {
50985            if (window.globalGetParams && globalGetParams.headless) {
50986                mySlideholderElem.style[Modernizr.prefixed('transform')] =
50987                'translate3d(' + deltaX + 'px,0,0)';
50988            } else {
50989                
50990                mySlideholderElem.style.left = deltaX + 'px';
50991            }
50992        }
50993
50994        if (!mobileOptimize) {
50995
50996            $('.slide-holder').removeClass('moving');
50997            $slideshowMainElem.removeClass('moving');
50998            $('.slide-holder').attr('class', $('.slide-holder').attr('class').replace(/[ ]*moving-off-of-[0-9]+/, ''));
50999            $slideshowMainElem.attr('class', $slideshowMainElem.attr('class').replace(/[ ]*moving-off-of-[0-9]+/, ''));
51000            $slideshowMainElem.attr('class', $slideshowMainElem.attr('class').replace(/[ ]*moving-onto-[0-9]+/, ''));
51001            $slideshowMainElem.attr('class', $slideshowMainElem.attr('class').replace(/[ ]*moving-to-dir-[^ ]+/, ''));
51002            
51003            $('.fso-slide-active').removeClass('fso-slide-active');
51004            if ($mySlide) {
51005                $mySlide.addClass('fso-slide-active');
51006            } else {
51007                $mySlides.eq(currentActiveSlideIdx).addClass('fso-slide-active');
51008            }
51009
51010        }
51011
51012        if (isIpad) $slideshowMainElem.removeClass('always-show');
51013
51014    }
51015
51016    animationDebugMode = false;
51017
51018    function fsoSliderAnimateIn($mySlide, aExtraMotion, aDelay, aMoveinText) {
51019
51020        
51021        if (globalIsIE) return aDelay;
51022
51023        if (aExtraMotion != 0) {
51024
51025            if (globalHas3d && Modernizr.csstransitions) {
51026                $mySlide.css(Modernizr.prefixed('transform'), 'translate3d(' + aExtraMotion + 'px, 0px, 0px)');
51027            } else {
51028                $mySlide.css('left', -aExtraMotion + 'px');
51029            }
51030        }
51031
51032        $mySlide.find('.item').each(function() {
51033
51034            var $myItem = $(this);
51035            var noAnimateDelay = $myItem.hasClass('no-animation-delay');
51036            if ($myItem.hasClass('text-item')) {
51037                if (aMoveinText) {
51038
51039                    var customDirection = myDirection;
51040                    
51041                    
51042                    
51043                    
51044                    
51045
51046                    $myItem.css('opacity', 1).addClass('animation-' + customDirection + '-hold');
51047                    (function() {
51048                        var theDirection = customDirection;
51049                        textAnimationQueue.push(setTimeout(function() {
51050                            $myItem.removeClass('animation-' + theDirection + '-hold').addClass('animation-' + theDirection + '-hold2');
51051                        }, 500 + aDelay));
51052                    })();
51053
51054                    
51055
51056
51057                }
51058            } else {
51059                if (aMoveinText || noAnimateDelay) {
51060                    var animateProps = {
51061                        opacity: 1
51062                    };
51063                    if (globalHas3d && Modernizr.csstransitions) {
51064                        animateProps[Modernizr.prefixed('transform')] = 'translate3d(' +
51065                            ((myDirection == 'left' ? minusOne : plusOne) * fsoSlideWidth2) +
51066                            'px, 0px, 0px)';
51067                        globalAnimationController.animate(
51068                            $myItem,
51069                            animateProps,
51070                            (
51071                                noAnimateDelay ?
51072                                (animationDebugMode ? '10s' : '1s') + ' cubic-bezier(0.23, 1, 0.32, 1)' :
51073                                (animationDebugMode ? '8s' : '.8s') + ' cubic-bezier(0.165, 0.840, 0.440, 1.000) ' + aDelay + 'ms'
51074                            )
51075                        );
51076                    } else {
51077                        $myItem.css('left', (myDirection == 'left' ? -1 : 1) * fsoSlideWidth2 + 'px');
51078                    }
51079                } else {
51080                    $myItem.addClass('move-' + myDirection);
51081                }
51082
51083                
51084
51085
51086            }
51087            aDelay += (animationDebugMode ? 500 : 50);
51088
51089        });
51090
51091        return aDelay;
51092
51093    }
51094
51095    
51096    function fsoSliderFixAppleDots(newSlideIdx) {
51097
51098        if (!tooManyAppleDots) return;
51099
51100        var animateProps = {};
51101
51102        
51103        if (newSlideIdx > totalSlides / 2) {
51104
51105            animateProps[isRTL ? 'right' : 'left'] = dotHolderWidth + (
51106                fsoSliderZoomedIn ?
51107                ($('.slide-dot-over.slide-dot-over-left').eq(1).width() - lastSlideOffset) :
51108                ($('.slide-dot-over.slide-dot-over-left').eq(1).width() - lastSlideOffset)
51109            );
51110            
51111            $('.slide-dots-holder-inner').stop(true, true).animate(animateProps, 300, function() {
51112                $('.slide-link[href="#slide' + (midwaySlideNumLow + 5) + '"]').css('opacity', 0.8);
51113                $('.slide-link[href="#slide' + (midwaySlideNumLow + 4) + '"]').css('opacity', 0.4);
51114                $('.slide-link[href="#slide' + (midwaySlideNumLow + 3) + '"]').css('opacity', 0.2);
51115                $('.slide-link[href="#slide' + (midwaySlideNumLow + 2) + '"]').css('opacity', 0.1);
51116                $('.slide-link[href="#slide' + (midwaySlideNum - 1) + '"]').css('opacity', 1);
51117                $('.slide-link[href="#slide' + midwaySlideNum + '"]').css('opacity', 1);
51118                $('.slide-link[href="#slide' + (midwaySlideNum + 1) + '"]').css('opacity', 1);
51119                $('.slide-link[href="#slide' + (midwaySlideNum + 2) + '"]').css('opacity', 1);
51120                $('.slide-dots-holder-inner').css('opacity', 1);
51121            });
51122
51123        } else {
51124
51125            animateProps[isRTL ? 'right' : 'left'] = $('.slide-dot-over.slide-dot-over-left').eq(1).width() + 2;
51126
51127            $('.slide-dots-holder-inner').stop(true, true).animate(animateProps, 300, function() {
51128                $('.slide-link[href="#slide' + (midwaySlideNumLow + 5) + '"]').css('opacity', 1);
51129                $('.slide-link[href="#slide' + (midwaySlideNumLow + 4) + '"]').css('opacity', 1);
51130                $('.slide-link[href="#slide' + (midwaySlideNumLow + 3) + '"]').css('opacity', 1);
51131                $('.slide-link[href="#slide' + (midwaySlideNumLow + 2) + '"]').css('opacity', 1);
51132                $('.slide-link[href="#slide' + (midwaySlideNum - 1) + '"]').css('opacity', 0.8);
51133                $('.slide-link[href="#slide' + midwaySlideNum + '"]').css('opacity', 0.4);
51134                $('.slide-link[href="#slide' + (midwaySlideNum + 1) + '"]').css('opacity', 0.2);
51135                $('.slide-link[href="#slide' + (midwaySlideNum + 2) + '"]').css('opacity', 0.1
51135);
51136                $('.slide-dots-holder-inner').css('opacity', 1);
51137            });
51138
51139        }
51140
51141    }
51142
51143    
51144    function fsoSliderRecalculateAppleDots() {
51145
51146        if (!tooManyAppleDots) return;
51147
51148        var currentDots = (fsoSliderZoomedIn ? allZoomedInAppleDots : allNormalAppleDots);
51149
51150        
51151        if (!fsoSliderZoomedIn && $('.slide-dots-holder')[1]) {
51152            $('.slide-dots-holder')[1].offsetTop;
51153            dotHolderWidth = $('.slide-dots-holder').eq(1).width() - $('.slide-dot-over.slide-dot-over-left').eq(1).width() - $('.slide-dot-over.slide-dot-over-right').eq(1).width() + 30;
51154        } else {
51155            $('.slide-dots-holder')[0].offsetTop;
51156            dotHolderWidth = $('.slide-dots-holder').eq(0).width() - $('.slide-dot-over.slide-dot-over-left').eq(0).width() - $('.slide-dot-over.slide-dot-over-right').eq(0).width() + 30;
51157        }
51158
51159        if (dotHolderWidth >= lastSlideOffset) {
51160            $('body').addClass('fso-slides-wide-enough-for-apple-dots-no-slide');
51161        } else {
51162            $('body').removeClass('fso-slides-wide-enough-for-apple-dots-no-slide');
51163        }
51164
51165        midwaySlideNum = 0;
51166        midwaySlideNumLow = 0;
51167
51168        if (!isRTL) {
51169            for (var i = totalSlides; i >= 1; i--) {
51170                if (midwaySlideNum == 0 && currentDots.eq(i - 1).position().left < dotHolderWidth) {
51171                    midwaySlideNum = i;
51172                }
51173                if (lastSlideOffset - currentDots.eq(i - 1).position().left < dotHolderWidth) {
51174                    midwaySlideNumLow = Math.max(0, i - 3);
51175                }
51176            };
51177        } else {
51178            var overallWidth = $('.slide-dots-holder-inner').eq(1).width();
51179            for (var i = totalSlides; i >= 1; i--) {
51180                if (midwaySlideNum == 0 && overallWidth - currentDots.eq(i - 1).position().left < dotHolderWidth) {
51181                    midwaySlideNum = i;
51182                }
51183
51184                if (lastSlideOffset - (overallWidth - currentDots.eq(i - 1).position().left) < dotHolderWidth) {
51185                    midwaySlideNumLow = Math.max(0, i - 3);
51186                }
51187            };
51188        }
51189
51190        $('.slide-link').css('opacity', 1);
51191
51192    }
51193
51194    function fsoSliderHashChange() {
51195
51196        var newSlideIdx = parseInt(location.hash.substring(1).replace(/slide/, '')) - 1;
51197        if (isNaN(newSlideIdx) || newSlideIdx < 0 || newSlideIdx > totalSlides - 1) return;
51198
51199        if (currentActiveSlideIdx == newSlideIdx) return;
51200
51201        if (!isIpad) {
51202            fsoSliderGotoSlide(newSlideIdx, true);
51203        } else {
51204            fsoSliderGotoSlide(newSlideIdx, false);
51205            sliderPositionSlides(true);
51206        }
51207
51208    }
51209
51210    function fsoSliderGotoSlide(newSlideIdx, animate) {
51211
51212        if (!window.slide8Ignore) {
51213
51214            if (newSlideIdx > 6) {
51215                $('.menu-holder-after-8').fadeIn(300);
51216            } else {
51217                $('.menu-holder-after-8').hide();
51218            }
51219
51220            if (newSlideIdx == 7) {
51221                $('.fso-custom-menu').addClass('always-show');
51222                $('body').addClass('hide-zoomer');
51223            } else {
51224                $('.fso-custom-menu').removeClass('always-show');
51225                $('body').removeClass('hide-zoomer');
51226            }
51227
51228        }
51229
51230        
51231        $('.slide-link').removeClass('selected');
51232        $('.slide-link[href="#slide' + (newSlideIdx + 1) + '"]').addClass('selected');
51233
51234        
51235        
51236        if (animate) fsoSliderFixAppleDots(newSlideIdx);
51237
51238        setTimeout(function() {
51239            loadSurroundingSlides(newSlideIdx);
51240        }, 100);
51241
51242        
51243
51244
51245        if (animate) {
51246
51247            if (!simpleAnimation) {
51248
51249                sliderEndAnimation();
51250
51251                
51252                for (var i = 0; i < textAnimationQueue.length; i++) {
51253                    clearTimeout(textAnimationQueue[i]);
51254                }
51255                $('.text-item').removeClass('animation-left-hold animation-left-hold2 animation-right-hold animation-right-hold2');
51256
51257            }
51258
51259            
51260            myDirection = (currentActiveSlideIdx < newSlideIdx) ? 'left' : 'right';
51261            var myDelay = 0;
51262            var $myActiveSlide = $mySlides.eq(currentActiveSlideIdx).addClass('sliding');
51263            $mySlide = $mySlides.eq(newSlideIdx).addClass('sliding');
51264
51265            
51266            var $myNextSlide = null;
51267            var $myPrevSlide = null;
51268            if (myDirection === 'left') {
51269                if (newSlideIdx < totalSlides - 1)
51270                    $myNextSlide = $mySlides.eq(newSlideIdx + 1).addClass('sliding');
51271                if (currentActiveSlideIdx > 0)
51272                    $myPrevSlide = $mySlides.eq(currentActiveSlideIdx - 1).addClass('sliding');
51273            } else {
51274                if (newSlideIdx > 0)
51275                    $myNextSlide = $mySlides.eq(newSlideIdx - 1).addClass('sliding');
51276                if (currentActiveSlideIdx < totalSlides - 1)
51277                    $myPrevSlide = $mySlides.eq(currentActiveSlideIdx + 1).addClass('sliding');
51278            }
51279
51280            
51281
51282            $('.slide-holder').addClass('moving');
51283            $slideshowMainElem.addClass('moving');
51284            $('.slide-holder').addClass('moving-off-of-' + currentActiveSlideIdx);
51285            $slideshowMainElem.addClass('moving-off-of-' + currentActiveSlideIdx);
51286            $slideshowMainElem.addClass('moving-onto-' + (newSlideIdx + 1));
51287            $slideshowMainElem.addClass('moving-to-dir-' + myDirection);
51288
51289            if (!simpleAnimation) {
51290
51291                
51292                var extraMotion = 0;
51293                var nextExtraMotion = 0;
51294                if (Math.abs(currentActiveSlideIdx - newSlideIdx) > 1) {
51295                    extraMotion = (currentActiveSlideIdx - newSlideIdx) * (fsoSlideWidth2);
51296                    extraMotion += (fsoSlideWidth2) * ((currentActiveSlideIdx < newSlideIdx) ? +1 : -1);
51297                    nextExtraMotion = extraMotion + (fsoSlideWidth2) * ((currentActiveSlideIdx < newSlideIdx) ? +1 : -1);
51298                }
51299
51300                if ($myPrevSlide) {
51301                    $myPrevSlide.find('.item').each(function() {
51302
51303                        var noAnimateDelay = $(this).hasClass('no-animation-delay');
51304
51305                        if (globalHas3d && Modernizr.csstransitions) {
51306                            var animateProps = {
51307                                opacity: window.globalSlideshowFadeout !== void 0 ? globalSlideshowFadeout : 0.2,
51308                            };
51309                            if ($(this).hasClass('text-item')) animateProps.opacity = 0;
51310                            animateProps[Modernizr.prefixed('transform')] = 'translate3d(' +
51311                                ((myDirection == 'left' ? minusOne : plusOne) * fsoSlideWidth2) +
51312                                'px, 0px, 0px)';
51313                            globalAnimationController.animate(
51314                                $(this),
51315                                animateProps,
51316                                (
51317                                    noAnimateDelay ?
51318                                    (animationDebugMode ? '10s' : '1s') + ' cubic-bezier(0.23, 1, 0.32, 1)' :
51319                                    (animationDebugMode ? '6s' : '.6s') + ' cubic-bezier(0.165, 0.840, 0.440, 1.000)'
51320                                )
51321                            );
51322                        } else {
51323                            $(this).css('left', (myDirection == 'left' ? -1 : 1) * fsoSlideWidth2 + 'px');
51324                        }
51325
51326                        
51327
51328                    });
51329                }
51330
51331                $myActiveSlide.find('.item').each(function() {
51332                    var $myItem = $(this);
51333                    var noAnimateDelay = $myItem.hasClass('no-animation-delay');
51334
51335                    if (globalHas3d && Modernizr.csstransitions) {
51336                        var animateProps = {
51337                            opacity: window.globalSlideshowFadeout !== void 0 ? globalSlideshowFadeout : 0.2,
51338                        };
51339                        if ($(this).hasClass('text-item')) animateProps.opacity = 0;
51340                        animateProps[Modernizr.prefixed('transform')] = 'translate3d(' +
51341                            ((myDirection == 'left' ? minusOne : plusOne) * fsoSlideWidth2) +
51342                            'px, 0px, 0px)';
51343                        globalAnimationController.animate(
51344                            $(this),
51345                            animateProps,
51346                            (
51347                                noAnimateDelay ?
51348                                (animationDebugMode ? '10s' : '1s') + ' cubic-bezier(0.23, 1, 0.32, 1)' :
51349                                (animationDebugMode ? '6s' : '.6s') + ' cubic-bezier(0.165, 0.840, 0.440, 1.000) ' + myDelay + 'ms'
51350                            )
51351                        );
51352                    } else {
51353                        $(this).css('left', (myDirection == 'left' ? -1 : 1) * fsoSlideWidth2 + 'px');
51354                    }
51355
51356                    
51357
51358
51359                    myDelay += (animationDebugMode ? 500 : 50);
51360                });
51361
51362                myDelay = Math.max(0, myDelay - (animationDebugMode ? 500 : 50));
51363
51364                if (isCloned) {
51365                    nextExtraMotion += (isRTL ? 1 : -1) * totalSlides * fsoSlideWidth2;
51366                    extraMotion += (isRTL ? 1 : -1) * totalSlides * fsoSlideWidth2;
51367                }
51368
51369            }
51370
51371            if (!simpleAnimation) {
51372                if ($myNextSlide) fsoSliderAnimateIn($myNextSlide, plusOne * nextExtraMotion, 0, false);
51373                myDelay = fsoSliderAnimateIn($mySlide, plusOne * (isRTL ? -1 : 1) * extraMotion, myDelay, true);
51374
51375                ipAnimation = setTimeout(function() {
51376                    sliderEndAnimation();
51377                }, myDelay + animationGracePeriod);
51378
51379                
51380
51381
51382            } else {
51383
51384                
51385                
51386                var deltaX = (isRTL ? -1 : 1) * newSlideIdx * 100;
51387
51388                if (isCloned) {
51389                    deltaX += (isRTL ? -1 : 1) * totalSlides * 100;
51390                }
51391
51392                var animateProps = {};
51393                animateProps[Modernizr.prefixed('transform')] = 'translate3d(' + (-deltaX) + '%, 0, 0)';
51394
51395                globalAnimationController.animate(
51396                    $slideHolderDom,
51397                    animateProps,
51398                    (animationDebugMode ? '8s' : '.8s') + ' cubic-bezier(0.165, 0.840, 0.440, 1.000)',
51399                    function() {
51400                        sliderEndAnimation(true);
51401                    }
51402                );
51403
51404                
51405                
51406                $('.fso-slide-active').removeClass('fso-slide-active');
51407                $mySlides.eq(newSlideIdx).addClass('fso-slide-active');
51408
51409            }
51410
51411        } else {
51412            $mySlide = $mySlides.eq(newSlideIdx); 
51413        }
51414
51415        
51416        me.slideWillChange();
51417
51418        
51419        currentActiveSlideIdx = newSlideIdx;
51420        $slideshowMainElem.attr('data-slide-active', newSlideIdx);
51421        $('.fso-slide-mobile-numbers .slide-num').text(currentActiveSlideIdx + 1);
51422
51423        if ((newSlideIdx == totalSlides - 1)) {
51424            $slideshowMainElem.addClass('fso-slide-last');
51425            $('.slideshow-holder').addClass('fso-slider-last');
51426        } else {
51427            $slideshowMainElem.removeClass('fso-slide-last');
51428            $('.slideshow-holder').removeClass('fso-slider-last');
51429        }
51430
51431        if (newSlideIdx == 0) {
51432            $('.slideshow-holder').addClass('slider-first-slide');
51433        } else {
51434            $('.slideshow-holder').removeClass('slider-first-slide');
51435        }
51436
51437        
51438        me.slideHasChanged();
51439
51440    };
51441
51442    me.slideWillChange = function() {
51443        if (!globalIsIOS) {
51444            if ($mySlides.eq(currentActiveSlideIdx).find('.video-js').length) stopVideoForSlide(currentActiveSlideIdx);
51445        }
51446        $slideshowMainElem.trigger('slide-will-change', currentActiveSlideIdx);
51447    }
51448
51449    me.slideHasChanged = function() {
51450
51451        if($('.slide-number').length > 0) {
51452            $('.slide-number current').text(currentActiveSlideIdx+1);
51453            $('.slide-number total').text(this.totalSlides());
51454        }
51455
51456        
51457            var $customSlide = $('.custom-slide-leftnav[data-slide-id="' + $mySlides.eq(currentActiveSlideIdx).attr('data-slide-id') + '"]');
51458            $('.custom-slide-leftnav.show').removeClass('show');
51459
51460            if ($customSlide.length) {
51461                $('.slideshow-left-nav').addClass('custom-slide-showing');
51462                $customSlide.addClass('show');
51463            } else {
51464                $('.slideshow-left-nav').removeClass('custom-slide-showing');
51465            }
51466        
51467
51468        var slideArrowRight = $slideshowMainElem.find('.slide-right-arrow2')[0];
51469
51470        if(!this.isCircularClone() && slideArrowLeft != undefined && slideArrowRight != undefined) {
51471            if(currentActiveSlideIdx + 1 == this.totalSlides()) {
51472                $(slideArrowRight).hide();
51473            } else {
51474                $(slideArrowRight).show();
51475            }
51476
51477            if(currentActiveSlideIdx == 0) {
51478                $(slideArrowLeft).hide();
51479            } else {
51480                $(slideArrowLeft).show();
51481            }
51482        }
51483
51484        $slideshowMainElem.trigger('slide-has-changed', currentActiveSlideIdx);
51485        
51486    }
51487
51488    me.fsoSliderZoomIn = function() {
51489
51490         if(window.location.pathname == '/scientology-today/events/scientology-network.html') {
51491            return;
51492        }
51493
51494        
51495        if (globalIsIE) return;
51496
51497        
51498        if (screen && screen.width && screen.width <= 800) return;
51499
51500        if (fsoSliderZoomedIn) return;
51501        sliderEndAnimation();
51502        
51503        $('body')[0].scrollTop = 0;
51504
51505        $('.fso-slide-lower-bg .slide-selectors').css('left', $(window).width() / 2 - fsoSlideWidth / 2);
51506
51507        if (fsoSliderZoomTimeout > 0) clearTimeout(fsoSliderZoomTimeout);
51508
51509        $('.fso-zoomer').addClass('fadeOut').removeClass('fadeIn');
51510
51511        
51512        
51513        $('.fso-custom-slider-fader').css('display', 'block');
51514
51515        
51516
51517        
51518        var zoomRatio = this.fsoSliderCalculateZoomRatio();
51519
51520        $slideshowMainElem
51521            .css('-moz-transform', '-moz-translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ',1.0)')
51522            .css('-ms-transform', '-ms-translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ',1.0)')
51523            .css('-o-transform', '-o-translate(0px, ' + -zoomRatio.verticalDelta + 'px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ',1.0)')
51524            .css('transform', 'translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ',1.0)')
51525            .css('-webkit-transform', 'translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ',1.0)');
51526        $('.additional-zoomer-elem')
51527            .css('-moz-transform', '-moz-translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ',1.0)')
51528            .css('-ms-transform', '-ms-translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ',1.0)')
51529            .css('-o-transform', '-o-translate(0px, ' + -zoomRatio.verticalDelta + 'px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ',1.0)')
51530            .css('transform', 'translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ',1.0)')
51531            .css('-webkit-transform', 'translate3d(0px, ' + -zoomRatio.verticalDelta + 'px, 0px) scale3d(' + zoomRatio.scaleRatio + ',' + zoomRatio.scaleRatio + ',1.0)');
51532
51533        $slideshowMainElem.addClass('zoomedIn');
51534        $('body').addClass('slideshow-zoomed-in');
51535
51536        
51537        
51538        setTimeout(function() {
51539            fsoSliderZoomedIn = true;
51540        }, 50);
51541        
51542        
51543
51544
51545        
51546        $('.slide-dots-holder-inner').css('opacity', 0);
51547        setTimeout(function() {
51548            fsoSliderRecalculateAppleDots();
51549            fsoSliderFixAppleDots(currentActiveSlideIdx);
51550        }, 1000);
51551
51552        
51553        $mySlides.eq(currentActiveSlideIdx).find('.image-holder .zoomer-image:not([src]):not(.loaded)').each(function() {
51554            loadImage($(this));
51555        });
51556
51557        
51558        var i = 0;
51559        $mySlides.find('.image-holder .zoomer-image:not([src]):not(.loaded)').each(function() {
51560            var $this = $(this);
51561            (function() {
51562                setTimeout(function() {
51563                    loadImage($this);
51564                }, 1000 * i++);
51565            })();
51566        });
51567
51568    }
51569
51570    
51571    function loadImage($this) {
51572
51573        if (!$this[0]) return;
51574
51575        if (!$this.hasClass('loaded') && !$this.attr('src')) {
51576            logger.debug('(pre)loading double: ' + $this.attr('data-double-src'));
51577            $this.load(function() {
51578                $this.addClass('loaded').parent('.image-holder').addClass('double-loaded');
51579            });
51580            $this.attr('src', $this.attr('data-double-src'));
51581        }
51582    }
51583
51584    me.fsoSliderZoomOut = function() {
51585
51586        
51587        if (globalIsIE) return;
51588
51589        if (!fsoSliderZoomedIn) return;
51590        sliderEndAnimation();
51591
51592        $('.fso-zoomer').css('display', 'block').addClass('fadeIn').removeClass('fadeOut');
51593
51594        
51595        $('.fso-custom-slider-fader').css('display', 'none');
51596
51597        
51598
51599        fsoSliderZoomTimeout = setTimeout(function() {
51600            
51601            fsoSliderZoomTimeout = 0;
51602        }, 1500);
51603
51604        $slideshowMainElem.css('transform', 'none')
51605            .css('-moz-transform', 'none')
51606            .css('-ms-transform', 'none')
51607            .css('-o-transform', 'none')
51608            .css('-webkit-transform', 'none');
51609        $('.additional-zoomer-elem').css('transform', 'none')
51610            .css('-moz-transform', 'none')
51611            .css('-ms-transform', 'none')
51612            .css('-o-transform', 'none')
51613            .css('-webkit-transform', 'none');
51614
51615        $slideshowMainElem.removeClass('zoomedIn');
51616        $('body').removeClass('slideshow-zoomed-in');
51617        fsoSliderZoomedIn = false;
51618
51619        
51620
51621
51622        
51623        $('.slide-dots-holder-inner').css('opacity', 0);
51624        setTimeout(function() {
51625            fsoSliderRecalculateAppleDots();
51626            fsoSliderFixAppleDots(currentActiveSlideIdx);
51627        }, 1000);
51628
51629    }
51630
51631    me.fsoSliderCalculateZoomRatio = function() {
51632
51633        var tempSliderTop = fsoSliderTop || 0;
51634
51635        
51636        tempSliderTop = 0;
51637
51638        var windowWidth = $(window).width();
51639        if (!fsoSliderZoomedIn) windowWidth += 15; 
51640
51641        var horizRatio = (windowWidth - 200) / fsoSlideWidth;
51642        var verticalRatio = ($(window).height() - 120) / this.fsoSliderZoomHeight;
51643        var scaleRatio = Math.min(horizRatio, verticalRatio);
51644
51645        if (scaleRatio < 1) scaleRatio = 1;
51646
51647        var myNewTop = Math.floor(tempSliderTop - ((this.fsoSliderZoomHeight / 2) * scaleRatio - (this.fsoSliderZoomHeight / 2)));
51648        
51649        
51650        if (scaleRatio == horizRatio) {
51651            myNewTop -= Math.floor(($(window).height() - this.fsoSliderZoomHeight * scaleRatio) / 2);
51652        } else {
51653            myNewTop -= (this.sliderZoomTopAdjustment ? this.sliderZoomTopAdjustment : 0) + 40;
51654        }
51655
51656        myNewTop -= $(window).scrollTop();
51657        if ($('#header_and_content_container').length) {
51658            myNewTop += $('#header_and_content_container').position().top;
51659        } else if ($('#header_and_content').length) {
51660            myNewTop += $('#header_and_content').position().top;
51661        }
51662
51663        
51664        if (window.deviceCustomType && deviceCustomType == 'desktop') {
51665            scaleRatio = 1;
51666            console.log(this.fsoSliderZoomHeight);
51667            console.log(tempSliderTop);
51668         
51669            myNewTop = Math.floor(($(window).height() - this.fsoSliderZoomHeight * scaleRatio) / 2);
51670            myNewTop -= $('#header_and_content').position().top;
51671            myNewTop *= -1;
51672            console.log(myNewTop);
51673        }  
51674
51675        return {
51676            verticalDelta: myNewTop,
51677            scaleRatio: scaleRatio
51678        };
51679
51680    }
51681
51682    
51683    me.currentSlideIdx = function() {
51684        return currentActiveSlideIdx;
51685    }
51686
51687    
51688    me.totalSlides = function() {
51689        return totalSlides;
51690    }
51691
51692    
51693    me.isCircularClone = function() {
51694        return isCloned;
51695    }
51696
51697    
51698    function fireEvent(eventName, eventData) {
51699        $mySlideshowWrapper.trigger(eventName, eventData);
51700    }
51701
51702    
51703    function replaceHash(newHash) {
51704        if (history && history.replaceState) {
51705            history.replaceState({}, document.title, '#' + newHash);
51706            return fsoSliderHashChange();
51707        }
51708        location.hash = newHash;
51709    }
51710
51711    me.startVideoForSlide = function(num) {
51712        $myVideoJsElem = $mySlides.eq(num).addClass('ios-video-playing').find('.video-js');
51713        if ($myVideoJsElem.length) {
51714            playVideoJS($myVideoJsElem);
51715        }
51716    }
51717
51718    me.gotoSlide = function(num) {
51719        if(num != currentActiveSlideIdx)
51720        fsoSliderGotoSlide(num, true);
51721    }
51722
51723    me.replaceHash = function(num) {
51724        replaceHash(num);
51725    }
51726
51727    function initVideoJS(el) {
51728
51729        
51730        
51731        if ($('html').hasClass('device-ipad')) {
51732
51733            $('video').each(function() {
51734                this.preload = 'auto';
51735                this.controls = true;
51736                var thisVideo = this;
51737                this.addEventListener('play', function(e) {
51738                    thisVideo.parentNode.classList.add('ios-video-playing');
51739                    
51740                });
51741            });
51742            return {
51743                play: function() {}
51744            }
51745        }
51746
51747        el = $(el);
51748        el.addClass('video-js-inited')
51749        var vid;
51750        if (el && el.get(0) && el.get(0).tagName && el.get(0).tagName.toUpperCase() === 'VIDEO') {
51751            var opts;
51752            try {
51753                opts = JSON.parse(el.attr('data-gsc-setup'));
51754            } catch (e) {}
51755
51756            if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && 
51757                navigator.platform.indexOf("Win") > -1 &&
51758                el.find('source').eq(0).attr('type') != 'video/webm') {
51759                opts.techOrder = ["hls", "html5", "flash"];
51760            }
51761
51762            opts.html5 = {
51763                nativeVideoTracks : false,
51764                nativeAudioTracks : false,
51765                hls: {
51766                  overrideNative: true,
51767                }
51768              };
51769
51770            opts.techOrder = ['hls', 'html5', 'flash'];
51771
51772            vid = videojs(el.get(0), opts || 
51773                {
51774                    controls: true,
51775                    techOrder: ['hls', 'html5', 'flash'],
51776                    html5: {
51777                        nativeVideoTracks : false,
51778                        nativeAudioTracks : false,
51779                        hls: {
51780                          overrideNative: true,
51781                        }
51782                      },
51783                });
51784
51785
51786            
51787            if (opts && opts.showPosterOnVideoEnnd) {
51788                vid.on('ended', function() {
51789
51790                    
51791                    try { vid.cancelFullScreen() } catch (e) {}
51792                    
51793                    
51794                    vid.pause(); 
51795                    if (typeof vid.currentTime === 'function') vid.currentTime(0);
51796
51797                    
51798                    vid.posterImage.show();
51799
51800                    
51801                    $(vid.el()).addClass('gsc-ended');
51802                });
51803            }
51804
51805            
51806            vid.on('play', function (e) {
51807                el.siblings('.vjs-loading-spinner').hide();
51808            })
51809        } else {
51810            vid = videojs(el.get(0));
51811        }
51812
51813        return vid;
51814    }
51815
51816    function playVideoJS(el) {
51817
51818        
51819        if (window.globalGetParams && globalGetParams.headless) return;
51820
51821        var vid = initVideoJS(el);
51822        setTimeout(function () {
51823
51824            if (vid.muted()) {
51825                vid.muted(false);
51826                vid.controls(true);
51827                vid.pause();
51828                $('.video-slide-muted').removeClass('video-slide-muted');
51829                vid.currentTime(0);
51830            }
51831
51832            vid.play();
51833            $('body').addClass('slideshow-vid-playing');
51834
51835            vid.on('ended', function() {
51836                $('body').removeClass('slideshow-vid-playing');
51837            });
51838
51839            vid.on('timeupdate', function() {
51840                if (vid.paused()) {
51841                    $('body').removeClass('slideshow-vid-playing');
51842                } else {
51843                    $('body').addClass('slideshow-vid-playing');
51844                }
51845            });
51846
51847        }, 1);
51848    }
51849
51850    
51851    GscResponsiveSlider.initVideoJS = initVideoJS;
51852    GscResponsiveSlider.playVideoJS = playVideoJS;
51853
51854    return me;
51855
51856})();
51857
51858var globalHas3dResult;
51859
51860
51861var globalHas3d = (function(){
51862    if(globalHas3dResult !== undefined ) {
51863        return globalHas3dResult;
51864    }
51865    var el = document.createElement('p'),
51866    globalHas3d,
51867    transforms = {
51868        'webkitTransform':'-webkit-transform',
51869        'OTransform':'-o-transform',
51870        'msTransform':'-ms-transform',
51871        'MozTransform':'-moz-transform',
51872        'transform':'transform'
51873    };
51874
51875    
51876    if(!document.body) {
51877        return true;
51878    }
51879
51880    
51881    document.body.insertBefore(el, null);
51882
51883    var style = window.getComputedStyle(el);
51884
51885    for(var t in transforms){
51886      if (transforms.hasOwnProperty(t)) {
51887        if( el.style[t] !== undefined ){
51888            el.style[t] = 'translate3d(1px,1px,1px)';
51889            globalHas3d = style.getPropertyValue(transforms[t]);
51890          }
51891        }
51892    }
51893
51894    document.body.removeChild(el);
51895
51896    globalHas3dResult = (globalHas3d !== undefined && globalHas3d.length > 0 && globalHas3d !== "none")
51897
51898    return globalHas3dResult;
51899}());
51900
51901function determineDownloadSpeed(callback) {
51902
51903    var oProgress = document.getElementById("progress");
51904    var startTime, endTime;
51905    var download = new Image();
51906    download.onload = function () {
51907        endTime = (new Date()).getTime();
51908        callback && callback();
51909    }
51910        
51911    download.onerror = function (err, msg) {
51912        oProgress.innerHTML = "Invalid image, or error downloading";
51913    }
51914        
51915    startTime = (new Date()).getTime();
51916    var cacheBuster = "?nnn=" + startTime;
51917    download.src = imageAddr + cacheBuster;
51918    
51919    
51920
51921
51922}
51923
51924//</script>
51925
51926/**
51927
51928@file
51929Autoplayer/controller for a slideshow.
51930@documentation http://wiki.goldeneraproductions.org/wiki/Gsc_headers
51931
51932*/
51933
51934var GscSliderAutoplay = function(slideshowWrapperDom, slideshowRef, opts) {
51935    // mix in the opts
51936    this.slideshowWrapperDom = slideshowWrapperDom;
51937    this.slideshowRef = slideshowRef;
51938    if (opts) for (var key in opts) this[key] = opts[key];
51939}
51940
51941GscSliderAutoplay.prototype = (function() {
51942
51943    var me = {};
51944
51945    // defaults
51946    me.autosliding = false; // need explicit start() to start sliding
51947    me.interval = 9000;
51948
51949    // initializes (hookups, create DOM elements etm.), does not start autoplay yet
51950    me.init = function() {
51951
51952        var self = this;
51953
51954        // don't to it for IE
51955        if (globalIsIE) return this;
51956
51957        // sanity checks
51958        if (!this.slideshowWrapperDom) {
51959            window.console && console.error('No slideshowWrapperDom supplied - cannot initialize autoslider!');
51960            return this;
51961        }
51962
51963        if (!this.slideshowRef) {
51964            window.console && console.error('No slideshowRef supplied - cannot initialize autoslider!');
51965            return this;
51966        }
51967
51968        if (!(this.slideshowWrapperDom instanceof jQuery)) this.slideshowWrapperDom = $(this.slideshowWrapperDom);
51969
51970        // create the DOM elements
51971        this.slideshowWrapperDom.append('<div class="slide-gutter"><div class="slider-artifact">» Menú</div><div class="slider-play-button paused"></div></div>');
51972        this.slideshowWrapperDom.find('.slide-wrapper').append('<div class="slideshow-autoslide-strip-holder"><div class="slideshow-autoslide-strip"></div></div>');
51973        this.stripDom = this.slideshowWrapperDom.find('.slideshow-autoslide-strip');
51974        this.playbuttonDom = this.slideshowWrapperDom.find('.slider-play-button');
51975
51976        this.playbuttonDom.on('click', function() {
51977            if (!self.autosliding) {
51978                self.start();
51979            } else {
51980                self.stop();
51981            }           
51982        });
51983
51984        // hook up with the slideshow
51985        this.slideshowWrapperDom.bind('userInteraction', function() {
51986            self.stop();
51987        });
51988        this.slideshowWrapperDom.bind('videoAutoplay', function() {
51989            // console.log('videoAutoplay event received');
51990            _.defer(function() {
51991                self.stop();    
51992            });
51993            setTimeout(function() {
51994               self.stop();     
51995           }, 500);
51996        });
51997
51998        // console.log('autoplayer is listening for videoAutoplay');
51999
52000        setTimeout(function(){
52001            $(window).resize();
52002        }, 2000);
52003
52004        return this;
52005
52006    }
52007
52008    // animate the strip
52009    me.animateToNext = function() {
52010
52011        var self = this;
52012
52013        this.stripDom.width(0);
52014
52015        // the end, my friend, the end ...
52016        if (!this.slideshowRef.isCircularClone() && this.slideshowRef.currentSlideIdx() == this.slideshowRef.totalSlides() - 1) {
52017            this.stop();
52018            _.defer(function() {
52019                self.stop();
52020            });
52021            return;
52022        }
52023
52024        globalAnimationController.cancelAnimation(this.stripDom, true);
52025
52026        globalAnimationController.animate(this.stripDom, { width: this.stripDom.parent().outerWidth(true) },
52027            this.interval + 'ms linear',
52028            function() {
52029                self.slideshowRef.sliderMoveNext();
52030                _.defer(function() {
52031                    self.animateToNext();
52032                });
52033            }
52034        );
52035
52036    }
52037
52038
52039    // start autoplaying
52040    me.start = function() {
52041
52042        // console.log('autosliding started');
52043
52044        // don't to it for IE
52045        if (globalIsIE) return this;
52046
52047        this.animateToNext();
52048        this.playbuttonDom.removeClass('paused');
52049        this.autosliding = true;
52050        return this;
52051    }
52052
52053    // stop autoplaying
52054    me.stop = function() {
52055        globalAnimationController.cancelAnimation(this.stripDom, true);
52056        this.stripDom.width(0);
52057        this.playbuttonDom.addClass('paused');
52058        this.autosliding = false;
52059        return this;
52060    }
52061
52062    return me;
52063
52064})();
52065
52066
52067/**
52068
52069@file
52070Simple animation controller. Had to make a JS animation controller, partially because CSS transitions don't always fire the transitionEnd events (see spec http://dev.w3.org/csswg/css-transitions/#transition-events), which is required for precise control of animation (i.e. in some cases, we need to ensure
52071that the transition completion callback is called and executed before the next transition
52072begins).
52073
52074FIXME: Falls back to jQuery.animate() if no CSS transition capability (uses modernizr for detection).
52075
52076Requires:
52077---------
52078
52079jQuery, underscore.js, modernizr.js
52080
52081Usage:
52082------
52083
52084```javascript
52085globalAnimationController.animate2d(
52086	aDomElem,
52087	{x: -100, y:0},
52088	'.8s cubic-bezier(0.165, 0.840, 0.440, 1.000)',
52089	function() { ... }
52090);
52091```
52092
52093*/
52094
52095var AnimationController = function(opts) {
52096    // mix in the opts
52097    if (opts) for (var key in opts) this[key] = opts[key];
52098}
52099
52100AnimationController.prototype = (function() {
52101
52102    var me = {};
52103
52104    var transitionTransformProps = {
52105    	'WebkitTransform': '-webkit-transform',
52106    	'MozTransform': '-moz-transform',
52107    	'msTransform': '-ms-transform',
52108    	'OTransform': '-o-transform',
52109    	'transform': 'transform',
52110	};
52111
52112    me.callbacks = {};
52113    me.maxAnimationId = 0;
52114
52115    // for 2D transforms (implemented using translate3d for performance)
52116    me.animate2d = function(aDomElem, aTransform2d, aTransition, aCallbackFunc) {
52117
52118    	logger.debug('animate2d called for: ' + aTransform2d.x + ', ' + aTransition);
52119
52120    	var myController = this;
52121    	if (!(aDomElem instanceof jQuery)) aDomElem = $(aDomElem);
52122
52123    	var myAnimationId = aDomElem.attr('data-animation-id');
52124    	if (!myAnimationId) {
52125    		myAnimationId = myController.maxAnimationId++;
52126    		aDomElem.attr('data-animation-id', myAnimationId);
52127    	}
52128
52129    	myController.cancelAnimation(aDomElem);
52130
52131    	var myCaller = arguments.callee.caller.parent;
52132    	_.defer(function() {
52133
52134	    	if (Modernizr.csstransitions && Modernizr.csstransforms3d) {
52135
52136	    		// FIXME add to the transition property, don't override (otherwise will cobber other)
52137	    		if (aTransition != 'none') {
52138		    		aDomElem.css(
52139                            Modernizr.prefixed('transition'),
52140                            transitionTransformProps[Modernizr.prefixed('transform')] + ' ' + aTransition
52141                        );
52142
52143                        /*
52144                        // add some extra CSS that might speed things up
52145                        .css('-webkit-backface-visibility', 'hidden') // @info http://css-tricks.com/almanac/properties/b/backface-visibility/
52146                        .css('-webkit-transform-style', 'preserve-3d') // @info http://css-tricks.com/almanac/properties/t/transform-style/
52147                        .css('transform-style', 'preserve-3d');
52148                        */
52149
52150		    	} else {
52151		    		aDomElem.css(Modernizr.prefixed('transition'), '');
52152		    	}
52153
52154	            aDomElem.css(Modernizr.prefixed('transform'), 'translate3d(' + aTransform2d.x + 'px' + ',' + aTransform2d.y + 'px,0)');
52155
52156	        } else {
52157
52158	        	// FIXME animation fallback !!!
52159
52160                /*
52161	            aDomElem.animate({
52162	            	left: aTransform2d.x + 'px'
52163	            });
52164                */
52165
52166                aDomElem.css('left', aTransform2d.x + 'px');
52167
52168	            if (aTransform2d.y != 0) aDomElem.animate({
52169	            	top: aTransform2d.y + 'px'
52170	            });
52171
52172	        }
52173
52174	        myController.callbacks[myAnimationId] = [aCallbackFunc];
52175
52176	        logger.debug('animation started to: ' + aTransform2d.x);
52177
52178	        if (aTransition != 'none' && Modernizr.csstransitions && Modernizr.csstransforms3d) {
52179		        aDomElem.on('webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd MSTransitionEnd gcuiTransitionCancelled', function(e) {
52180			        if (e.target != aDomElem[0]) return true; // it's not us
52181			        aDomElem.unbind('webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd MSTransitionEnd gcuiTransitionCancelled');
52182			        logger.debug('transitionEnd called on: ' + aTransform2d.x);
52183			        _cancelAnimation(aDomElem, myCaller);
52184			    });
52185		    } else {
52186
52187		    	logger.debug('wrapping up no-transition on: ' + aTransform2d.x);
52188
52189				// if we are not animating at all, just call the animation compeltiong calls right now
52190		    	if (aTransition == 'none') {
52191					_cancelAnimation(aDomElem, myCaller);
52192				} else {
52193
52194					if (aTransition.match(/ms/)) {
52195						var myTime = parseFloat(aTransition.replace(/ms .*$/, ''));
52196					} else {
52197						var myTime = parseFloat(aTransition.replace(/s .*$/, '')) * 1000;
52198					}
52199
52200					setTimeout(function() {
52201						_cancelAnimation(aDomElem, myCaller);
52202					}, myTime);
52203
52204				}
52205		    }
52206
52207		});
52208
52209    };
52210
52211    // for generic animation
52212    me.animate = function(aDomElem, aProps, aTransition, aCallbackFunc) {
52213
52214    	var myController = this;
52215    	if (!(aDomElem instanceof jQuery)) aDomElem = $(aDomElem);
52216
52217    	var myAnimationId = aDomElem.attr('data-animation-id');
52218    	if (!myAnimationId) {
52219    		myAnimationId = myController.maxAnimationId++;
52220    		aDomElem.attr('data-animation-id', myAnimationId);
52221    	}
52222
52223    	myController.cancelAnimation(aDomElem);
52224
52225    	var myCaller = arguments.callee.caller.parent;
52226    	_.defer(function() {
52227
52228	    	if (Modernizr.csstransitions) {
52229
52230	    		// FIXME add to the transition property, don't override (otherwise will c
52230obber other)
52231	    		if (aTransition != 'none') {
52232	    			aDomElem.css(Modernizr.prefixed('transition'),
52233	    				/*
52234	    				_.reduce(aProps, function(m, v, k) {
52235	    					return m.concat([k + ' ' + aTransition]);
52236	    				}, []).join(', ')
52237						*/
52238						'all ' + aTransition
52239	    			);
52240
52241                    /*
52242	    			// add some extra CSS that might speed things up
52243					.css('-webkit-backface-visibility', 'hidden') // @info http://css-tricks.com/almanac/properties/b/backface-visibility/
52244					.css('-webkit-transform-style', 'preserve-3d') // @info http://css-tricks.com/almanac/properties/t/transform-style/
52245					.css('transform-style', 'preserve-3d');
52246                    */
52247
52248		    	} else {
52249		    		aDomElem.css(Modernizr.prefixed('transition'), '');
52250		    	}
52251
52252		    }
52253
52254	    	_.each(aProps, function(v, k) {
52255	    		aDomElem.css(k, v);
52256	    	});
52257
52258	        myController.callbacks[myAnimationId] = [aCallbackFunc];
52259
52260	        if (aTransition != 'none' && Modernizr.csstransitions) {
52261
52262		        aDomElem.on('webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd MSTransitionEnd gcuiTransitionCancelled', function(e) {
52263			        if (e.target != aDomElem[0]) return true; // it's not us
52264			        aDomElem.unbind('webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd MSTransitionEnd gcuiTransitionCancelled');
52265			        _cancelAnimation(aDomElem, myCaller);
52266			    });
52267		    } else {
52268		    	// if we are not animating at all, just call the animation compeltiong calls right now
52269		    	if (aTransition == 'none') {
52270					_cancelAnimation(aDomElem, myCaller);
52271				} else {
52272
52273					if (aTransition.match(/ms/)) {
52274						var myTime = parseFloat(aTransition.replace(/ms .*$/, ''));
52275					} else {
52276						var myTime = parseFloat(aTransition.replace(/s .*$/, '')) * 1000;
52277					}
52278
52279					setTimeout(function() {
52280						_cancelAnimation(aDomElem, myCaller);
52281					}, myTime);
52282
52283				}
52284		    }
52285
52286		});
52287
52288    };
52289
52290    // this is an internal one
52291    var _cancelAnimation = function(aDomElem, aCaller) {
52292
52293    	var myAnimationId = aDomElem.attr('data-animation-id');
52294
52295    	// FIXME only remove own transitions, don't clobber all
52296    	Modernizr.prefixed('transition') && aDomElem.css(Modernizr.prefixed('transition'), '');
52297
52298    	// call all callbacks for the element first
52299    	for (var a in me.callbacks[myAnimationId]) {
52300    		me.callbacks[myAnimationId][a] && me.callbacks[myAnimationId][a].apply(aCaller);
52301    	}
52302	    me.callbacks[myAnimationId] = [];
52303
52304    }
52305
52306    // call this to cancel any ongoing transitions on the aDomElem
52307    me.cancelAnimation = function(aDomElem, aSkipCallbacks) {
52308        if (!(aDomElem instanceof jQuery)) aDomElem = $(aDomElem);
52309    	if (aSkipCallbacks) this.callbacks[aDomElem.attr('data-animation-id')] = [];
52310    	aDomElem.trigger('gcuiTransitionCancelled');
52311    }
52312
52313    return me;
52314
52315})();
52316
52317globalAnimationController = new AnimationController();
52318
52319
52320//<script>
52321
52322
52323
52324 var GscResponsiveFlyouts = function(opts) {
52325    
52326    for (var key in opts) this[key] = opts[key];
52327}
52328
52329GscResponsiveFlyouts.prototype = (function() {
52330
52331    var me = {};
52332
52333    me.flyoutDomParent = $('.slideshow-wrapper');
52334    me.slideshowHolderDom = $('.slideshow-holder');
52335
52336    
52337    me.init = function() {
52338
52339        var that = this;
52340
52341        if (!(this.flyoutDomParent instanceof jQuery)) this.flyoutDomParent = $(this.flyoutDomParent);
52342        if (!(this.slideshowHolderDom instanceof jQuery)) this.slideshowHolderDom = $(this.slideshowHolderDom);
52343        
52344        this.flyoutDomParent.find('.flyout > .text-flyout .text-flyout.submenu').each(function() {
52345            $(this).css('margin-top', '-' + Math.floor($(this).height() / 2) + 'px');
52346        });
52347
52348        me.resize();
52349        $(window).on('resize', function() { that.resize(); });
52350
52351        if(cookieMonster.get("mobile-menu") != null && cookieMonster.get("mobile-menu") == "closed") {
52352            $('.slideshow-left-nav-mobile').removeClass('open');
52353        }
52354
52355        wireupTotalTouchControl('js-mobile-flyout-open', function(e) {
52356            
52357            $('.slideshow-left-nav-mobile').toggleClass('open');
52358            if($('.slideshow-left-nav-mobile').hasClass('open')) {
52359                cookieMonster.set("mobile-menu", "opened"); 
52360            } else {
52361                cookieMonster.set("mobile-menu", "closed"); 
52362            }
52363        });
52364
52365    };
52366
52367    me.resize = function() {
52368
52369        var slideshowWidth = this.slideshowHolderDom.width();
52370        var slideshowLeft = this.slideshowHolderDom.offset().left;
52371        var slideshowTop = this.slideshowHolderDom.offset().top;
52372        var slideshowBottom = slideshowTop + this.slideshowHolderDom.height();
52373
52374        if ($(window).width() < 860) {
52375
52376            return;
52377
52378            
52379
52380            this.slideshowHolderDom.find('.flyout > .text-flyout > li.parent').each(function() {
52381                var mySub = $(this).find('ul.text-flyout.submenu');
52382                if (!mySub[0]) return;
52383
52384                mySub.addClass('force-opened');
52385                mySub[0].offsetHeight; 
52386
52387                var myNewHeight = -(Math.floor(mySub.outerHeight(true) / 2) - Math.floor($(this).outerHeight(true) / 2) - 10);
52388                mySub.css('top', myNewHeight + 'px');
52389
52390                
52391
52392
52393                mySub.removeClass('force-opened');
52394
52395            });
52396
52397            
52398
52399        } else {
52400
52401            
52402
52403            
52404            this.slideshowHolderDom.find('.flyout li.parent ul.thumbs-flyout').each(function() {
52405
52406                $(this).css('height', 'auto');
52407
52408                var myLeft = $(this).offset().left - slideshowLeft;
52409                if (isRTL) myLeft = (slideshowLeft + slideshowWidth) - (myLeft + $(this).width());
52410
52411                $(this).css('width', (slideshowWidth - myLeft) + 'px').css('top', '0px');
52412
52413                var myElem = $(this);
52414
52415                $(this).find('li.hidden').removeClass('hidden');
52416
52417                
52418
52419                
52420                
52421                var myBottom = $(this).offset().top + $(this).height();
52422                if (myBottom > slideshowBottom) {
52423
52424                    
52425                    var myMenuitemBottom = $(this).parents('li.parent').offset().top + $(this).parents('li.parent').height();
52426                    if (myMenuitemBottom < slideshowBottom) {
52427                        $(this).css('top', (slideshowBottom - myBottom) + 'px');
52428                    } else {
52429                        $(this).css('top', (myMenuitemBottom - myBottom) + 'px');
52430                    }
52431
52432
52433                    
52434
52435                    
52436
52437                    
52438                    var infiniteGuard = 5000;
52439
52440                    var myTop = $(this).offset().top;
52441
52442                    while (myTop < slideshowTop) {
52443
52444                        var myElems = $(this).find('li').not('.hidden');
52445                        myElems.eq(myElems.length-1).addClass('hidden');
52446
52447
52448
52449                        
52450
52451                        
52452                        myBottom = $(this).offset().top + $(this).height();
52453                        var myCurrentCSSTop = parseInt($(this).css('top').replace(/px/, ''));
52454
52455                        if (myMenuitemBottom < slideshowBottom) {
52456                            $(this).css('top', myCurrentCSSTop + (slideshowBottom - myBottom) + 'px');
52457                        } else {
52458                            $(this).css('top', myCurrentCSSTop + (myMenuitemBottom - myBottom) + 'px');
52459                        }
52460
52461                        
52462
52463                        myBottom = $(this).offset().top + $(this).height();
52464                        myTop = $(this).offset().top;
52465
52466                        if (infiniteGuard-- < 0) {
52467                            window.console && console.error && console.error('ERROR: infinite loop detected');
52468                            break;
52469                        }
52470
52471                        if (Math.floor(myBottom) > slideshowBottom) {
52472                            $(this).css('outline', '2px solid red');
52473                            window.console && console.error && console.error('ERROR: resizing error');
52474                        }
52475
52476                    }
52477
52478                }
52479
52480            });
52481
52482            
52483
52484        }
52485
52486    };
52487
52488    return me;
52489
52490})();
52491
52492
52493//</script>
52494
52495/*!
52496 * VERSION: 1.11.2
52497 * DATE: 2013-11-20
52498 * UPDATES AND DOCS AT: http://www.greensock.com
52499 * 
52500 * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin
52501 *
52502 * @license Copyright (c) 2008-2013, GreenSock. All rights reserved.
52503 * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for
52504 * Club GreenSock members, the software agreement that was issued with your membership.
52505 * 
52506 * @author: Jack Doyle, [email protected]
52507 **/
52508(window._gsQueue||(window._gsQueue=[])).push(function(){"use strict";window._gsDefine("TweenMax",["core.Animation","core.SimpleTimeline","TweenLite"],function(t,e,i){var s=[].slice,r=function(t,e,s){i.call(this,t,e,s),this._cycle=0,this._yoyo=this.vars.yoyo===!0,this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._dirty=!0,this.render=r.prototype.render},n=1e-10,a=i._internals.isSelector,o=i._internals.isArray,h=r.prototype=i.to({},.1,{}),l=[];r.version="1.11.2",h.constructor=r,h.kill()._gc=!1,r.killTweensOf=r.killDelayedCallsTo=i.killTweensOf,r.getTweensOf=i.getTweensOf,r.ticker=i.ticker,h.invalidate=function(){return this._yoyo=this.vars.yoyo===!0,this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._uncache(!0),i.prototype.invalidate.call(this)},h.updateTo=function(t,e){var s,r=this.ratio;e&&this.timeline&&this._startTime<this._timeline._time&&(this._startTime=this._timeline._time,this._uncache(!1),this._gc?this._enabled(!0,!1):this._timeline.insert(this,this._startTime-this._delay));for(s in t)this.vars[s]=t[s];if(this._initted)if(e)this._initted=!1;else if(this._notifyPluginsOfEnabled&&this._firstPT&&i._onPluginEvent("_onDisable",this),this._time/this._duration>.998){var n=this._time;this.render(0,!0,!1),this._initted=!1,this.render(n,!0,!1)}else if(this._time>0){this._initted=!1,this._init();for(var a,o=1/(1-r),h=this._firstPT;h;)a=h.s+h.c,h.c*=o,h.s=a-h.c,h=h._next}return this},h.render=function(t,e,i){this._initted||0===this._duration&&this.vars.repeat&&this.invalidate();var s,r,a,o,h,_,u,p,f=this._dirty?this.totalDuration():this._totalDuration,c=this._time,m=this._totalTime,d=this._cycle,g=this._duration;if(t>=f?(this._totalTime=f,this._cycle=this._repeat,this._yoyo&&0!==(1&this._cycle)?(this._time=0,this.ratio=this._ease._calcEnd?this._ease.getRatio(0):0):(this._time=g,this.ratio=this._ease._calcEnd?this._ease.getRatio(1):1),this._reversed||(s=!0,r="onComplete"),0===g&&(p=this._rawPrevTime,(0===t||0>p||p===n)&&p!==t&&(i=!0,p>n&&(r="onReverseComplete")),this._rawPrevTime=p=!e||t?t:n)):1e-7>t?(this._totalTime=this._time=this._cycle=0,this.ratio=this._ease._calcEnd?this._ease.getRatio(0):0,(0!==m||0===g&&this._rawPrevTime>n)&&(r="onReverseComplete",s=this._reversed),0>t?(this._active=!1,0===g&&(this._rawPrevTime>=0&&(i=!0),this._rawPrevTime=p=!e||t?t:n)):this._initted||(i=!0)):(this._totalTime=this._time=t,0!==this._repeat&&(o=g+this._repeatDelay,this._cycle=this._totalTime/o>>0,0!==this._cycle&&this._cycle===this._totalTime/o&&this._cycle--,this._time=this._totalTime-this._cycle*o,this._yoyo&&0!==(1&this._cycle)&&(this._time=g-this._time),this._time>g?this._time=g:0>this._time&&(this._time=0)),this._easeType?(h=this._time/g,_=this._easeType,u=this._easePower,(1===_||3===_&&h>=.5)&&(h=1-h),3===_&&(h*=2),1===u?h*=h:2===u?h*=h*h:3===u?h*=h*h*h:4===u&&(h*=h*h*h*h),this.ratio=1===_?1-h:2===_?h:.5>this._time/g?h/2:1-h/2):this.ratio=this._ease.getRatio(this._time/g)),c===this._time&&!i&&d===this._cycle)return m!==this._totalTime&&this._onUpdate&&(e||this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||l)),void 0;if(!this._initted){if(this._init(),!this._initted||this._gc)return;this._time&&!s?this.ratio=this._ease.getRatio(this._time/g):s&&this._ease._calcEnd&&(this.ratio=this._ease.getRatio(0===this._time?0:1))}for(this._active||!this._paused&&this._time!==c&&t>=0&&(this._active=!0),0===m&&(this._startAt&&(t>=0?this._startAt.render(t,e,i):r||(r="_dummyGS")),this.vars.onStart&&(0!==this._totalTime||0===g)&&(e||this.vars.onStart.apply(this.vars.onStartScope||this,this.vars.onStartParams||l))),a=this._firstPT;a;)a.f?a.t[a.p](a.c*this.ratio+a.s):a.t[a.p]=a.c*this.ratio+a.s,a=a._next;this._onUpdate&&(0>t&&this._startAt&&this._startTime&&this._startAt.render(t,e,i),e||this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||l)),this._cycle!==d&&(e||this._gc||this.vars.onRepeat&&this.vars.onRepeat.apply(this.vars.onRepeatScope||this,this.vars.onRepeatParams||l)),r&&(this._gc||(0>t&&this._startAt&&!this._onUpdate&&this._startTime&&this._startAt.render(t,e,i),s&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!e&&this.vars[r]&&this.vars[r].apply(this.vars[r+"Scope"]||this,this.vars[r+"Params"]||l),0===g&&this._rawPrevTime===n&&p!==n&&(this._rawPrevTime=0)))}
vendor: 4,147 bytes, line 52508
52508,r.to=function(t,e,i){return new r(t,e,i)},r.from=function(t,e,i){return i.runBackwards=!0,i.immediateRender=0!=i.immediateRender,new r(t,e,i)},r.fromTo=function(t,e,i,s){return s.startAt=i,s.immediateRender=0!=s.immediateRender&&0!=i.immediateRender,new r(t,e,s)},r.staggerTo=r.allTo=function(t,e,n,h,_,u,p){h=h||0;var f,c,m,d,g=n.delay||0,v=[],y=function(){n.onComplete&&n.onComplete.apply(n.onCompleteScope||this,arguments),_.apply(p||this,u||l)};for(o(t)||("string"==typeof t&&(t=i.selector(t)||t),a(t)&&(t=s.call(t,0))),f=t.length,m=0;f>m;m++){c={};for(d in n)c[d]=n[d];c.delay=g,m===f-1&&_&&(c.onComplete=y),v[m]=new r(t[m],e,c),g+=h}return v},r.staggerFrom=r.allFrom=function(t,e,i,s,n,a,o){return i.runBackwards=!0,i.immediateRender=0!=i.immediateRender,r.staggerTo(t,e,i,s,n,a,o)},r.staggerFromTo=r.allFromTo=function(t,e,i,s,n,a,o,h){return s.startAt=i,s.immediateRender=0!=s.immediateRender&&0!=i.immediateRender,r.staggerTo(t,e,s,n,a,o,h)},r.delayedCall=function(t,e,i,s,n){return new r(e,0,{delay:t,onComplete:e,onCompleteParams:i,onCompleteScope:s,onReverseComplete:e,onReverseCompleteParams:i,onReverseCompleteScope:s,immediateRender:!1,useFrames:n,overwrite:0})},r.set=function(t,e){return new r(t,0,e)},r.isTweening=function(t){return i.getTweensOf(t,!0).length>0};var _=function(t,e){for(var s=[],r=0,n=t._first;n;)n instanceof i?s[r++]=n:(e&&(s[r++]=n),s=s.concat(_(n,e)),r=s.length),n=n._next;return s},u=r.getAllTweens=function(e){return _(t._rootTimeline,e).concat(_(t._rootFramesTimeline,e))};r.killAll=function(t,i,s,r){null==i&&(i=!0),null==s&&(s=!0);var n,a,o,h=u(0!=r),l=h.length,_=i&&s&&r;for(o=0;l>o;o++)a=h[o],(_||a instanceof e||(n=a.target===a.vars.onComplete)&&s||i&&!n)&&(t?a.totalTime(a.totalDuration()):a._enabled(!1,!1))},r.killChildTweensOf=function(t,e){if(null!=t){var n,h,l,_,u,p=i._tweenLookup;if("string"==typeof t&&(t=i.selector(t)||t),a(t)&&(t=s(t,0)),o(t))for(_=t.length;--_>-1;)r.killChildTweensOf(t[_],e);else{n=[];for(l in p)for(h=p[l].target.parentNode;h;)h===t&&(n=n.concat(p[l].tweens)),h=h.parentNode;for(u=n.length,_=0;u>_;_++)e&&n[_].totalTime(n[_].totalDuration()),n[_]._enabled(!1,!1)}}};var p=function(t,i,s,r){i=i!==!1,s=s!==!1,r=r!==!1;for(var n,a,o=u(r),h=i&&s&&r,l=o.length;--l>-1;)a=o[l],(h||a instanceof e||(n=a.target===a.vars.onComplete)&&s||i&&!n)&&a.paused(t)};return r.pauseAll=function(t,e,i){p(!0,t,e,i)},r.resumeAll=function(t,e,i){p(!1,t,e,i)},r.globalTimeScale=function(e){var s=t._rootTimeline,r=i.ticker.time;return arguments.length?(e=e||n,s._startTime=r-(r-s._startTime)*s._timeScale/e,s=t._rootFramesTimeline,r=i.ticker.frame,s._startTime=r-(r-s._startTime)*s._timeScale/e,s._timeScale=t._rootTimeline._timeScale=e,e):s._timeScale},h.progress=function(t){return arguments.length?this.totalTime(this.duration()*(this._yoyo&&0!==(1&this._cycle)?1-t:t)+this._cycle*(this._duration+this._repeatDelay),!1):this._time/this.duration()},h.totalProgress=function(t){return arguments.length?this.totalTime(this.totalDuration()*t,!1):this._totalTime/this.totalDuration()},h.time=function(t,e){return arguments.length?(this._dirty&&this.totalDuration(),t>this._duration&&(t=this._duration),this._yoyo&&0!==(1&this._cycle)?t=this._duration-t+this._cycle*(this._duration+this._repeatDelay):0!==this._repeat&&(t+=this._cycle*(this._duration+this._repeatDelay)),this.totalTime(t,e)):this._time},h.duration=function(e){return arguments.length?t.prototype.duration.call(this,e):this._duration},h.totalDuration=function(t){return arguments.length?-1===this._repeat?this:this.duration((t-this._repeat*this._repeatDelay)/(this._repeat+1)):(this._dirty&&(this._totalDuration=-1===this._repeat?999999999999:this._duration*(this._repeat+1)+this._repeatDelay*this._repeat,this._dirty=!1),this._totalDuration)},h.repeat=function(t){return arguments.length?(this._repeat=t,this._uncache(!0)):this._repeat},h.repeatDelay=function(t){return arguments.length?(this._repeatDelay=t,this._uncache(!0)):this._repeatDelay},h.yoyo=function(t){return arguments.length?(this._yoyo=t,this):this._yoyo},r},!0),window._gsDefine("TimelineLite",["core.Animation","core.SimpleTimeline","TweenLite"],function(t,e,
52508i){var s=function(t){e.call(this,t),this._labels={},this.autoRemoveChildren=this.vars.autoRemoveChildren===!0,this.smoothChildTiming=this.vars.smoothChildTiming===!0,this._sortChildren=!0,this._onUpdate=this.vars.onUpdate;var i,s,r=this.vars;for(s in r)i=r[s],a(i)&&-1!==i.join("").indexOf("{self}")&&(r[s]=this._swapSelfInParams(i));a(r.tweens)&&this.add(r.tweens,0,r.align,r.stagger)},r=1e-10,n=i._internals.isSelector,a=i._internals.isArray,o=[],h=function(t){var e,i={};for(e in t)i[e]=t[e];return i},l=function(t,e,i,s){t._timeline.pause(t._startTime),e&&e.apply(s||t._timeline,i||o)},_=o.slice,u=s.prototype=new e;return s.version="1.11.0",u.constructor=s,u.kill()._gc=!1,u.to=function(t,e,s,r){return e?this.add(new i(t,e,s),r):this.set(t,s,r)},u.from=function(t,e,s,r){return this.add(i.from(t,e,s),r)},u.fromTo=function(t,e,s,r,n){return e?this.add(i.fromTo(t,e,s,r),n):this.set(t,r,n)},u.staggerTo=function(t,e,r,a,o,l,u,p){var f,c=new s({onComplete:l,onCompleteParams:u,onCompleteScope:p});for("string"==typeof t&&(t=i.selector(t)||t),n(t)&&(t=_.call(t,0)),a=a||0,f=0;t.length>f;f++)r.startAt&&(r.startAt=h(r.startAt)),c.to(t[f],e,h(r),f*a);return this.add(c,o)},u.staggerFrom=function(t,e,i,s,r,n,a,o){return i.immediateRender=0!=i.immediateRender,i.runBackwards=!0,this.staggerTo(t,e,i,s,r,n,a,o)},u.staggerFromTo=function(t,e,i,s,r,n,a,o,h){return s.startAt=i,s.immediateRender=0!=s.immediateRender&&0!=i.immediateRender,this.staggerTo(t,e,s,r,n,a,o,h)},u.call=function(t,e,s,r){return this.add(i.delayedCall(0,t,e,s),r)},u.set=function(t,e,s){return s=this._parseTimeOrLabel(s,0,!0),null==e.immediateRender&&(e.immediateRender=s===this._time&&!this._paused),this.add(new i(t,0,e),s)},s.exportRoot=function(t,e){t=t||{},null==t.smoothChildTiming&&(t.smoothChildTiming=!0);var r,n,a=new s(t),o=a._timeline;for(null==e&&(e=!0),o._remove(a,!0),a._startTime=0,a._rawPrevTime=a._time=a._totalTime=o._time,r=o._first;r;)n=r._next,e&&r instanceof i&&r.target===r.vars.onComplete||a.add(r,r._startTime-r._delay),r=n;return o.add(a,0),a},u.add=function(r,n,o,h){var l,_,u,p,f,c;if("number"!=typeof n&&(n=this._parseTimeOrLabel(n,0,!0,r)),!(r instanceof t)){if(r instanceof Array||r&&r.push&&a(r)){for(o=o||"normal",h=h||0,l=n,_=r.length,u=0;_>u;u++)a(p=r[u])&&(p=new s({tweens:p})),this.add(p,l),"string"!=typeof p&&"function"!=typeof p&&("sequence"===o?l=p._startTime+p.totalDuration()/p._timeScale:"start"===o&&(p._startTime-=p.delay())),l+=h;return this._uncache(!0)}if("string"==typeof r)return this.addLabel(r,n);if("function"!=typeof r)throw"Cannot add "+r+" into the timeline; it is not a tween, timeline, function, or string.";r=i.delayedCall(0,r)}if(e.prototype.add.call(this,r,n),this._gc&&!this._paused&&this._duration<this.duration())for(f=this,c=f.rawTime()>r._startTime;f._gc&&f._timeline;)f._timeline.smoothChildTiming&&c?f.totalTime(f._totalTime,!0):f._enabled(!0,!1),f=f._timeline;return this},u.remove=function(e){if(e instanceof t)return this._remove(e,!1);if(e instanceof Array||e&&e.push&&a(e)){for(var i=e.length;--i>-1;)this.remove(e[i]);return this}return"string"==typeof e?this.removeLabel(e):this.kill(null,e)},u._remove=function(t,i){e.prototype._remove.call(this,t,i);var s=this._last;return s?this._time>s._startTime+s._totalDuration/s._timeScale&&(this._time=this.duration(),this._totalTime=this._totalDuration):this._time=this._totalTime=0,this},u.append=function(t,e){return this.add(t,this._parseTimeOrLabel(null,e,!0,t))},u.insert=u.insertMultiple=function(t,e,i,s){return this.add(t,e||0,i,s)},u.appendMultiple=function(t,e,i,s){return this.add(t,this._parseTimeOrLabel(null,e,!0,t),i,s)},u.addLabel=function(t,e){return this._labels[t]=this._parseTimeOrLabel(e),this},u.addPause=function(t,e,i,s){return this.call(l,["{self}",e,i,s],this,t)},u.removeLabel=function(t){return delete this._labels[t],this},u.getLabelTime=function(t){return null!=this._labels[t]?this._labels[t]:-1},u._parseTimeOrLabel=function(e,i,s,r){var n;if(r instanceof t&&r.timeline===this)this.remove(r);else if(r&&(r instanceof Array||r.push&&a(r)))for(n=r.length;--n>-1;)r[n]instanceof t&&r[n].timeline===this&&this.remove(r[n]);if("string"==typeof i)return this._parseTimeOrLabel(i,s&&"number"==typeof e&&null==this._labels[i]?e-this.duration():0,s);if(i=i||0,"string"!=typeof e||!isNaN(e)&&null==this._labels[e])null==e&&(e=this.duration());else{if(n=e.indexOf("="),-1===n)return null==this._labels[e]?s?this._labels[e]=this.duration()+i:i:this._labels[e]+i;i=parseInt(e.charAt(n-1)+"1",10)*Number(e.substr(n+1)),e=n>1?this._parseTimeOrLabel(e.substr(0,n-1),0,s):this.duration()}return Number(e)+i},u.seek=function(t,e){return this.totalTime("number"==typeof t?t:this._parseTimeOrLabel(t),e!==!1)},u.stop=function(){return this.paused(!0)},u.gotoAndPlay=function(t,e){return this.play(t,e)},u.gotoAndStop=function(t,e){return this.pause(t,e)}
52508,u.render=function(t,e,i){this._gc&&this._enabled(!0,!1);var s,n,a,h,l,_=this._dirty?this.totalDuration():this._totalDuration,u=this._time,p=this._startTime,f=this._timeScale,c=this._paused;if(t>=_?(this._totalTime=this._time=_,this._reversed||this._hasPausedChild()||(n=!0,h="onComplete",0===this._duration&&(0===t||0>this._rawPrevTime||this._rawPrevTime===r)&&this._rawPrevTime!==t&&this._first&&(l=!0,this._rawPrevTime>r&&(h="onReverseComplete"))),this._rawPrevTime=this._duration||!e||t?t:r,t=_+1e-6):1e-7>t?(this._totalTime=this._time=0,(0!==u||0===this._duration&&(this._rawPrevTime>r||0>t&&this._rawPrevTime>=0))&&(h="onReverseComplete",n=this._reversed),0>t?(this._active=!1,0===this._duration&&this._rawPrevTime>=0&&this._first&&(l=!0),this._rawPrevTime=t):(this._rawPrevTime=this._duration||!e||t?t:r,t=0,this._initted||(l=!0))):this._totalTime=this._time=this._rawPrevTime=t,this._time!==u&&this._first||i||l){if(this._initted||(this._initted=!0),this._active||!this._paused&&this._time!==u&&t>0&&(this._active=!0),0===u&&this.vars.onStart&&0!==this._time&&(e||this.vars.onStart.apply(this.vars.onStartScope||this,this.vars.onStartParams||o)),this._time>=u)for(s=this._first;s&&(a=s._next,!this._paused||c);)(s._active||s._startTime<=this._time&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=a;else for(s=this._last;s&&(a=s._prev,!this._paused||c);)(s._active||u>=s._startTime&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=a;this._onUpdate&&(e||this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||o)),h&&(this._gc||(p===this._startTime||f!==this._timeScale)&&(0===this._time||_>=this.totalDuration())&&(n&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!e&&this.vars[h]&&this.vars[h].apply(this.vars[h+"Scope"]||this,this.vars[h+"Params"]||o)))}},u._hasPausedChild=function(){for(var t=this._first;t;){if(t._paused||t instanceof s&&t._hasPausedChild())return!0;t=t._next}return!1},u.getChildren=function(t,e,s,r){r=r||-9999999999;for(var n=[],a=this._first,o=0;a;)r>a._startTime||(a instanceof i?e!==!1&&(n[o++]=a):(s!==!1&&(n[o++]=a),t!==!1&&(n=n.concat(a.getChildren(!0,e,s)),o=n.length))),a=a._next;return n},u.getTweensOf=function(t,e){for(var s=i.getTweensOf(t),r=s.length,n=[],a=0;--r>-1;)(s[r].timeline===this||e&&this._contains(s[r]))&&(n[a++]=s[r]);return n},u._contains=function(t){for(var e=t.timeline;e;){if(e===this)return!0;e=e.timeline}return!1},u.shiftChildren=function(t,e,i){i=i||0;for(var s,r=this._first,n=this._labels;r;)r._startTime>=i&&(r._startTime+=t),r=r._next;if(e)for(s in n)n[s]>=i&&(n[s]+=t);return this._uncache(!0)},u._kill=function(t,e){if(!t&&!e)return this._enabled(!1,!1);for(var i=e?this.getTweensOf(e):this.getChildren(!0,!0,!1),s=i.length,r=!1;--s>-1;)i[s]._kill(t,e)&&(r=!0);return r},u.clear=function(t){var e=this.getChildren(!1,!0,!0),i=e.length;for(this._time=this._totalTime=0;--i>-1;)e[i]._enabled(!1,!1);return t!==!1&&(this._labels={}),this._uncache(!0)},u.invalidate=function(){for(var t=this._first;t;)t.invalidate(),t=t._next;return this},u._enabled=function(t,i){if(t===this._gc)for(var s=this._first;s;)s._enabled(t,!0),s=s._next;return e.prototype._enabled.call(this,t,i)},u.duration=function(t){return arguments.length?(0!==this.duration()&&0!==t&&this.timeScale(this._duration/t),this):(this._dirty&&this.totalDuration(),this._duration)},u.totalDuration=function(t){if(!arguments.length){if(this._dirty){for(var e,i,s=0,r=this._last,n=999999999999;r;)e=r._prev,r._dirty&&r.totalDuration(),r._startTime>n&&this._sortChildren&&!r._paused?this.add(r,r._startTime-r._delay):n=r._startTime,0>r._startTime&&!r._paused&&(s-=r._startTime,this._timeline.smoothChildTiming&&(this._startTime+=r._startTime/this._timeScale),this.shiftChildren(-r._startTime,!1,-9999999999),n=0),i=r._startTime+r._totalDuration/r._timeScale,i>s&&(s=i),r=e;this._duration=this._totalDuration=s,this._dirty=!1}return this._totalDuration}return 0!==this.totalDuration()&&0!==t&&this.timeScale(this._totalDuration/t),this},u.usesFrames=function(){for(var e=this._timeline;e._timeline;)e=e._timeline;return e===t._rootFramesTimeline},u.rawTime=function(){return this._paused?this._totalTime:(this._timeline.rawTime()-this._startTime)*this._timeScale},s},!0),window._gsDefine("TimelineMax",["TimelineLite","TweenLite","easing.Ease"],function(t,e,
52508i){var s=function(e){t.call(this,e),this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._cycle=0,this._yoyo=this.vars.yoyo===!0,this._dirty=!0},r=1e-10,n=[],a=new i(null,null,1,0),o=s.prototype=new t;return o.constructor=s,o.kill()._gc=!1,s.version="1.11.0",o.invalidate=function(){return this._yoyo=this.vars.yoyo===!0,this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._uncache(!0),t.prototype.invalidate.call(this)},o.addCallback=function(t,i,s,r){return this.add(e.delayedCall(0,t,s,r),i)},o.removeCallback=function(t,e){if(t)if(null==e)this._kill(null,t);else for(var i=this.getTweensOf(t,!1),s=i.length,r=this._parseTimeOrLabel(e);--s>-1;)i[s]._startTime===r&&i[s]._enabled(!1,!1);return this},o.tweenTo=function(t,i){i=i||{};var s,r,o={ease:a,overwrite:2,useFrames:this.usesFrames(),immediateRender:!1};for(s in i)o[s]=i[s];return o.time=this._parseTimeOrLabel(t),r=new e(this,Math.abs(Number(o.time)-this._time)/this._timeScale||.001,o),o.onStart=function(){r.target.paused(!0),r.vars.time!==r.target.time()&&r.duration(Math.abs(r.vars.time-r.target.time())/r.target._timeScale),i.onStart&&i.onStart.apply(i.onStartScope||r,i.onStartParams||n)},r},o.tweenFromTo=function(t,e,i){i=i||{},t=this._parseTimeOrLabel(t),i.startAt={onComplete:this.seek,onCompleteParams:[t],onCompleteScope:this},i.immediateRender=i.immediateRender!==!1;var s=this.tweenTo(e,i);return s.duration(Math.abs(s.vars.time-t)/this._timeScale||.001)},o.render=function(t,e,i){this._gc&&this._enabled(!0,!1);var s,a,o,h,l,_,u=this._dirty?this.totalDuration():this._totalDuration,p=this._duration,f=this._time,c=this._totalTime,m=this._startTime,d=this._timeScale,g=this._rawPrevTime,v=this._paused,y=this._cycle;if(t>=u?(this._locked||(this._totalTime=u,this._cycle=this._repeat),this._reversed||this._hasPausedChild()||(a=!0,h="onComplete",0===this._duration&&(0===t||0>g||g===r)&&g!==t&&this._first&&(l=!0,g>r&&(h="onReverseComplete"))),this._rawPrevTime=this._duration||!e||t?t:r,this._yoyo&&0!==(1&this._cycle)?this._time=t=0:(this._time=p,t=p+1e-6)):1e-7>t?(this._locked||(this._totalTime=this._cycle=0),this._time=0,(0!==f||0===p&&(g>r||0>t&&g>=0)&&!this._locked)&&(h="onReverseComplete",a=this._reversed),0>t?(this._active=!1,0===p&&g>=0&&this._first&&(l=!0),this._rawPrevTime=t):(this._rawPrevTime=p||!e||t?t:r,t=0,this._initted||(l=!0))):(0===p&&0>g&&(l=!0),this._time=this._rawPrevTime=t,this._locked||(this._totalTime=t,0!==this._repeat&&(_=p+this._repeatDelay,this._cycle=this._totalTime/_>>0,0!==this._cycle&&this._cycle===this._totalTime/_&&this._cycle--,this._time=this._totalTime-this._cycle*_,this._yoyo&&0!==(1&this._cycle)&&(this._time=p-this._time),this._time>p?(this._time=p,t=p+1e-6):0>this._time?this._time=t=0:t=this._time))),this._cycle!==y&&!this._locked){var T=this._yoyo&&0!==(1&y),w=T===(this._yoyo&&0!==(1&this._cycle)),x=this._totalTime,b=this._cycle,P=this._rawPrevTime,S=this._time;if(this._totalTime=y*p,y>this._cycle?T=!T:this._totalTime+=p,this._time=f,this._rawPrevTime=0===p?g-1e-5:g,this._cycle=y,this._locked=!0,f=T?0:p,this.render(f,e,0===p),e||this._gc||this.vars.onRepeat&&this.vars.onRepeat.apply(this.vars.onRepeatScope||this,this.vars.onRepeatParams||n),w&&(f=T?p+1e-6:-1e-6,this.render(f,!0,!1)),this._locked=!1,this._paused&&!v)return;this._time=S,this._totalTime=x,this._cycle=b,this._rawPrevTime=P}if(!(this._time!==f&&this._first||i||l))return c!==this._totalTime&&this._onUpdate&&(e||this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||n)),void 0;if(this._initted||(this._initted=!0),this._active||!this._paused&&this._totalTime!==c&&t>0&&(this._active=!0),0===c&&this.vars.onStart&&0!==this._totalTime&&(e||this.vars.onStart.apply(this.vars.onStartScope||this,this.vars.onStartParams||n)),this._time>=f)for(s=this._first;s&&(o=s._next,!this._paused||v);)(s._active||s._startTime<=this._time&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=o;else for(s=this._last;s&&(o=s._prev,!this._paused||v);)(s._active||f>=s._startTime&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=o;
vendor: 10,448 bytes, lines 52508-52509
52508this._onUpdate&&(e||this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||n)),h&&(this._locked||this._gc||(m===this._startTime||d!==this._timeScale)&&(0===this._time||u>=this.totalDuration())&&(a&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!e&&this.vars[h]&&this.vars[h].apply(this.vars[h+"Scope"]||this,this.vars[h+"Params"]||n)))},o.getActive=function(t,e,i){null==t&&(t=!0),null==e&&(e=!0),null==i&&(i=!1);var s,r,n=[],a=this.getChildren(t,e,i),o=0,h=a.length;for(s=0;h>s;s++)r=a[s],r.isActive()&&(n[o++]=r);return n},o.getLabelAfter=function(t){t||0!==t&&(t=this._time);var e,i=this.getLabelsArray(),s=i.length;for(e=0;s>e;e++)if(i[e].time>t)return i[e].name;return null},o.getLabelBefore=function(t){null==t&&(t=this._time);for(var e=this.getLabelsArray(),i=e.length;--i>-1;)if(t>e[i].time)return e[i].name;return null},o.getLabelsArray=function(){var t,e=[],i=0;for(t in this._labels)e[i++]={time:this._labels[t],name:t};return e.sort(function(t,e){return t.time-e.time}),e},o.progress=function(t){return arguments.length?this.totalTime(this.duration()*(this._yoyo&&0!==(1&this._cycle)?1-t:t)+this._cycle*(this._duration+this._repeatDelay),!1):this._time/this.duration()},o.totalProgress=function(t){return arguments.length?this.totalTime(this.totalDuration()*t,!1):this._totalTime/this.totalDuration()},o.totalDuration=function(e){return arguments.length?-1===this._repeat?this:this.duration((e-this._repeat*this._repeatDelay)/(this._repeat+1)):(this._dirty&&(t.prototype.totalDuration.call(this),this._totalDuration=-1===this._repeat?999999999999:this._duration*(this._repeat+1)+this._repeatDelay*this._repeat),this._totalDuration)},o.time=function(t,e){return arguments.length?(this._dirty&&this.totalDuration(),t>this._duration&&(t=this._duration),this._yoyo&&0!==(1&this._cycle)?t=this._duration-t+this._cycle*(this._duration+this._repeatDelay):0!==this._repeat&&(t+=this._cycle*(this._duration+this._repeatDelay)),this.totalTime(t,e)):this._time},o.repeat=function(t){return arguments.length?(this._repeat=t,this._uncache(!0)):this._repeat},o.repeatDelay=function(t){return arguments.length?(this._repeatDelay=t,this._uncache(!0)):this._repeatDelay},o.yoyo=function(t){return arguments.length?(this._yoyo=t,this):this._yoyo},o.currentLabel=function(t){return arguments.length?this.seek(t,!0):this.getLabelBefore(this._time+1e-8)},s},!0),function(){var t=180/Math.PI,e=[],i=[],s=[],r={},n=function(t,e,i,s){this.a=t,this.b=e,this.c=i,this.d=s,this.da=s-t,this.ca=i-t,this.ba=e-t},a=",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",o=function(t,e,i,s){var r={a:t},n={},a={},o={c:s},h=(t+e)/2,l=(e+i)/2,_=(i+s)/2,u=(h+l)/2,p=(l+_)/2,f=(p-u)/8;return r.b=h+(t-h)/4,n.b=u+f,r.c=n.a=(r.b+n.b)/2,n.c=a.a=(u+p)/2,a.b=p-f,o.b=_+(s-_)/4,a.c=o.a=(a.b+o.b)/2,[r,n,a,o]},h=function(t,r,n,a,h){var l,_,u,p,f,c,m,d,g,v,y,T,w,x=t.length-1,b=0,P=t[0].a;for(l=0;x>l;l++)f=t[b],_=f.a,u=f.d,p=t[b+1].d,h?(y=e[l],T=i[l],w=.25*(T+y)*r/(a?.5:s[l]||.5),c=u-(u-_)*(a?.5*r:0!==y?w/y:0),m=u+(p-u)*(a?.5*r:0!==T?w/T:0),d=u-(c+((m-c)*(3*y/(y+T)+.5)/4||0))):(c=u-.5*(u-_)*r,m=u+.5*(p-u)*r,d=u-(c+m)/2),c+=d,m+=d,f.c=g=c,f.b=0!==l?P:P=f.a+.6*(f.c-f.a),f.da=u-_,f.ca=g-_,f.ba=P-_,n?(v=o(_,P,g,u),t.splice(b,1,v[0],v[1],v[2],v[3]),b+=4):b++,P=m;f=t[b],f.b=P,f.c=P+.4*(f.d-P),f.da=f.d-f.a,f.ca=f.c-f.a,f.ba=P-f.a,n&&(v=o(f.a,P,f.c,f.d),t.splice(b,1,v[0],v[1],v[2],v[3]))},l=function(t,s,r,a){var o,h,l,_,u,p,f=[];if(a)for(t=[a].concat(t),h=t.length;--h>-1;)"string"==typeof(p=t[h][s])&&"="===p.charAt(1)&&(t[h][s]=a[s]+Number(p.charAt(0)+p.substr(2)));if(o=t.length-2,0>o)return f[0]=new n(t[0][s],0,0,t[-1>o?0:1][s]),f;for(h=0;o>h;h++)l=t[h][s],_=t[h+1][s],f[h]=new n(l,0,0,_),r&&(u=t[h+2][s],e[h]=(e[h]||0)+(_-l)*(_-l),i[h]=(i[h]||0)+(u-_)*(u-_));return f[h]=new n(t[h][s],0,0,t[h+1][s]),f},_=function(t,n,o,_,u,p){var f,c,m,d,g,v,y,T,w={},x=[],b=p||t[0];u="string"==typeof u?","+u+",":a,null==n&&(n=1);for(c in t[0])x.push(c);if(t.length>1){for(T=t[t.length-1],y=!0,f=x.length;--f>-1;)if(c=x[f],Math.abs(b[c]-T[c])>.05){y=!1;break}y&&(t=t.concat(),p&&t.unshift(p),t.push(t[1]),p=t[t.length-3])}for(e.length=i.length=s.length=0,f=x.length;--f>-1;)c=x[f],r[c]=-1!==u.indexOf(","+c+","),w[c]=l(t,c,r[c],p);for(f=e.length;--f>-1;)e[f]=Math.sqrt(e[f]),i[f]=Math.sqrt(i[f]);if(!_){for(f=x.length;--f>-1;)if(r[c])for(m=w[x[f]],v=m.length-1,d=0;v>d;d++)g=m[d+1].da/i[d]+m[d].da/e[d],s[d]=(s[d]||0)+g*g;for(f=s.length;--f>-1;)s[f]=Math.sqrt(s[f])}for(f=x.length,d=o?4:1;--f>-1;)c=x[f],m=w[c],h(m,n,o,_,r[c]),y&&(m.splice(0,d),m.splice(m.length-d,d));return w},u=function(t,e,i){e=e||"soft";var s,r,a,o,h,l,_,u,p,f,c,m={},d="cubic"===e?3:2,g="soft"===e,v=[];if(g&&i&&(t=[i].concat(t)),null==t||d+1>t.length)throw"invalid Bezier data";for(p in t[0])v.push(p);for(l=v.length;--l>-1;){for(p=v[l],m[p]=h=[],f=0,u=t.length,_=0;u>_;_++)s=null==i?t[_][p]:"string"==typeof(c=t[_][p])&&"="===c.charAt(1)?i[p]+Number(c.charAt(0)+c.substr(2)):Number(c),g&&_>1&&u-1>_&&(h[f++]=(s+h[f-2])/2),h[f++]=s;for(u=f-d+1,f=0,_=0;u>_;_+=d)s=h[_],r=h[_+1],a=h[_+2],o=2===d?0:h[_+3],h[f++]=c=3===d?new n(s,r,a,o):new n(s,(2*r+s)/3,(2*r+a)/3,a);h.length=f}return m},p=function(t,e,i){for(var s,r,n,a,o,h,l,_,u,p,f,c=1/i,m=t.length;--m>-1;)for(p=t[m],n=p.a,a=p.d-n,o=p.c-n,h=p.b-n,s=r=0,_=1;i>=_;_++)l=c*_,u=1-l,s=r-(r=(l*l*a+3*u*(l*o+u*h))*l),f=m*i+_-1,e[f]=(e[f]||0)+s*s},f=function(t,e){e=e>>0||6;var i,s,r,n,a=[],o=[],h=0,l=0,_=e-1,u=[],f=[];for(i in t)p(t[i],a,e);for(r=a.length,s=0;r>s;s++)h+=Math.sqrt(a[s]),n=s%e,f[n]=h,n===_&&(l+=h,n=s/e>>0,u[n]=f,o[n]=l,h=0,f=[]);return{length:l,lengths:o,segments:u}},c=window._gsDefine.plugin({propName:"bezier",priority:-1,API:2,global:!0,init:function(t,e,i){this._target=t,e instanceof Array&&(e={values:e}),this._func={},this._round={},this._props=[],this._timeRes=null==e.timeResolution?6:parseInt(e.timeResolution,10);var s,r,n,a,o,h=e.values||[],l={},p=h[0],c=e.autoRotate||i.vars.orientToBezier;this._autoRotate=c?c instanceof Array?c:[["x","y","rotation",c===!0?0:Number(c)||0]]:null;for(s in p)this._props.push(s);for(n=this._props.length;--n>-1;)s=this._props[n],this._overwriteProps.push(s),r=this._func[s]="function"==typeof t[s],l[s]=r?t[s.indexOf("set")||"function"!=typeof t["get"+s.substr(3)]?s:"get"+s.substr(3)]():parseFloat(t[s]),o||l[s]!==h[0][s]&&(o=l);if(this._beziers="cubic"!==e.type&&"quadratic"!==e.type&&"soft"!==e.type?_(h,isNaN(e.curviness)?1:e.curviness,!1,"thruBasic"===e.type,e.correlate,o):u(h,e.type,l),this._segCount=this._beziers[s].length,this._timeRes){var m=f(this._beziers,this._timeRes);this._length=m.length,this._lengths=m.lengths,this._segments=m.segments,this._l1=this._li=this._s1=this._si=0,this._l2=this._lengths[0],this._curSeg=this._segments[0],this._s2=this._curSeg[0],this._prec=1/this._curSeg.length}if(c=this._autoRotate)for(c[0]instanceof Array||(this._autoRotate=c=[c]),n=c.length;--n>-1;)for(a=0;3>a;a++)s=c[n][a],this._func[s]="function"==typeof t[s]?t[s.indexOf("set")||"function"!=typeof t["get"+s.substr(3)]?s:"get"+s.substr(3)]:!1;return!0},set:function(e){var i,s,r,n,a,o,h,l,_,u,p=this._segCount,f=this._func,c=this._target;if(this._timeRes){if(_=this._lengths,u=this._curSeg,e*=this._length,r=this._li,e>this._l2&&p-1>r){for(l=p-1;l>r&&e>=(this._l2=_[++r]););this._l1=_[r-1],this._li=r,this._curSeg=u=this._segments[r],this._s2=u[this._s1=this._si=0]}else if(this._l1>e&&r>0){for(;r>0&&(this._l1=_[--r])>=e;);0===r&&this._l1>e?this._l1=0:r++,this._l2=_[r],this._li=r,this._curSeg=u=this._segments[r],this._s1=u[(this._si=u.length-1)-1]||0,this._s2=u[this._si]}if(i=r,e-=this._l1,r=this._si,e>this._s2&&u.length-1>r){for(l=u.length-1;l>r&&e>=(this._s2=u[++r]););this._s1=u[r-1],this._si=r}else if(this._s1>e&&r>0){for(;r>0&&(this._s1=u[--r])>=e;);0===r&&this._s1>e?this._s1=0:r++,this._s2=u[r],this._si=r}o=(r+(e-this._s1)/(this._s2-this._s1))*this._prec}else i=0>e?0:e>=1?p-1:p*e>>0,o=(e-i*(1/p))*p;for(s=1-o,r=this._props.length;--r>-1;)n=this._props[r],a=this._beziers[n][i],h=(o*o*a.da+3*s*(o*a.ca+s*a.ba))*o+a.a,this._round[n]&&(h=h+(h>0?.5:-.5)>>0),f[n]?c[n](h):c[n]=h;if(this._autoRotate){var m,d,g,v,y,T,w,x=this._autoRotate;for(r=x.length;--r>-1;)n=x[r][2],T=x[r][3]||0,w=x[r][4]===!0?1:t,a=this._beziers[x[r][0]],m=this._beziers[x[r][1]],a&&m&&(a=a[i],m=m[i],d=a.a+(a.b-a.a)*o,v=a.b+(a.c-a.b)*o,d+=(v-d)*o,v+=(a.c+(a.d-a.c)*o-v)*o,g=m.a+(m.b-m.a)*o,y=m.b+(m.c-m.b)*o,g+=(y-g)*o,y+=(m.c+(m.d-m.c)*o-y)*o,h=Math.atan2(y-g,v-d)*w+T,f[n]?c[n](h):c[n]=h)}}}),m=c.prototype;c.bezierThrough=_,c.cubicToQuadratic=o,c._autoCSS=!0,c.quadraticToCubic=function(t,e,i){return new n(t,(2*e+t)/3,(2*e+i)/3,i)},c._cssRegister=function(){var t=window._gsDefine.globals.CSSPlugin;if(t){var e=t._internals,i=e._parseToProxy,s=e._setPluginRatio,r=e.CSSPropTween;e._registerComplexSpecialProp("bezier",{parser:function(t,e,n,a,o,h){e instanceof Array&&(e={values:e}),h=new c;var l,_,u,p=e.values,f=p.length-1,m=[],d={};if(0>f)return o;for(l=0;f>=l;l++)u=i(t,p[l],a,o,h,f!==l),m[l]=u.end;for(_ in e)d[_]=e[_];return d.values=m,o=new r(t,"bezier",0,0,u.pt,2),o.data=u,o.plugin=h,o.setRatio=s,0===d.autoRotate&&(d.autoRotate=!0),!d.autoRotate||d.autoRotate instanceof Array||(l=d.autoRotate===!0?0:Number(d.autoRotate),d.autoRotate=null!=u.end.left?[["left","top","rotation",l,!1]]:null!=u.end.x?[["x","y","rotation",l,!1]]:!1),d.autoRotate&&(a._transform||a._enableTransforms(!1),u.autoRotate=a._target._gsTransform),h._onInitTween(u.proxy,d,a._tween),o}})}},m._roundProps=function(t,e){for(var i=this._overwriteProps,s=i.length;--s>-1;)(t[i[s]]||t.bezier||t.bezierThrough)&&(this._round[i[s]]=e)},m._kill=function(t){var e,i,s=this._props;
52509for(e in this._beziers)if(e in t)for(delete this._beziers[e],delete this._func[e],i=s.length;--i>-1;)s[i]===e&&s.splice(i,1);return this._super._kill.call(this,t)}}(),window._gsDefine("plugins.CSSPlugin",["plugins.TweenPlugin","TweenLite"],function(t,e){var i,s,r,n,a=function(){t.call(this,"css"),this._overwriteProps.length=0,this.setRatio=a.prototype.setRatio},o={},h=a.prototype=new t("css");h.constructor=a,a.version="1.11.2",a.API=2,a.defaultTransformPerspective=0,h="px",a.suffixMap={top:h,right:h,bottom:h,left:h,width:h,height:h,fontSize:h,padding:h,margin:h,perspective:h};var l,_,u,p,f,c,m=/(?:\d|\-\d|\.\d|\-\.\d)+/g,d=/(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,g=/(?
52509:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi,v=/[^\d\-\.]/g,y=/(?:\d|\-|\+|=|#|\.)*/g,T=/opacity *= *([^)]*)/,w=/opacity:([^;]*)/,x=/alpha\(opacity *=.+?\)/i,b=/^(rgb|hsl)/,P=/([A-Z])/g,S=/-([a-z])/gi,k=/(^(?:url\(\"|url\())|(?:(\"\))$|\)$)/gi,R=function(t,e){return e.toUpperCase()},A=/(?:Left|Right|Width)/i,C=/(M11|M12|M21|M22)=[\d\-\.e]+/gi,O=/progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,D=/,(?=[^\)]*(?:\(|$))/gi,M=Math.PI/180,I=180/Math.PI,E={},F=document,N=F.createElement("div"),L=F.createElement("img"),X=a._internals={_specialProps:o},z=navigator.userAgent,U=function(){var t,e=z.indexOf("Android"),i=F.createElement("div");return u=-1!==z.indexOf("Safari")&&-1===z.indexOf("Chrome")&&(-1===e||Number(z.substr(e+8,1))>3),f=u&&6>Number(z.substr(z.indexOf("Version/")+8,1)),p=-1!==z.indexOf("Firefox"),/MSIE ([0-9]{1,}[\.0-9]{0,})/.exec(z)&&(c=parseFloat(RegExp.$1)),i.innerHTML="<a style='top:1px;opacity:.55;'>a</a>",t=i.getElementsByTagName("a")[0],t?/^0.55/.test(t.style.opacity):!1}(),Y=function(t){return T.test("string"==typeof t?t:(t.currentStyle?t.currentStyle.filter:t.style.filter)||"")?parseFloat(RegExp.$1)/100:1},j=function(t){window.console&&console.log(t)},B="",q="",V=function(t,e){e=e||N;var i,s,r=e.style;if(void 0!==r[t])return t;for(t=t.charAt(0).toUpperCase()+t.substr(1),i=["O","Moz","ms","Ms","Webkit"],s=5;--s>-1&&void 0===r[i[s]+t];);return s>=0?(q=3===s?"ms":i[s],B="-"+q.toLowerCase()+"-",q+t):null},Z=F.defaultView?F.defaultView.getComputedStyle:function(){},G=a.getStyle=function(t,e,i,s,r){var n;return U||"opacity"!==e?(!s&&t.style[e]?n=t.style[e]:(i=i||Z(t,null))?(t=i.getPropertyValue(e.replace(P,"-$1").toLowerCase()),n=t||i.length?t:i[e]):t.currentStyle&&(n=t.currentStyle[e]),null==r||n&&"none"!==n&&"auto"!==n&&"auto auto"!==n?n:r):Y(t)},$=function(t,e,i,s,r){if("px"===s||!s)return i;if("auto"===s||!i)return 0;var n,a=A.test(e),o=t,h=N.style,l=0>i;return l&&(i=-i),"%"===s&&-1!==e.indexOf("border")?n=i/100*(a?t.clientWidth:t.clientHeight):(h.cssText="border:0 solid red;position:"+G(t,"position")+";line-height:0;","%"!==s&&o.appendChild?h[a?"borderLeftWidth":"borderTopWidth"]=i+s:(o=t.parentNode||F.body,h[a?"width":"height"]=i+s),o.appendChild(N),n=parseFloat(N[a?"offsetWidth":"offsetHeight"]),o.removeChild(N),0!==n||r||(n=$(t,e,i,s,!0))),l?-n:n},Q=function(t,e,i){if("absolute"!==G(t,"position",i))return 0;var s="left"===e?"Left":"Top",r=G(t,"margin"+s,i);return t["offset"+s]-($(t,e,parseFloat(r),r.replace(y,""))||0)},W=function(t,e){var i,s,r={};if(e=e||Z(t,null))if(i=e.length)for(;--i>-1;)r[e[i].replace(S,R)]=e.getPropertyValue(e[i]);else for(i in e)r[i]=e[i];else if(e=t.currentStyle||t.style)for(i in e)"string"==typeof i&&void 0!==r[i]&&(r[i.replace(S,R)]=e[i]);return U||(r.opacity=Y(t)),s=be(t,e,!1),r.rotation=s.rotation,r.skewX=s.skewX,r.scaleX=s.scaleX,r.scaleY=s.scaleY,r.x=s.x,r.y=s.y,xe&&(r.z=s.z,r.rotationX=s.rotationX,r.rotationY=s.rotationY,r.scaleZ=s.scaleZ),r.filters&&delete r.filters,r},H=function(t,e,i,s,r){var n,a,o,h={},l=t.style;for(a in i)"cssText"!==a&&"length"!==a&&isNaN(a)&&(e[a]!==(n=i[a])||r&&r[a])&&-1===a.indexOf("Origin")&&("number"==typeof n||"string"==typeof n)&&(h[a]="auto"!==n||"left"!==a&&"top"!==a?""!==n&&"auto"!==n&&"none"!==n||"string"!=typeof e[a]||""===e[a].replace(v,"")?n:0:Q(t,a),void 0!==l[a]&&(o=new ue(l,a,l[a],o)));if(s)for(a in s)"className"!==a&&(h[a]=s[a]);return{difs:h,firstMPT:o}},K={width:["Left","Right"],height:["Top","Bottom"]},J=["marginLeft","marginRight","marginTop","marginBottom"],te=function(t,e,i){var s=parseFloat("width"===e?t.offsetWidth:t.offsetHeight),r=K[e],n=r.length;for(i=i||Z(t,null);--n>-1;)s-=parseFloat(G(t,"padding"+r[n],i,!0))||0,s-=parseFloat(G(t,"border"+r[n]+"Width",i,!0))||0;return s},ee=function(t,e){(null==t||""===t||"auto"===t||"auto auto"===t)&&(t="0 0");var i=t.split(" "),s=-1!==t.indexOf("left")?"0%":-1!==t.indexOf("right")?"100%":i[0],r=-1!==t.indexOf("top")?"0%":-1!==t.indexOf("bottom")?"100%":i[1];return null==r?r="0":"center"===r&&(r="50%"),("center"===s||isNaN(parseFloat(s))&&-1===(s+"").indexOf("="))&&(s="50%"),e&&(e.oxp=-1!==s.indexOf("%"),e.oyp=-1!==r.indexOf("%"),e.oxr="="===s.charAt(1),e.oyr="="===r.charAt(1),e.ox=parseFloat(s.replace(v,"")),e.oy=parseFloat(r.replace(v,""))),s+" "+r+(i.length>2?" "+i[2]:"")},ie=function(t,e){return"string"==typeof t&&"="===t.charAt(1)?parseInt(t.charAt(0)+"1",10)*parseFloat(t.substr(2)):parseFloat(t)-parseFloat(e)},se=function(t,e){return null==t?e:"string"==typeof t&&"="===t.charAt(1)?parseInt(t.charAt(0)+"1",10)*Number(t.substr(2))+e:parseFloat(t)}
52509,re=function(t,e,i,s){var r,n,a,o,h=1e-6;return null==t?o=e:"number"==typeof t?o=t:(r=360,n=t.split("_"),a=Number(n[0].replace(v,""))*(-1===t.indexOf("rad")?1:I)-("="===t.charAt(1)?0:e),n.length&&(s&&(s[i]=e+a),-1!==t.indexOf("short")&&(a%=r,a!==a%(r/2)&&(a=0>a?a+r:a-r)),-1!==t.indexOf("_cw")&&0>a?a=(a+9999999999*r)%r-(0|a/r)*r:-1!==t.indexOf("ccw")&&a>0&&(a=(a-9999999999*r)%r-(0|a/r)*r)),o=e+a),h>o&&o>-h&&(o=0),o},ne={aqua:[0,255,255],lime:[0,255,0],silver:[192,192,192],black:[0,0,0],maroon:[128,0,0],teal:[0,128,128],blue:[0,0,255],navy:[0,0,128],white:[255,255,255],fuchsia:[255,0,255],olive:[128,128,0],yellow:[255,255,0],orange:[255,165,0],gray:[128,128,128],purple:[128,0,128],green:[0,128,0],red:[255,0,0],pink:[255,192,203],cyan:[0,255,255],transparent:[255,255,255,0]},ae=function(t,e,i){return t=0>t?t+1:t>1?t-1:t,0|255*(1>6*t?e+6*(i-e)*t:.5>t?i:2>3*t?e+6*(i-e)*(2/3-t):e)+.5},oe=function(t){var e,i,s,r,n,a;return t&&""!==t?"number"==typeof t?[t>>16,255&t>>8,255&t]:(","===t.charAt(t.length-1)&&(t=t.substr(0,t.length-1)),ne[t]?ne[t]:"#"===t.charAt(0)?(4===t.length&&(e=t.charAt(1),i=t.charAt(2),s=t.charAt(3),t="#"+e+e+i+i+s+s),t=parseInt(t.substr(1),16),[t>>16,255&t>>8,255&t]):"hsl"===t.substr(0,3)?(t=t.match(m),r=Number(t[0])%360/360,n=Number(t[1])/100,a=Number(t[2])/100,i=.5>=a?a*(n+1):a+n-a*n,e=2*a-i,t.length>3&&(t[3]=Number(t[3])),t[0]=ae(r+1/3,e,i),t[1]=ae(r,e,i),t[2]=ae(r-1/3,e,i),t):(t=t.match(m)||ne.transparent,t[0]=Number(t[0]),t[1]=Number(t[1]),t[2]=Number(t[2]),t.length>3&&(t[3]=Number(t[3])),t)):ne.black},he="(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#.+?\\b";for(h in ne)he+="|"+h+"\\b";he=RegExp(he+")","gi");var le=function(t,e,i,s){if(null==t)return function(t){return t};var r,n=e?(t.match(he)||[""])[0]:"",a=t.split(n).join("").match(g)||[],o=t.substr(0,t.indexOf(a[0])),h=")"===t.charAt(t.length-1)?")":"",l=-1!==t.indexOf(" ")?" ":",",_=a.length,u=_>0?a[0].replace(m,""):"";return _?r=e?function(t){var e,p,f,c;if("number"==typeof t)t+=u;else if(s&&D.test(t)){for(c=t.replace(D,"|").split("|"),f=0;c.length>f;f++)c[f]=r(c[f]);return c.join(",")}if(e=(t.match(he)||[n])[0],p=t.split(e).join("").match(g)||[],f=p.length,_>f--)for(;_>++f;)p[f]=i?p[0|(f-1)/2]:a[f];return o+p.join(l)+l+e+h+(-1!==t.indexOf("inset")?" inset":"")}:function(t){var e,n,p;if("number"==typeof t)t+=u;else if(s&&D.test(t)){for(n=t.replace(D,"|").split("|"),p=0;n.length>p;p++)n[p]=r(n[p]);return n.join(",")}if(e=t.match(g)||[],p=e.length,_>p--)for(;_>++p;)e[p]=i?e[0|(p-1)/2]:a[p];return o+e.join(l)+h}:function(t){return t}},_e=function(t){return t=t.split(","),function(e,i,s,r,n,a,o){var h,l=(i+"").split(" ");for(o={},h=0;4>h;h++)o[t[h]]=l[h]=l[h]||l[(h-1)/2>>0];return r.parse(e,o,n,a)}},ue=(X._setPluginRatio=function(t){this.plugin.setRatio(t);for(var e,i,s,r,n=this.data,a=n.proxy,o=n.firstMPT,h=1e-6;o;)e=a[o.v],o.r?e=e>0?0|e+.5:0|e-.5:h>e&&e>-h&&(e=0),o.t[o.p]=e,o=o._next;if(n.autoRotate&&(n.autoRotate.rotation=a.rotation),1===t)for(o=n.firstMPT;o;){if(i=o.t,i.type){if(1===i.type){for(r=i.xs0+i.s+i.xs1,s=1;i.l>s;s++)r+=i["xn"+s]+i["xs"+(s+1)];i.e=r}}else i.e=i.s+i.xs0;o=o._next}},function(t,e,i,s,r){this.t=t,this.p=e,this.v=i,this.r=r,s&&(s._prev=this,this._next=s)}),pe=(X._parseToProxy=function(t,e,i,s,r,n){var a,o,h,l,_,u=s,p={},f={},c=i._transform,m=E;for(i._transform=null,E=e,s=_=i.parse(t,e,s,r),E=m,n&&(i._transform=c,u&&(u._prev=null,u._prev&&(u._prev._next=null)));s&&s!==u;){if(1>=s.type&&(o=s.p,f[o]=s.s+s.c,p[o]=s.s,n||(l=new ue(s,"s",o,l,s.r),s.c=0),1===s.type))for(a=s.l;--a>0;)h="xn"+a,o=s.p+"_"+h,f[o]=s.data[h],p[o]=s[h],n||(l=new ue(s,h,o,l,s.rxp[h]));s=s._next}return{proxy:p,end:f,firstMPT:l,pt:_}},X.CSSPropTween=function(t,e,s,r,a,o,h,l,_,u,p){this.t=t,this.p=e,this.s=s,this.c=r,this.n=h||e,t instanceof pe||n.push(this.n),this.r=l,this.type=o||0,_&&(this.pr=_,i=!0),this.b=void 0===u?s:u,this.e=void 0===p?s+r:p,a&&(this._next=a,a._prev=this)}),fe=a.parseComplex=function(t,e,i,s,r,n,a,o,h,_){i=i||n||"",a=new pe(t,e,0,0,a,_?2:1,null,!1,o,i,s),s+="";var u,p,f,c,g,v,y,T,w,x,P,S,k=i.split(", ").join(",").split(" "),R=s.split(", ").join(",").split(" "),A=k.length,C=l!==!1;for((-1!==s.indexOf(",")||-1!==i.indexOf(","))&&(k=k.join(" ").replace(D,", ").split(" "),R=R.join(" ").replace(D,", ").split(" "),A=k.length),A!==R.length&&(k=(n||"").split(" "),A=k.length),a.plugin=h,a.setRatio=_,u=0;A>u;u++)if(c=k[u],g=R[u],T=parseFloat(c),T||0===T)a.appendXtra("",T,ie(g,T),g.replace(d,""),C&&-1!==g.indexOf("px"),!0);else if(r&&("#"===c.charAt(0)||ne[c]||b.test(c)))S=","===g.charAt(g.length-1)?"),":")",c=oe(c),g=oe(g),w=c.length+g.length>
525096,w&&!U&&0===g[3]?(a["xs"+a.l]+=a.l?" transparent":"transparent",a.e=a.e.split(R[u]).join("transparent")):(U||(w=!1),a.appendXtra(w?"rgba(":"rgb(",c[0],g[0]-c[0],",",!0,!0).appendXtra("",c[1],g[1]-c[1],",",!0).appendXtra("",c[2],g[2]-c[2],w?",":S,!0),w&&(c=4>c.length?1:c[3],a.appendXtra("",c,(4>g.length?1:g[3])-c,S,!1)));else if(v=c.match(m)){if(y=g.match(d),!y||y.length!==v.length)return a;for(f=0,p=0;v.length>p;p++)P=v[p],x=c.indexOf(P,f),a.appendXtra(c.substr(f,x-f),Number(P),ie(y[p],P),"",C&&"px"===c.substr(x+P.length,2),0===p),f=x+P.length;a["xs"+a.l]+=c.substr(f)}else a["xs"+a.l]+=a.l?" "+c:c;if(-1!==s.indexOf("=")&&a.data){for(S=a.xs0+a.data.s,u=1;a.l>u;u++)S+=a["xs"+u]+a.data["xn"+u];a.e=S+a["xs"+u]}return a.l||(a.type=-1,a.xs0=a.e),a.xfirst||a},ce=9;for(h=pe.prototype,h.l=h.pr=0;--ce>0;)h["xn"+ce]=0,h["xs"+ce]="";h.xs0="",h._next=h._prev=h.xfirst=h.data=h.plugin=h.setRatio=h.rxp=null,h.appendXtra=function(t,e,i,s,r,n){var a=this,o=a.l;return a["xs"+o]+=n&&o?" "+t:t||"",i||0===o||a.plugin?(a.l++,a.type=a.setRatio?2:1,a["xs"+a.l]=s||"",o>0?(a.data["xn"+o]=e+i,a.rxp["xn"+o]=r,a["xn"+o]=e,a.plugin||(a.xfirst=new pe(a,"xn"+o,e,i,a.xfirst||a,0,a.n,r,a.pr),a.xfirst.xs0=0),a):(a.data={s:e+i},a.rxp={},a.s=e,a.c=i,a.r=r,a)):(a["xs"+o]+=e+(s||""),a)};var me=function(t,e){e=e||{},this.p=e.prefix?V(t)||t:t,o[t]=o[this.p]=this,this.format=e.formatter||le(e.defaultValue,e.color,e.collapsible,e.multi),e.parser&&(this.parse=e.parser),this.clrs=e.color,this.multi=e.multi,this.keyword=e.keyword,this.dflt=e.defaultValue,this.pr=e.priority||0},de=X._registerComplexSpecialProp=function(t,e,i){"object"!=typeof e&&(e={parser:i});var s,r,n=t.split(","),a=e.defaultValue;for(i=i||[a],s=0;n.length>s;s++)e.prefix=0===s&&e.prefix,e.defaultValue=i[s]||a,r=new me(n[s],e)},ge=function(t){if(!o[t]){var e=t.charAt(0).toUpperCase()+t.substr(1)+"Plugin";de(t,{parser:function(t,i,s,r,n,a,h){var l=(window.GreenSockGlobals||window).com.greensock.plugins[e];return l?(l._cssRegister(),o[s].parse(t,i,s,r,n,a,h)):(j("Error: "+e+" js file not loaded."),n)}})}};h=me.prototype,h.parseComplex=function(t,e,i,s,r,n){var a,o,h,l,_,u,p=this.keyword;if(this.multi&&(D.test(i)||D.test(e)?(o=e.replace(D,"|").split("|"),h=i.replace(D,"|").split("|")):p&&(o=[e],h=[i])),h){for(l=h.length>o.length?h.length:o.length,a=0;l>a;a++)e=o[a]=o[a]||this.dflt,i=h[a]=h[a]||this.dflt,p&&(_=e.indexOf(p),u=i.indexOf(p),_!==u&&(i=-1===u?h:o,i[a]+=" "+p));e=o.join(", "),i=h.join(", ")}return fe(t,this.p,e,i,this.clrs,this.dflt,s,this.pr,r,n)},h.parse=function(t,e,i,s,n,a){return this.parseComplex(t.style,this.format(G(t,this.p,r,!1,this.dflt)),this.format(e),n,a)},a.registerSpecialProp=function(t,e,i){de(t,{parser:function(t,s,r,n,a,o){var h=new pe(t,r,0,0,a,2,r,!1,i);return h.plugin=o,h.setRatio=e(t,s,n._tween,r),h},priority:i})};var ve="scaleX,scaleY,scaleZ,x,y,z,skewX,rotation,rotationX,rotationY,perspective".split(","),ye=V("transform"),Te=B+"transform",we=V("transformOrigin"),xe=null!==V("perspective"),be=function(t,e,i,s){if(t._gsTransform&&i&&!s)return t._gsTransform;var r,n,o,h,l,_,u,p,f,c,m,d,g,v=i?t._gsTransform||{skewY:0}:{skewY:0},y=0>v.scaleX,T=2e-5,w=1e5,x=179.99,b=x*M,P=xe?parseFloat(G(t,we,e,!1,"0 0 0").split(" ")[2])||v.zOrigin||0:0;for(ye?r=G(t,Te,e,!0):t.currentStyle&&(r=t.currentStyle.filter.match(C),r=r&&4===r.length?[r[0].substr(4),Number(r[2].substr(4)),Number(r[1].substr(4)),r[3].substr(4),v.x||0,v.y||0].join(","):""),n=(r||"").match(/(?:\-|\b)[\d\-\.e]+\b/gi)||[],o=n.length;--o>-1;)h=Number(n[o]),n[o]=(l=h-(h|=0))?(0|l*w+(0>l?-.5:.5))/w+h:h;if(16===n.length){var S=n[8],k=n[9],R=n[10],A=n[12],O=n[13],D=n[14];if(v.zOrigin&&(D=-v.zOrigin,A=S*D-n[12],O=k*D-n[13],D=R*D+v.zOrigin-n[14]),!i||s||null==v.rotationX){var E,F,N,L,X,z,U,Y=n[0],j=n[1],B=n[2],q=n[3],V=n[4],Z=n[5],$=n[6],Q=n[7],W=n[11],H=Math.atan2($,R),K=-b>H||H>b;v.rotationX=H*I,H&&(L=Math.cos(-H),X=Math.sin(-H),E=V*L+S*X,F=Z*L+k*X,N=$*L+R*X,S=V*-X+S*L,k=Z*-X+k*L,R=$*-X+R*L,W=Q*-X+W*L,V=E,Z=F,$=N),H=Math.atan2(S,Y),v.rotationY=H*I,H&&(z=-b>H||H>b,L=Math.cos(-H),X=Math.sin(-H),E=Y*L-S*X,F=j*L-k*X,N=B*L-R*X,k=j*X+k*L,R=B
52509*X+R*L,W=q*X+W*L,Y=E,j=F,B=N),H=Math.atan2(j,Z),v.rotation=H*I,H&&(U=-b>H||H>b,L=Math.cos(-H),X=Math.sin(-H),Y=Y*L+V*X,F=j*L+Z*X,Z=j*-X+Z*L,$=B*-X+$*L,j=F),U&&K?v.rotation=v.rotationX=0:U&&z?v.rotation=v.rotationY=0:z&&K&&(v.rotationY=v.rotationX=0),v.scaleX=(0|Math.sqrt(Y*Y+j*j)*w+.5)/w,v.scaleY=(0|Math.sqrt(Z*Z+k*k)*w+.5)/w,v.scaleZ=(0|Math.sqrt($*$+R*R)*w+.5)/w,v.skewX=0,v.perspective=W?1/(0>W?-W:W):0,v.x=A,v.y=O,v.z=D}}else if(!(xe&&!s&&n.length&&v.x===n[4]&&v.y===n[5]&&(v.rotationX||v.rotationY)||void 0!==v.x&&"none"===G(t,"display",e))){var J=n.length>=6,te=J?n[0]:1,ee=n[1]||0,ie=n[2]||0,se=J?n[3]:1;v.x=n[4]||0,v.y=n[5]||0,_=Math.sqrt(te*te+ee*ee),u=Math.sqrt(se*se+ie*ie),p=te||ee?Math.atan2(ee,te)*I:v.rotation||0,f=ie||se?Math.atan2(ie,se)*I+p:v.skewX||0,c=_-Math.abs(v.scaleX||0),m=u-Math.abs(v.scaleY||0),Math.abs(f)>90&&270>Math.abs(f)&&(y?(_*=-1,f+=0>=p?180:-180,p+=0>=p?180:-180):(u*=-1,f+=0>=f?180:-180)),d=(p-v.rotation)%180,g=(f-v.skewX)%180,(void 0===v.skewX||c>T||-T>c||m>T||-T>m||d>-x&&x>d&&false|d*w||g>-x&&x>g&&false|g*w)&&(v.scaleX=_,v.scaleY=u,v.rotation=p,v.skewX=f),xe&&(v.rotationX=v.rotationY=v.z=0,v.perspective=parseFloat(a.defaultTransformPerspective)||0,v.scaleZ=1)}v.zOrigin=P;for(o in v)T>v[o]&&v[o]>-T&&(v[o]=0);return i&&(t._gsTransform=v),v},Pe=function(t){var e,i,s=this.data,r=-s.rotation*M,n=r+s.skewX*M,a=1e5,o=(0|Math.cos(r)*s.scaleX*a)/a,h=(0|Math.sin(r)*s.scaleX*a)/a,l=(0|Math.sin(n)*-s.scaleY*a)/a,_=(0|Math.cos(n)*s.scaleY*a)/a,u=this.t.style,p=this.t.currentStyle;if(p){i=h,h=-l,l=-i,e=p.filter,u.filter="";var f,m,d=this.t.offsetWidth,g=this.t.offsetHeight,v="absolute"!==p.position,w="progid:DXImageTransform.Microsoft.Matrix(M11="+o+", M12="+h+", M21="+l+", M22="+_,x=s.x,b=s.y;if(null!=s.ox&&(f=(s.oxp?.01*d*s.ox:s.ox)-d/2,m=(s.oyp?.01*g*s.oy:s.oy)-g/2,x+=f-(f*o+m*h),b+=m-(f*l+m*_)),v?(f=d/2,m=g/2,w+=", Dx="+(f-(f*o+m*h)+x)+", Dy="+(m-(f*l+m*_)+b)+")"):w+=", sizingMethod='auto expand')",u.filter=-1!==e.indexOf("DXImageTransform.Microsoft.Matrix(")?e.replace(O,w):w+" "+e,(0===t||1===t)&&1===o&&0===h&&0===l&&1===_&&(v&&-1===w.indexOf("Dx=0, Dy=0")||T.test(e)&&100!==parseFloat(RegExp.$1)||-1===e.indexOf("gradient("&&e.indexOf("Alpha"))&&u.removeAttribute("filter")),!v){var P,S,k,R=8>c?1:-1;for(f=s.ieOffsetX||0,m=s.ieOffsetY||0,s.ieOffsetX=Math.round((d-((0>o?-o:o)*d+(0>h?-h:h)*g))/2+x),s.ieOffsetY=Math.round((g-((0>_?-_:_)*g+(0>l?-l:l)*d))/2+b),ce=0;4>ce;ce++)S=J[ce],P=p[S],i=-1!==P.indexOf("px")?parseFloat(P):$(this.t,S,parseFloat(P),P.replace(y,""))||0,k=i!==s[S]?2>ce?-s.ieOffsetX:-s.ieOffsetY:2>ce?f-s.ieOffsetX:m-s.ieOffsetY,u[S]=(s[S]=Math.round(i-k*(0===ce||2===ce?1:R)))+"px"}}},Se=function(){var t,e,i,s,r,n,a,o,h,l,_,u,f,c,m,d,g,v,y,T,w,x,b,P=this.data,S=this.t.style,k=P.rotation*M,R=P.scaleX,A=P.scaleY,C=P.scaleZ,O=P.perspective;if(p){var D=1e-4;D>R&&R>-D&&(R=C=2e-5),D>A&&A>-D&&(A=C=2e-5),!O||P.z||P.rotationX||P.rotationY||(O=0)}if(k||P.skewX)v=Math.cos(k),y=Math.sin(k),t=v,r=y,P.skewX&&(k-=P.skewX*M,v=Math.cos(k),y=Math.sin(k)),e=-y,n=v;else{if(!(P.rotationY||P.rotationX||1!==C||O))return S[ye]="translate3d("+P.x+"px,"+P.y+"px,"+P.z+"px)"+(1!==R||1!==A?" scale("+R+","+A+")":""),void 0;t=n=1,e=r=0}_=1,i=s=a=o=h=l=u=f=c=0,m=O?-1/O:0,d=P.zOrigin,g=1e5,k=P.rotationY*M,k&&(v=Math.cos(k),y=Math.sin(k),h=_*-y,f=m*-y,i=t*y,a=r*y,_*=v,m*=v,t*=v,r*=v),k=P.rotationX*M,k&&(v=Math.cos(k),y=Math.sin(k),T=e*v+i*y,w=n*v+a*y,x=l*v+_*y,b=c*v+m*y,i=e*-y+i*v,a=n*-y+a*v,_=l*-y+_*v,m=c*-y+m*v,e=T,n=w,l=x,c=b),1!==C&&(i*=C,a*=C,_*=C,m*=C),1!==A&&(e*=A,n*=A,l*=A,c*=A),1!==R&&(t*=R,r*=R,h*=R,f*=R),d&&(u-=d,s=i*u,o=a*u,u=_*u+d),s=(T=(s+=P.x)-(s|=0))?(0|T*g+(0>T?-.5:.5))/g+s:s,o=(T=(o+=P.y)-(o|=0))?(0|T*g+(0>T?-.5:.5))/g+o:o,u=(T=(u+=P.z)-(u|=0))?(0|T*g+(0>T?-.5:.5))/g+u:u,S[ye]="matrix3d("+[(0|t*g)/g,(0|r*g)/g,(0|h*g)/g,(0|f*g)/g,(0|e*g)/g,(0|n*g)/g,(0|l*g)/g,(0|c*g)/g,(0|i*g)/g,(0|a*g)/g,(0|_*g)/g,(0|m*g)/g,s,o,u,O?1+-u/O:1].join(",")+")"},ke=function(){var t,e,i,s,r,n,a,o,h,l=this.data,_=this.t,u=_.style;p&&(t=u.top?"top":u.bottom?"bottom":parseFloat(G(_,"top",null,!1))?"bottom":"top",e=G(_,t,null,!1),i=parseFloat(e)||0,s=e.substr((i+"").length)||"px",l._ffFix=!l._ffFix,u[t]=(l._ffFix?i+.05:i-.05)+s),l.rotation||l.skewX?(r=l.rotation*M,n=r-l.skewX*M,a=1e5,o=l.scaleX*a,h=l.scaleY*a,u[ye]="matrix("+(0|Math.cos(r)*o)
52509/a+","+(0|Math.sin(r)*o)/a+","+(0|Math.sin(n)*-h)/a+","+(0|Math.cos(n)*h)/a+","+l.x+","+l.y+")"):u[ye]="matrix("+l.scaleX+",0,0,"+l.scaleY+","+l.x+","+l.y+")"};de("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,transformPerspective,directionalRotation,parseTransform,force3D",{parser:function(t,e,i,s,n,a,o){if(s._transform)return n;var h,l,_,u,p,f,c,m=s._transform=be(t,r,!0,o.parseTransform),d=t.style,g=1e-6,v=ve.length,y=o,T={};if("string"==typeof y.transform&&ye)_=d.cssText,d[ye]=y.transform,d.display="block",h=be(t,null,!1),d.cssText=_;else if("object"==typeof y){if(h={scaleX:se(null!=y.scaleX?y.scaleX:y.scale,m.scaleX),scaleY:se(null!=y.scaleY?y.scaleY:y.scale,m.scaleY),scaleZ:se(null!=y.scaleZ?y.scaleZ:y.scale,m.scaleZ),x:se(y.x,m.x),y:se(y.y,m.y),z:se(y.z,m.z),perspective:se(y.transformPerspective,m.perspective)},c=y.directionalRotation,null!=c)if("object"==typeof c)for(_ in c)y[_]=c[_];else y.rotation=c;h.rotation=re("rotation"in y?y.rotation:"shortRotation"in y?y.shortRotation+"_short":"rotationZ"in y?y.rotationZ:m.rotation,m.rotation,"rotation",T),xe&&(h.rotationX=re("rotationX"in y?y.rotationX:"shortRotationX"in y?y.shortRotationX+"_short":m.rotationX||0,m.rotationX,"rotationX",T),h.rotationY=re("rotationY"in y?y.rotationY:"shortRotationY"in y?y.shortRotationY+"_short":m.rotationY||0,m.rotationY,"rotationY",T)),h.skewX=null==y.skewX?m.skewX:re(y.skewX,m.skewX),h.skewY=null==y.skewY?m.skewY:re(y.skewY,m.skewY),(l=h.skewY-m.skewY)&&(h.skewX+=l,h.rotation+=l)}for(null!=y.force3D&&(m.force3D=y.force3D,f=!0),p=m.force3D||m.z||m.rotationX||m.rotationY||h.z||h.rotationX||h.rotationY||h.perspective,p||null==y.scale||(h.scaleZ=1);--v>-1;)i=ve[v],u=h[i]-m[i],(u>g||-g>u||null!=E[i])&&(f=!0,n=new pe(m,i,m[i],u,n),i in T&&(n.e=T[i]),n.xs0=0,n.plugin=a,s._overwriteProps.push(n.n));return u=y.transformOrigin,(u||xe&&p&&m.zOrigin)&&(ye?(f=!0,i=we,u=(u||G(t,i,r,!1,"50% 50%"))+"",n=new pe(d,i,0,0,n,-1,"transformOrigin"),n.b=d[i],n.plugin=a,xe?(_=m.zOrigin,u=u.split(" "),m.zOrigin=(u.length>2&&(0===_||"0px"!==u[2])?parseFloat(u[2]):_)||0,n.xs0=n.e=d[i]=u[0]+" "+(u[1]||"50%")+" 0px",n=new pe(m,"zOrigin",0,0,n,-1,n.n),n.b=_,n.xs0=n.e=m.zOrigin):n.xs0=n.e=d[i]=u):ee(u+"",m)),f&&(s._transformType=p||3===this._transformType?3:2),n},prefix:!0}),de("boxShadow",{defaultValue:"0px 0px 0px 0px #999",prefix:!0,color:!0,multi:!0,keyword:"inset"}),de("borderRadius",{defaultValue:"0px",parser:function(t,e,i,n,a){e=this.format(e);var o,h,l,_,u,p,f,c,m,d,g,v,y,T,w,x,b=["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],P=t.style;for(m=parseFloat(t.offsetWidth),d=parseFloat(t.offsetHeight),o=e.split(" "),h=0;b.length>h;h++)this.p.indexOf("border")&&(b[h]=V(b[h])),u=_=G(t,b[h],r,!1,"0px"),-1!==u.indexOf(" ")&&(_=u.split(" "),u=_[0],_=_[1]),p=l=o[h],f=parseFloat(u),v=u.substr((f+"").length),y="="===p.charAt(1),y?(c=parseInt(p.charAt(0)+"1",10),p=
vendor: 4,198 bytes, line 52509
52509p.substr(2),c*=parseFloat(p),g=p.substr((c+"").length-(0>c?1:0))||""):(c=parseFloat(p),g=p.substr((c+"").length)),""===g&&(g=s[i]||v),g!==v&&(T=$(t,"borderLeft",f,v),w=$(t,"borderTop",f,v),"%"===g?(u=100*(T/m)+"%",_=100*(w/d)+"%"):"em"===g?(x=$(t,"borderLeft",1,"em"),u=T/x+"em",_=w/x+"em"):(u=T+"px",_=w+"px"),y&&(p=parseFloat(u)+c+g,l=parseFloat(_)+c+g)),a=fe(P,b[h],u+" "+_,p+" "+l,!1,"0px",a);return a},prefix:!0,formatter:le("0px 0px 0px 0px",!1,!0)}),de("backgroundPosition",{defaultValue:"0 0",parser:function(t,e,i,s,n,a){var o,h,l,_,u,p,f="background-position",m=r||Z(t,null),d=this.format((m?c?m.getPropertyValue(f+"-x")+" "+m.getPropertyValue(f+"-y"):m.getPropertyValue(f):t.currentStyle.backgroundPositionX+" "+t.currentStyle.backgroundPositionY)||"0 0"),g=this.format(e);if(-1!==d.indexOf("%")!=(-1!==g.indexOf("%"))&&(p=G(t,"backgroundImage").replace(k,""),p&&"none"!==p)){for(o=d.split(" "),h=g.split(" "),L.setAttribute("src",p),l=2;--l>-1;)d=o[l],_=-1!==d.indexOf("%"),_!==(-1!==h[l].indexOf("%"))&&(u=0===l?t.offsetWidth-L.width:t.offsetHeight-L.height,o[l]=_?parseFloat(d)/100*u+"px":100*(parseFloat(d)/u)+"%");d=o.join(" ")}return this.parseComplex(t.style,d,g,n,a)},formatter:ee}),de("backgroundSize",{defaultValue:"0 0",formatter:ee}),de("perspective",{defaultValue:"0px",prefix:!0}),de("perspectiveOrigin",{defaultValue:"50% 50%",prefix:!0}),de("transformStyle",{prefix:!0}),de("backfaceVisibility",{prefix:!0}),de("userSelect",{prefix:!0}),de("margin",{parser:_e("marginTop,marginRight,marginBottom,marginLeft")}),de("padding",{parser:_e("paddingTop,paddingRight,paddingBottom,paddingLeft")}),de("clip",{defaultValue:"rect(0px,0px,0px,0px)",parser:function(t,e,i,s,n,a){var o,h,l;return 9>c?(h=t.currentStyle,l=8>c?" ":",",o="rect("+h.clipTop+l+h.clipRight+l+h.clipBottom+l+h.clipLeft+")",e=this.format(e).split(",").join(l)):(o=this.format(G(t,this.p,r,!1,this.dflt)),e=this.format(e)),this.parseComplex(t.style,o,e,n,a)}}),de("textShadow",{defaultValue:"0px 0px 0px #999",color:!0,multi:!0}),de("autoRound,strictUnits",{parser:function(t,e,i,s,r){return r}}),de("border",{defaultValue:"0px solid #000",parser:function(t,e,i,s,n,a){return this.parseComplex(t.style,this.format(G(t,"borderTopWidth",r,!1,"0px")+" "+G(t,"borderTopStyle",r,!1,"solid")+" "+G(t,"borderTopColor",r,!1,"#000")),this.format(e),n,a)},color:!0,formatter:function(t){var e=t.split(" ");return e[0]+" "+(e[1]||"solid")+" "+(t.match(he)||["#000"])[0]}}),de("float,cssFloat,styleFloat",{parser:function(t,e,i,s,r){var n=t.style,a="cssFloat"in n?"cssFloat":"styleFloat";return new pe(n,a,0,0,r,-1,i,!1,0,n[a],e)}});var Re=function(t){var e,i=this.t,s=i.filter||G(this.data,"filter"),r=0|this.s+this.c*t;100===r&&(-1===s.indexOf("atrix(")&&-1===s.indexOf("radient(")&&-1===s.indexOf("oader(")?(i.removeAttribute("filter"),e=!G(this.data,"filter")):(i.filter=s.replace(x,""),e=!0)),e||(this.xn1&&(i.filter=s=s||"alpha(opacity="+r+")"),-1===s.indexOf("opacity")?0===r&&this.xn1||(i.filter=s+" alpha(opacity="+r+")"):i.filter=s.replace(T,"opacity="+r))};de("opacity,alpha,autoAlpha",{defaultValue:"1",parser:function(t,e,i,s,n,a){var o=parseFloat(G(t,"opacity",r,!1,"1")),h=t.style,l="autoAlpha"===i;return"string"==typeof e&&"="===e.charAt(1)&&(e=("-"===e.charAt(0)?-1:1)*parseFloat(e.substr(2))+o),l&&1===o&&"hidden"===G(t,"visibility",r)&&0!==e&&(o=0),U?n=new pe(h,"opacity",o,e-o,n):(n=new pe(h,"opacity",100*o,100*(e-o),n),n.xn1=l?1:0,h.zoom=1,n.type=2,n.b="alpha(opacity="+n.s+")",n.e="alpha(opacity="+(n.s+n.c)+")",n.data=t,n.plugin=a,n.setRatio=Re),l&&(n=new pe(h,"visibility",0,0,n,-1,null,!1,0,0!==o?"inherit":"hidden",0===e?"hidden":"inherit"),n.xs0="inherit",s._overwriteProps.push(n.n),s._overwriteProps.push(i)),n}});var Ae=function(t,e){e&&(t.removeProperty?t.removeProperty(e.replace(P,"-$1").toLowerCase()):t.removeAttribute(e))},Ce=function(t){if(this.t._gsClassPT=this,1===t||0===t){this.t.className=0===t?this.b:this.e;for(var e=this.data,i=this.t.style;e;)e.v?i[e.p]=e.v:Ae(i,e.p),e=e._next;1===t&&this.t._gsClassPT===this&&(this.t._gsClassPT=null)}else this.t.className!==this.e&&(this.t.className=this.e)};de("className",{parser:function(t,e,s,n,a,o,h){var l,_,u,p,f,c=t.className,m=t.
52509style.cssText;if(a=n._classNamePT=new pe(t,s,0,0,a,2),a.setRatio=Ce,a.pr=-11,i=!0,a.b=c,_=W(t,r),u=t._gsClassPT){for(p={},f=u.data;f;)p[f.p]=1,f=f._next;u.setRatio(1)}return t._gsClassPT=a,a.e="="!==e.charAt(1)?e:c.replace(RegExp("\\s*\\b"+e.substr(2)+"\\b"),"")+("+"===e.charAt(0)?" "+e.substr(2):""),n._tween._duration&&(t.className=a.e,l=H(t,_,W(t),h,p),t.className=c,a.data=l.firstMPT,t.style.cssText=m,a=a.xfirst=n.parse(t,l.difs,a,o)),a}});var Oe=function(t){if((1===t||0===t)&&this.data._totalTime===this.data._totalDuration&&"isFromStart"!==this.data.data){var e,i,s,r,n=this.t.style,a=o.transform.parse;if("all"===this.e)n.cssText="",r=!0;else for(e=this.e.split(","),s=e.length;--s>-1;)i=e[s],o[i]&&(o[i].parse===a?r=!0:i="transformOrigin"===i?we:o[i].p),Ae(n,i);r&&(Ae(n,ye),this.t._gsTransform&&delete this.t._gsTransform)}};for(de("clearProps",{parser:function(t,e,s,r,n){return n=new pe(t,s,0,0,n,2),n.setRatio=Oe,n.e=e,n.pr=-10,n.data=r._tween,i=!0,n}}),h="bezier,throwProps,physicsProps,physics2D".split(","),ce=h.length;ce--;)ge(h[ce]);h=a.prototype,h._firstPT=null,h._onInitTween=function(t,e,o){if(!t.nodeType)return!1;this._target=t,this._tween=o,this._vars=e,l=e.autoRound,i=!1,s=e.suffixMap||a.suffixMap,r=Z(t,""),n=this._overwriteProps;var h,p,c,m,d,g,v,y,T,x=t.style;if(_&&""===x.zIndex&&(h=G(t,"zIndex",r),("auto"===h||""===h)&&(x.zIndex=0)),"string"==typeof e&&(m=x.cssText,h=W(t,r),x.cssText=m+";"+e,h=H(t,h,W(t)).difs,!U&&w.test(e)&&(h.opacity=parseFloat(RegExp.$1)),e=h,x.cssText=m),this._firstPT=p=this.parse(t,e,null),this._transformType){for(T=3===this._transformType,ye?u&&(_=!0,""===x.zIndex&&(v=G(t,"zIndex",r),("auto"===v||""===v)&&(x.zIndex=0)),f&&(x.WebkitBackfaceVisibility=this._vars.WebkitBackfaceVisibility||(T?"visible":"hidden"))):x.zoom=1,c=p;c&&c._next;)c=c._next;y=new pe(t,"transform",0,0,null,2),this._linkCSSP(y,null,c),y.setRatio=T&&xe?Se:ye?ke:Pe,y.data=this._transform||be(t,r,!0),n.pop()}if(i){for(;p;){for(g=p._next,c=m;c&&c.pr>p.pr;)c=c._next;(p._prev=c?c._prev:d)?p._prev._next=p:m=p,(p._next=c)?c._prev=p:d=p,p=g}this._firstPT=m}return!0},h.parse=function(t,e,i,n){var a,h,_,u,p,f,c,m,d,g,v=t.style;for(a in e)f=e[a],h=o[a],h?i=h.parse(t,f,a,this,i,n,e):(p=G(t,a,r)+"",d="string"==typeof f,"color"===a||"fill"===a||"stroke"===a||-1!==a.indexOf("Color")||d&&b.test(f)?(d||(f=oe(f),f=(f.length>3?"rgba(":"rgb(")+f.join(",")+")"),i=fe(v,a,p,f,!0,"transparent",i,0,n)):!d||-1===f.indexOf(" ")&&-1===f.indexOf(",")?(_=parseFloat(p),c=_||0===_?p.substr((_+"").length):"",(""===p||"auto"===p)&&("width"===a||"height"===a?(_=te(t,a,r),c="px"):"left"===a||"top"===a?(_=Q(t,a,r),c="px"):(_="opacity"!==a?0:1,c="")),g=d&&"="===f.charAt(1),g?(u=parseInt(f.charAt(0)+"1",10),f=f.substr(2),u*=parseFloat(f),m=f.replace(y,"")):(u=parseFloat(f),m=d?f.substr((u+"").length)||"":""),""===m&&(m=s[a]||c),f=u||0===u?(g?u+_:u)+m:e[a],c!==m&&""!==m&&(u||0===u)&&(_||0===_)&&(_=$(t,a,_,c),"%"===m?(_/=$(t,a,100,"%")/100,_>100&&(_=100),e.strictUnits!==!0&&(p=_+"%")):"em"===m?_/=$(t,a,1,"em"):(u=$(t,a,u,m),m="px"),g&&(u||0===u)&&(f=u+_+m)),g&&(u+=_),!_&&0!==_||!u&&0!==u?void 0!==v[a]&&(f||"NaN"!=f+""&&null!=f)?(i=new pe(v,a,u||_||0,0,i,-1,a,!1,0,p,f),i.xs0="none"!==f||"display"!==a&&-1===a.indexOf("Style")?f:p):j("invalid "+a+" tween value: "+e[a]):(i=new pe(v,a,_,u-_,i,0,a,l!==!1&&("px"===m||"zIndex"===a),0,p,f),i.xs0=m)):i=fe(v,a,p,f,!0,null,i,0,n)),n&&i&&!i.plugin&&(i.plugin=n);return i},h.setRatio=function(t){var e,i,s,r=this._firstPT,n=1e-6;if(1!==t||this._tween._time!==this._tween._duration&&0!==this._tween._time)if(t||this._tween._time!==this._tween._duration&&0!==this._tween._time||this._tween._rawPrevTime===-1e-6)for(;r;){if(e=r.c*t+r.s,r.r?e=e>0?0|e+.5:0|e-.5:n>e&&e>-n&&(e=0),r.type)if(1===r.type)if(s=r.l,2===s)r.t[r.p]=r.xs0+e+r.xs1+r.xn1+r.xs2;else if(3===s)r.t[r.p]=r.xs0+e+r.xs1+r.xn1+r.xs2+r.xn2+r.xs3;else if(4===s)r.t[r.p]=r.xs0+e+r.xs1+r.xn1+r.xs2+r.xn2+r.xs3+r.xn3+r.xs4;else if(5===s)r.t[r.p]=r.xs0+e+r.xs1+r.xn1+r.xs2+r.xn2+r.xs3+r.xn3+r.xs4+r.xn4+r.xs5;else{for(i=r.xs0+e+r.xs1,s=1;r.l>s;s++)i+=r["xn"+s]+r["xs"+(s+1)];r.t[r.p]=i}else-1===r.type?r.t[r.p]=r.xs0:r.setRatio&&r.setRatio(t);else r.t[r.p]=e+r.xs0;r=r._next}else for(;r;)2!==r.type?r.t[r.p]=r.b:r.setRatio(t),r=r._next;else for(;r;)2!==r.type?r.t[r.p]=r.e:r.setRatio(t),r=r._next},h._enableTransforms=function(t){this._transformType=t||3===this._transformType?3:2,this._transform=this._transform||be(this._target,r,!0)}
52509,h._linkCSSP=function(t,e,i,s){return t&&(e&&(e._prev=t),t._next&&(t._next._prev=t._prev),t._prev?t._prev._next=t._next:this._firstPT===t&&(this._firstPT=t._next,s=!0),i?i._next=t:s||null!==this._firstPT||(this._firstPT=t),t._next=e,t._prev=i),t},h._kill=function(e){var i,s,r,n=e;if(e.autoAlpha||e.alpha){n={};for(s in e)n[s]=e[s];n.opacity=1,n.autoAlpha&&(n.visibility=1)}return e.className&&(i=this._classNamePT)&&(r=i.xfirst,r&&r._prev?this._linkCSSP(r._prev,i._next,r._prev._prev):r===this._firstPT&&(this._firstPT=i._next),i._next&&this._linkCSSP(i._next,i._next._next,r._prev),this._classNamePT=null),t.prototype._kill.call(this,n)};var De=function(t,e,i){var s,r,n,a;if(t.slice)for(r=t.length;--r>-1;)De(t[r],e,i);else for(s=t.childNodes,r=s.length;--r>-1;)n=s[r],a=n.type,n.style&&(e.push(W(n)),i&&i.push(n)),1!==a&&9!==a&&11!==a||!n.childNodes.length||De(n,e,i)};return a.cascadeTo=function(t,i,s){var r,n,a,o=e.to(t,i,s),h=[o],l=[],_=[],u=[],p=e._internals.reservedProps;for(t=o._targets||o.target,De(t,l,u),o.render(i,!0),De(t,_),o.render(0,!0),o._enabled(!0),r=u.length;--r>-1;)if(n=H(u[r],l[r],_[r]),n.firstMPT){n=n.difs;for(a in s)p[a]&&(n[a]=s[a]);h.push(e.to(u[r],i,n))}return h},t.activate([a]),a},!0),function(){var t=window._gsDefine.plugin({propName:"roundProps",priority:-1,API:2,init:function(t,e,i){return this._tween=i,!0}}),e=t.prototype;e._onInitAllProps=function(){for(var t,e,i,s=this._tween,r=s.vars.roundProps instanceof Array?s.vars.roundProps:s.vars.roundProps.split(","),n=r.length,a={},o=s._propLookup.roundProps;--n>-1;)a[r[n]]=1;for(n=r.length;--n>-1;)for(t=r[n],e=s._firstPT;e;)i=e._next,e.pg?e.t._roundProps(a,!0):e.n===t&&(this._add(e.t,t,e.s,e.c),i&&(i._prev=e._prev),e._prev?e._prev._next=i:s._firstPT===e&&(s._firstPT=i),e._next=e._prev=null,s._propLookup[t]=o),e=i;return!1},e._add=function(t,e,i,s){this._addTween(t,e,i,i+s,e,!0),this._overwriteProps.push(e)}}(),window._gsDefine.plugin({propName:"attr",API:2,init:function(t,e){var i;if("function"!=typeof t.setAttribute)return!1;this._target=t,this._proxy={};
52510for(i in e)this._addTween(this._proxy,i,parseFloat(t.getAttribute(i)),e[i],i)&&this._overwriteProps.push(i);return!0},set:function(t){this._super.setRatio.call(this,t);for(var e,i=this._overwriteProps,s=i.length;--s>-1;)e=i[s],this._target.setAttribute(e,this._proxy[e]+"")}}),window._gsDefine.plugin({propName:"directionalRotation",API:2,init:function(t,e){"object"!=typeof e&&(e={rotation:e}),this.finals={};var i,s,r,n,a,o,h=e.useRadians===!0?2*Math.PI:360,l=1e-6;for(i in e)"useRadians"!==i&&(o=(e[i]+"").split("_"),s=o[0],r=parseFloat("function"!=typeof t[i]?t[i]:t[i.indexOf("set")||"function"!=typeof t["get"+i.substr(3)]?i:"get"+i.substr(3)]()),n=this.finals[i]="string"==typeof s&&"="===s.charAt(1)?r+parseInt(s.charAt(0)+"1",10)*Number(s.substr(2)):Number(s)||0,a=n-r,o.length&&(s=o.join("_"),-1!==s.indexOf("short")&&(a%=h,a!==a%(h/2)&&(a=0>a?a+h:a-h)),-1!==s.indexOf("_cw")&&0>a?a=(a+9999999999*h)%h-(0|a/h)*h:-1!==s.indexOf("ccw")&&a>0&&(a=(a-9999999999*h)%h-(0|a/h)*h)),(a>l||-l>a)&&(this._addTween(t,i,r,r+a,i),this._overwriteProps.push(i)));return!0},set:function(t){var e;if(1!==t)this._super.setRatio.call(this,t);else for(e=this._firstPT;e;)e.f?e.t[e.p](this.finals[e.p]):e.t[e.p]=this.finals[e.p],e=e._next}})._autoCSS=!0,window._gsDefine("easing.Back",["easing.Ease"],function(t){var e,i,s,r=window.GreenSockGlobals||window,n=r.com.greensock,a=2*Math.PI,o=Math.PI/2,h=n._class,l=function(e,i){var s=h("easing."+e,function(){},!0),r=s.prototype=new t;return r.constructor=s,r.getRatio=i,s},_=t.register||function(){},u=function(t,e,i,s){var r=h("easing."+t,{easeOut:new e,easeIn:new i,easeInOut:new s},!0);return _(r,t),r},p=function(t,e,i){this.t=t,this.v=e,i&&(this.next=i,i.prev=this,this.c=i.v-e,this.gap=i.t-t)},f=function(e,i){var s=h("easing."+e,function(t){this._p1=t||0===t?t:1.70158,this._p2=1.525*this._p1},!0),r=s.prototype=new t;return r.constructor=s,r.getRatio=i,r.config=function(t){return new s(t)},s},c=u("Back",f("BackOut",function(t){return(t-=1)*t*((this._p1+1)*t+this._p1)+1}),f("BackIn",function(t){return t*t*((this._p1+1)*t-this._p1)}),f("BackInOut",function(t){return 1>(t*=2)?.5*t*t*((this._p2+1)*t-this._p2):.5*((t-=2)*t*((this._p2+1)*t+this._p2)+2)}
vendor: 4,316 bytes, line 52510
52510)),m=h("easing.SlowMo",function(t,e,i){e=e||0===e?e:.7,null==t?t=.7:t>1&&(t=1),this._p=1!==t?e:0,this._p1=(1-t)/2,this._p2=t,this._p3=this._p1+this._p2,this._calcEnd=i===!0},!0),d=m.prototype=new t;return d.constructor=m,d.getRatio=function(t){var e=t+(.5-t)*this._p;return this._p1>t?this._calcEnd?1-(t=1-t/this._p1)*t:e-(t=1-t/this._p1)*t*t*t*e:t>this._p3?this._calcEnd?1-(t=(t-this._p3)/this._p1)*t:e+(t-e)*(t=(t-this._p3)/this._p1)*t*t*t:this._calcEnd?1:e},m.ease=new m(.7,.7),d.config=m.config=function(t,e,i){return new m(t,e,i)},e=h("easing.SteppedEase",function(t){t=t||1,this._p1=1/t,this._p2=t+1},!0),d=e.prototype=new t,d.constructor=e,d.getRatio=function(t){return 0>t?t=0:t>=1&&(t=.999999999),(this._p2*t>>0)*this._p1},d.config=e.config=function(t){return new e(t)},i=h("easing.RoughEase",function(e){e=e||{};for(var i,s,r,n,a,o,h=e.taper||"none",l=[],_=0,u=0|(e.points||20),f=u,c=e.randomize!==!1,m=e.clamp===!0,d=e.template instanceof t?e.template:null,g="number"==typeof e.strength?.4*e.strength:.4;--f>-1;)i=c?Math.random():1/u*f,s=d?d.getRatio(i):i,"none"===h?r=g:"out"===h?(n=1-i,r=n*n*g):"in"===h?r=i*i*g:.5>i?(n=2*i,r=.5*n*n*g):(n=2*(1-i),r=.5*n*n*g),c?s+=Math.random()*r-.5*r:f%2?s+=.5*r:s-=.5*r,m&&(s>1?s=1:0>s&&(s=0)),l[_++]={x:i,y:s};for(l.sort(function(t,e){return t.x-e.x}),o=new p(1,1,null),f=u;--f>-1;)a=l[f],o=new p(a.x,a.y,o);this._prev=new p(0,0,0!==o.t?o:o.next)},!0),d=i.prototype=new t,d.constructor=i,d.getRatio=function(t){var e=this._prev;if(t>e.t){for(;e.next&&t>=e.t;)e=e.next;e=e.prev}else for(;e.prev&&e.t>=t;)e=e.prev;return this._prev=e,e.v+(t-e.t)/e.gap*e.c},d.config=function(t){return new i(t)},i.ease=new i,u("Bounce",l("BounceOut",function(t){return 1/2.75>t?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}),l("BounceIn",function(t){return 1/2.75>(t=1-t)?1-7.5625*t*t:2/2.75>t?1-(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1-(7.5625*(t-=2.25/2.75)*t+.9375):1-(7.5625*(t-=2.625/2.75)*t+.984375)}),l("BounceInOut",function(t){var e=.5>t;return t=e?1-2*t:2*t-1,t=1/2.75>t?7.5625*t*t:2/2.75>t?7.5625*(t-=1.5/2.75)*t+.75:2.5/2.75>t?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375,e?.5*(1-t):.5*t+.5})),u("Circ",l("CircOut",function(t){return Math.sqrt(1-(t-=1)*t)}),l("CircIn",function(t){return-(Math.sqrt(1-t*t)-1)}),l("CircInOut",function(t){return 1>(t*=2)?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)})),s=function(e,i,s){var r=h("easing."+e,function(t,e){this._p1=t||1,this._p2=e||s,this._p3=this._p2/a*(Math.asin(1/this._p1)||0)},!0),n=r.prototype=new t;return n.constructor=r,n.getRatio=i,n.config=function(t,e){return new r(t,e)},r},u("Elastic",s("ElasticOut",function(t){return this._p1*Math.pow(2,-10*t)*Math.sin((t-this._p3)*a/this._p2)+1},.3),s("ElasticIn",function(t){return-(this._p1*Math.pow(2,10*(t-=1))*Math.sin((t-this._p3)*a/this._p2))},.3),s("ElasticInOut",function(t){return 1>(t*=2)?-.5*this._p1*Math.pow(2,10*(t-=1))*Math.sin((t-this._p3)*a/this._p2):.5*this._p1*Math.pow(2,-10*(t-=1))*Math.sin((t-this._p3)*a/this._p2)+1},.45)),u("Expo",l("ExpoOut",function(t){return 1-Math.pow(2,-10*t)}),l("ExpoIn",function(t){return Math.pow(2,10*(t-1))-.001}),l("ExpoInOut",function(t){return 1>(t*=2)?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*(t-1)))})),u("Sine",l("SineOut",function(t){return Math.sin(t*o)}),l("SineIn",function(t){return-Math.cos(t*o)+1}),l("SineInOut",function(t){return-.5*(Math.cos(Math.PI*t)-1)})),h("easing.EaseLookup",{find:function(e){return t.map[e]}},!0),_(r.SlowMo,"SlowMo","ease,"),_(i,"RoughEase","ease,"),_(e,"SteppedEase","ease,"),c},!0)}),function(t){"use strict";var e=t.GreenSockGlobals||t;if(!e.TweenLite){var i,s,r,n,a,o=function(t){var i,s=t.split("."),r=e;for(i=0;s.length>i;i++)r[s[i]]=r=r[s[i]]||{};return r},h=o("com.greensock"),l=1e-10,_=[].slice,u=function(){},p=function(){var t=Object.prototype.toString,e=t.call([]);return function(i){return i instanceof Array||"object"==typeof i&&!!i.push&&t.call(i)===e}}(),f={},c=function(i,s,r,n){this.sc=f[i]?f[i].sc:[],f[i]=this,this.gsClass=null,this.func=r;var a=[];this.check=function(h){for(var l,_,u,p,m=s.length,d=m;--m>-1;)(l=f[s[m]]||new c(s[m],[])).gsClass?(a[m]=l.gsClass,d--):h&&l.sc.push(this);if(0===d&&r)for(_=("com.greensock."+i).split("."),u=_.pop(),p=o(_.j
52510oin("."))[u]=this.gsClass=r.apply(r,a),n&&(e[u]=p,"function"==typeof define&&define.amd?define((t.GreenSockAMDPath?t.GreenSockAMDPath+"/":"")+i.split(".").join("/"),[],function(){return p}):"undefined"!=typeof module&&module.exports&&(module.exports=p)),m=0;this.sc.length>m;m++)this.sc[m].check()},this.check(!0)},m=t._gsDefine=function(t,e,i,s){return new c(t,e,i,s)},d=h._class=function(t,e,i){return e=e||function(){},m(t,[],function(){return e},i),e};m.globals=e;var g=[0,0,1,1],v=[],y=d("easing.Ease",function(t,e,i,s){this._func=t,this._type=i||0,this._power=s||0,this._params=e?g.concat(e):g},!0),T=y.map={},w=y.register=function(t,e,i,s){for(var r,n,a,o,l=e.split(","),_=l.length,u=(i||"easeIn,easeOut,easeInOut").split(",");--_>-1;)for(n=l[_],r=s?d("easing."+n,null,!0):h.easing[n]||{},a=u.length;--a>-1;)o=u[a],T[n+"."+o]=T[o+n]=r[o]=t.getRatio?t:t[o]||new t};for(r=y.prototype,r._calcEnd=!1,r.getRatio=function(t){if(this._func)return this._params[0]=t,this._func.apply(null,this._params);var e=this._type,i=this._power,s=1===e?1-t:2===e?t:.5>t?2*t:2*(1-t);return 1===i?s*=s:2===i?s*=s*s:3===i?s*=s*s*s:4===i&&(s*=s*s*s*s),1===e?1-s:2===e?s:.5>t?s/2:1-s/2},i=["Linear","Quad","Cubic","Quart","Quint,Strong"],s=i.length;--s>-1;)r=i[s]+",Power"+s,w(new y(null,null,1,s),r,"easeOut",!0),w(new y(null,null,2,s),r,"easeIn"+(0===s?",easeNone":"")),w(new y(null,null,3,s),r,"easeInOut");T.linear=h.easing.Linear.easeIn,T.swing=h.easing.Quad.easeInOut;var x=d("events.EventDispatcher",function(t){this._listeners={},this._eventTarget=t||this});r=x.prototype,r.addEventListener=function(t,e,i,s,r){r=r||0;var o,h,l=this._listeners[t],_=0;for(null==l&&(this._listeners[t]=l=[]),h=l.length;--h>-1;)o=l[h],o.c===e&&o.s===i?l.splice(h,1):0===_&&r>o.pr&&(_=h+1);l.splice(_,0,{c:e,s:i,up:s,pr:r}),this!==n||a||n.wake()},r.removeEventListener=function(t,e){var i,s=this._listeners[t];if(s)for(i=s.length;--i>-1;)if(s[i].c===e)return s.splice(i,1),void 0},r.dispatchEvent=function(t){var e,i,s,r=this._listeners[t];if(r)for(e=r.length,i=this._eventTarget;--e>-1;)s=r[e],s.up?s.c.call(s.s||i,{type:t,target:i}):s.c.call(s.s||i)};var b=t.requestAnimationFrame,P=t.cancelAnimationFrame,S=Date.now||function(){return(new Date).getTime()},k=S();for(i=["ms","moz","webkit","o"],s=i.length;--s>-1&&!b;)b=t[i[s]+"RequestAnimationFrame"],P=t[i[s]+"CancelAnimationFrame"]||t[i[s]+"CancelRequestAnimationFrame"];d("Ticker",function(t,e){var i,s,r,o,h,l=this,_=S(),p=e!==!1&&b,f=function(t){k=S(),l.time=(k-_)/1e3;var e,n=l.time-h;(!i||n>0||t===!0)&&(l.frame++,h+=n+(n>=o?.004:o-n),e=!0),t!==!0&&(r=s(f)),e&&l.dispatchEvent("tick")};x.call(l),l.time=l.frame=0,l.tick=function(){f(!0)},l.sleep=function(){null!=r&&(p&&P?P(r):clearTimeout(r),s=u,r=null,l===n&&(a=!1))},l.wake=function(){null!==r&&l.sleep(),s=0===i?u:p&&b?b:function(t){return setTimeout(t,0|1e3*(h-l.time)+1)},l===n&&(a=!0),f(2)},l.fps=function(t){return arguments.length?(i=t,o=1/(i||60),h=this.time+o,l.wake(),void 0):i},l.useRAF=function(t){return arguments.length?(l.sleep(),p=t,l.fps(i),void 0):p},l.fps(t),setTimeout(function(){p&&(!r||5>l.frame)&&l.useRAF(!1)},1500)}),r=h.Ticker.prototype=new h.events.EventDispatcher,r.constructor=h.Ticker;var R=d("core.Animation",function(t,e){if(this.vars=e=e||{},this._duration=this._totalDuration=t||0,this._delay=Number(e.delay)||0,this._timeScale=1,this._active=e.immediateRender===!0,this.data=e.data,this._reversed=e.reversed===!0,U){a||n.wake();var i=this.vars.useFrames?z:U;i.add(this,i._time),this.vars.paused&&this.paused(!0)}});n=R.ticker=new h.Ticker,r=R.prototype,r._dirty=r._gc=r._initted=r._paused=!1,r._totalTime=r._time=0,r._rawPrevTime=-1,r._next=r._last=r._onUpdate=r._timeline=r.timeline=null,r._paused=!1;var A=function(){a&&S()-k>2e3&&n.wake(),setTimeout(A,2e3)};A(),r.play=function(t,e){return arguments.length&&this.seek(t,e),this.reversed(!1).paused(!1)},r.pause=function(t,e){return arguments.length&&this.seek(t,e),this.paused(!0)},r.resume=function(t,e){return arguments.length&&this.seek(t,e),this.paused(!1)},r.seek=function(t,e){return this.totalTime(Number(t),e!==!1)},r.restart=function(t,e){return this.reversed(!1).paused(!1).totalTime(t?-this._delay:0,e!==!1,!0)},r.reverse=function(t,e){return arguments.length&&this.seek(t||this.totalDuration(),e),this.reversed(!0).paused(!1)},r.render=function(){},r.invalidate=function(){return this},r.isActive=function(){var t,e=this._timeline,i=this._startTime;return!e||!this._gc&&!this._paused&&e.isActive()&&(t=e.rawTime())>=i&&i+this.totalDuration()/this._timeScale>t},r._enabled=function(t,e){return a||n.wake(),this._gc=!t,this._active=this.isActive(),e!==!0&&(t&&!this.timeline?this._timeline.add(this,this._startTime-this._delay):!t&&this.timeline&&this._timeline._remove(this,!0)),!1},r._kill=function(){return this._enabled(!1,!1)},r.kill=function(t,e){return this._kill(t,e),this},r._uncache=function(t){for(var e=t?this:this.timeline;e;)e._dirty=!0,e=e.timeline;return this},r._swapSelfInParams=function(t){for(var e=t.length,i=t.concat();--e>-1;)"{self}"===t[e]&&(i[e]=this);return i}
vendor: 4,483 bytes, line 52510
52510,r.eventCallback=function(t,e,i,s){if("on"===(t||"").substr(0,2)){var r=this.vars;if(1===arguments.length)return r[t];null==e?delete r[t]:(r[t]=e,r[t+"Params"]=p(i)&&-1!==i.join("").indexOf("{self}")?this._swapSelfInParams(i):i,r[t+"Scope"]=s),"onUpdate"===t&&(this._onUpdate=e)}return this},r.delay=function(t){return arguments.length?(this._timeline.smoothChildTiming&&this.startTime(this._startTime+t-this._delay),this._delay=t,this):this._delay},r.duration=function(t){return arguments.length?(this._duration=this._totalDuration=t,this._uncache(!0),this._timeline.smoothChildTiming&&this._time>0&&this._time<this._duration&&0!==t&&this.totalTime(this._totalTime*(t/this._duration),!0),this):(this._dirty=!1,this._duration)},r.totalDuration=function(t){return this._dirty=!1,arguments.length?this.duration(t):this._totalDuration},r.time=function(t,e){return arguments.length?(this._dirty&&this.totalDuration(),this.totalTime(t>this._duration?this._duration:t,e)):this._time},r.totalTime=function(t,e,i){if(a||n.wake(),!arguments.length)return this._totalTime;if(this._timeline){if(0>t&&!i&&(t+=this.totalDuration()),this._timeline.smoothChildTiming){this._dirty&&this.totalDuration();var s=this._totalDuration,r=this._timeline;if(t>s&&!i&&(t=s),this._startTime=(this._paused?this._pauseTime:r._time)-(this._reversed?s-t:t)/this._timeScale,r._dirty||this._uncache(!1),r._timeline)for(;r._timeline;)r._timeline._time!==(r._startTime+r._totalTime)/r._timeScale&&r.totalTime(r._totalTime,!0),r=r._timeline}this._gc&&this._enabled(!0,!1),(this._totalTime!==t||0===this._duration)&&this.render(t,e,!1)}return this},r.progress=r.totalProgress=function(t,e){return arguments.length?this.totalTime(this.duration()*t,e):this._time/this.duration()},r.startTime=function(t){return arguments.length?(t!==this._startTime&&(this._startTime=t,this.timeline&&this.timeline._sortChildren&&this.timeline.add(this,t-this._delay)),this):this._startTime},r.timeScale=function(t){if(!arguments.length)return this._timeScale;if(t=t||l,this._timeline&&this._timeline.smoothChildTiming){var e=this._pauseTime,i=e||0===e?e:this._timeline.totalTime();this._startTime=i-(i-this._startTime)*this._timeScale/t}return this._timeScale=t,this._uncache(!1)},r.reversed=function(t){return arguments.length?(t!=this._reversed&&(this._reversed=t,this.totalTime(this._totalTime,!0)),this):this._reversed},r.paused=function(t){if(!arguments.length)return this._paused;if(t!=this._paused&&this._timeline){a||t||n.wake();var e=this._timeline,i=e.rawTime(),s=i-this._pauseTime;!t&&e.smoothChildTiming&&(this._startTime+=s,this._uncache(!1)),this._pauseTime=t?i:null,this._paused=t,this._active=this.isActive(),!t&&0!==s&&this._initted&&this.duration()&&this.render(e.smoothChildTiming?this._totalTime:(i-this._startTime)/this._timeScale,!0,!0)}return this._gc&&!t&&this._enabled(!0,!1),this};var C=d("core.SimpleTimeline",function(t){R.call(this,0,t),this.autoRemoveChildren=this.smoothChildTiming=!0});r=C.prototype=new R,r.constructor=C,r.kill()._gc=!1,r._first=r._last=null,r._sortChildren=!1,r.add=r.insert=function(t,e){var i,s;if(t._startTime=Number(e||0)+t._delay,t._paused&&this!==t._timeline&&(t._pauseTime=t._startTime+(this.rawTime()-t._startTime)/t._timeScale),t.timeline&&t.timeline._remove(t,!0),t.timeline=t._timeline=this,t._gc&&t._enabled(!0,!0),i=this._last,this._sortChildren)for(s=t._startTime;i&&i._startTime>s;)i=i._prev;return i?(t._next=i._next,i._next=t):(t._next=this._first,this._first=t),t._next?t._next._prev=t:this._last=t,t._prev=i,this._timeline&&this._uncache(!0),this},r._remove=function(t,e){return t.timeline===this&&(e||t._enabled(!1,!0),t.timeline=null,t._prev?t._prev._next=t._next:this._first===t&&(this._first=t._next),t._next?t._next._prev=t._prev:this._last===t&&(this._last=t._prev),this._timeline&&this._uncache(!0)),this},r.render=function(t,e,i){var s,r=this._first;for(this._totalTime=this._time=this._rawPrevTime=t;r;)s=r._next,(r._active||t>=r._startTime&&!r._paused)&&(r._reversed?r.render((r._dirty?r.totalDuration():r._totalDuration)-(t-r._startTime)*r._timeScale,e,i):r.render((t-r._startTime)*r._timeScale,e,i)),r=s},r.rawTime=function(){return a||n.wake(),this._totalTime};var O=d("TweenLite",function(e,i,s){if(R.call(this,i,s),this.render=O.prototype.render,null==e)throw"Cannot tween a null target.";this.target=e="string"!=typeof e?e:O.selector(e)||e;var r,n,a,o=e.jquery||e.length&&e!==t&&e[0]&&(e[0]===t||e[0].nodeType&&e[0].style&&!e.nodeType),h=this.vars.over
52510write;if(this._overwrite=h=null==h?X[O.defaultOverwrite]:"number"==typeof h?h>>0:X[h],(o||e instanceof Array||e.push&&p(e))&&"number"!=typeof e[0])for(this._targets=a=_.call(e,0),this._propLookup=[],this._siblings=[],r=0;a.length>r;r++)n=a[r],n?"string"!=typeof n?n.length&&n!==t&&n[0]&&(n[0]===t||n[0].nodeType&&n[0].style&&!n.nodeType)?(a.splice(r--,1),this._targets=a=a.concat(_.call(n,0))):(this._siblings[r]=Y(n,this,!1),1===h&&this._siblings[r].length>1&&j(n,this,null,1,this._siblings[r])):(n=a[r--]=O.selector(n),"string"==typeof n&&a.splice(r+1,1)):a.splice(r--,1);else this._propLookup={},this._siblings=Y(e,this,!1),1===h&&this._siblings.length>1&&j(e,this,null,1,this._siblings);(this.vars.immediateRender||0===i&&0===this._delay&&this.vars.immediateRender!==!1)&&this.render(-this._delay,!1,!0)},!0),D=function(e){return e.length&&e!==t&&e[0]&&(e[0]===t||e[0].nodeType&&e[0].style&&!e.nodeType)},M=function(t,e){var i,s={};for(i in t)L[i]||i in e&&"x"!==i&&"y"!==i&&"width"!==i&&"height"!==i&&"className"!==i&&"border"!==i||!(!E[i]||E[i]&&E[i]._autoCSS)||(s[i]=t[i],delete t[i]);t.css=s};r=O.prototype=new R,r.constructor=O,r.kill()._gc=!1,r.ratio=0,r._firstPT=r._targets=r._overwrittenProps=r._startAt=null,r._notifyPluginsOfEnabled=!1,O.version="1.11.2",O.defaultEase=r._ease=new y(null,null,1,1),O.defaultOverwrite="auto",O.ticker=n,O.autoSleep=!0,O.selector=t.$||t.jQuery||function(e){return t.$?(O.selector=t.$,t.$(e)):t.document?t.document.getElementById("#"===e.charAt(0)?e.substr(1):e):e};var I=O._internals={isArray:p,isSelector:D},E=O._plugins={},F=O._tweenLookup={},N=0,L=I.reservedProps={ease:1,delay:1,overwrite:1,onComplete:1,onCompleteParams:1,onCompleteScope:1,useFrames:1,runBackwards:1,startAt:1,onUpdate:1,onUpdateParams:1,onUpdateScope:1,onStart:1,onStartParams:1,onStartScope:1,onReverseComplete:1,onReverseCompleteParams:1,onReverseCompleteScope:1,onRepeat:1,onRepeatParams:1,onRepeatScope:1,easeParams:1,yoyo:1,immediateRender:1,repeat:1,repeatDelay:1,data:1,paused:1,reversed:1,autoCSS:1},X={none:0,all:1,auto:2,concurrent:3,allOnStart:4,preexisting:5,"true":1,"false":0},z=R._rootFramesTimeline=new C,U=R._rootTimeline=new C;U._startTime=n.time,z._startTime=n.frame,U._active=z._active=!0,R._updateRoot=function(){if(U.render((n.time-U._startTime)*U._timeScale,!1,!1),z.render((n.frame-z._startTime)*z._timeScale,!1,!1),!(n.frame%120)){var t,e,i;for(i in F){for(e=F[i].tweens,t=e.length;--t>-1;)e[t]._gc&&e.splice(t,1);0===e.length&&delete F[i]}if(i=U._first,(!i||i._paused)&&O.autoSleep&&!z._first&&1===n._listeners.tick.length){for(;i&&i._paused;)i=i._next;i||n.sleep()}}},n.addEventListener("tick",R._updateRoot);var Y=function(t,e,i){var s,r,n=t._gsTweenID;if(F[n||(t._gsTweenID=n="t"+N++)]||(F[n]={target:t,tweens:[]}),e&&(s=F[n].tweens,s[r=s.length]=e,i))for(;--r>-1;)s[r]===e&&s.splice(r,1);return F[n].tweens},j=function(t,e,i,s,r){var n,a,o,h;if(1===s||s>=4){for(h=r.length,n=0;h>n;n++)if((o=r[n])!==e)o._gc||o._enabled(!1,!1)&&(a=!0);else if(5===s)break;return a}var _,u=e._startTime+l,p=[],f=0,c=0===e._duration;for(n=r.length;--n>-1;)(o=r[n])===e||o._gc||o._paused||(o._timeline!==e._timeline?(_=_||B(e,0,c),0===B(o,_,c)&&(p[f++]=o)):u>=o._startTime&&o._startTime+o.totalDuration()/o._timeScale+l>u&&((c||!o._initted)&&2e-10>=u-o._startTime||(p[f++]=o)));for(n=f;--n>-1;)o=p[n],2===s&&o._kill(i,t)&&(a=!0),(2!==s||!o._firstPT&&o._initted)&&o._enabled(!1,!1)&&(a=!0);return a},B=function(t,e,i){for(var s=t._timeline,r=s._timeScale,n=t._startTime;s._timeline;){if(n+=s._startTime,r*=s._timeScale,s._paused)return-100;s=s._timeline}return n/=r,n>e?n-e:i&&n===e||!t._initted&&2*l>n-e?l:(n+=t.totalDuration()/t._timeScale/r)>e+l?0:n-e-l};r._init=function(){var t,e,i,s,r=this.vars,n=this._overwrittenProps,a=this._duration,o=r.immediateRender,h=r.ease;if(r.startAt){if(this._startAt&&this._startAt.render(-1,!0),r.startAt.overwrite=0,r.startAt.immediateRender=!0,this._startAt=O.to(this.target,0,r.startAt),o)if(this._time>0)this._startAt=null;else if(0!==a)return}else if(r.runBackwards&&0!==a)if(this._startAt)this._startAt.render(-1,!0),this._startAt=null;else{i={};for(s in r)L[s]&&"autoCSS"!==s||(i[s]=r[s]);if(i.overwrite=0,i.data="isFromStart",this._startAt=O.to(this.target,0,i),r.immediateRender){if(0===this._time)return}else this._startAt.render(-1,!0)}if(this._ease=h?h instanceof y?r.easeParams instanceof Array?h.config.apply(h,r.easeParams):h:"function"==typeof h?new y(
52510h,r.easeParams):T[h]||O.defaultEase:O.defaultEase,this._easeType=this._ease._type,this._easePower=this._ease._power,this._firstPT=null,this._targets)for(t=this._targets.length;--t>-1;)this._initProps(this._targets[t],this._propLookup[t]={},this._siblings[t],n?n[t]:null)&&(e=!0);else e=this._initProps(this.target,this._propLookup,this._siblings,n);if(e&&O._onPluginEvent("_onInitAllProps",this),n&&(this._firstPT||"function"!=typeof this.target&&this._enabled(!1,!1)),r.runBackwards)for(i=this._firstPT;i;)i.s+=i.c,i.c=-i.c,i=i._next;this._onUpdate=r.onUpdate,this._initted=!0},r._initProps=function(e,i,s,r){var n,a,o,h,l,_;if(null==e)return!1;this.vars.css||e.style&&e!==t&&e.nodeType&&E.css&&this.vars.autoCSS!==!1&&M(this.vars,e);for(n in this.vars){if(_=this.vars[n],L[n])_&&(_ instanceof Array||_.push&&p(_))&&-1!==_.join("").indexOf("{self}")&&(this.vars[n]=_=this._swapSelfInParams(_,this));else if(E[n]&&(h=new E[n])._onInitTween(e,this.vars[n],this)){for(this._firstPT=l={_next:this._firstPT,t:h,p:"setRatio",s:0,c:1,f:!0,n:n,pg:!0,pr:h._priority},a=h._overwriteProps.length;--a>-1;)i[h._overwriteProps[a]]=this._firstPT;(h._priority||h._onInitAllProps)&&(o=!0),(h._onDisable||h._onEnable)&&(this._notifyPluginsOfEnabled=!0)}else this._firstPT=i[n]=l={_next:this._firstPT,t:e,p:n,f:"function"==typeof e[n],n:n,pg:!1,pr:0},l.s=l.f?e[n.indexOf("set")||"function"!=typeof e["get"+n.substr(3)]?n:"get"+n.substr(3)]():parseFloat(e[n]),l.c="string"==typeof _&&"="===_.charAt(1)?parseInt(_.charAt(0)+"1",10)*Number(_.substr(2)):Number(_)-l.s||0;l&&l._next&&(l._next._prev=l)}return r&&this._kill(r,e)?this._initProps(e,i,s,r):this._overwrite>1&&this._firstPT&&s.length>1&&j(e,this,i,this._overwrite,s)?(this._kill(i,e),this._initProps(e,i,s,r)):o},r.render=function(t,e,i){var s,r,n,a,o=this._time,h=this._duration;if(t>=h)this._totalTime=this._time=h,this.ratio=this._ease._calcEnd?this._ease.getRatio(1):1,this._reversed||(s=!0,r="onComplete"),0===h&&(a=this._rawPrevTime,(0===t||0>a||a===l)&&a!==t&&(i=!0,a>l&&(r="onReverseComplete")),this._rawPrevTime=a=!e||t?t:l);else if(1e-7>t)this._totalTime=this._time=0,this.ratio=this._ease._calcEnd?this._ease.getRatio(0):0,(0!==o||0===h&&this._rawPrevTime>l)&&(r="onReverseComplete",s=this._reversed),0>t?(this._active=!1,0===h&&(this._rawPrevTime>=0&&(i=!0),this._rawPrevTime=a=!e||t?t:l)):this._initted||(i=!0);else if(this._totalTime=this._time=t,this._easeType){var _=t/h,u=this._easeType,p=this._easePower;(1===u||3===u&&_>=.5)&&(_=1-_),3===u&&(_*=2),1===p?_*=_:2===p?_*=_*_:3===p?_*=_*_*_:4===p&&(_*=_*_*_*_),this.ratio=1===u?1-_:2===u?_:.5>t/h?_/2:1-_/2}else this.ratio=this._ease.getRatio(t/h);if(this._time!==o||i){if(!this._initted){if(this._init(),!this._initted||this._gc)return;this._time&&!s?this.ratio=this._ease.getRatio(this._time/h):s&&this._ease._calcEnd&&(this.ratio=this._ease.getRatio(0===this._time?0:1))}for(this._active||!this._paused&&this._time!==o&&t>=0&&(this._active=!0),0===o&&(this._startAt&&(t>=0?this._startAt.render(t,e,i):r||(r="_dummyGS")),this.vars.onStart&&(0!==this._time||0===h)&&(e||this.vars.onStart.apply(this.vars.onStartScope||this,this.vars.onStartParams||v))),n=this._firstPT;n;)n.f?n.t[n.p](n.c*this.ratio+n.s):n.t[n.p]=n.c*this.ratio+n.s,n=n._next;this._onUpdate&&(0>t&&this._startAt&&this._startTime&&this._startAt.render(t,e,i),e||i&&0===this._time&&0===o||this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||v)),r&&(this._gc||(0>t&&this._startAt&&!this._onUpdate&&this._startTime&&this._startAt.render(t,e,i),s&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!e&&this.vars[r]&&this.vars[r].apply(this.vars[r+"Scope"]||this,this.vars[r+"Params"]||v),0===h&&this._rawPrevTime===l&&a!==l&&(this._rawPrevTime=0)))}},r._kill=function(t,e){if("all"===t&&(t=null),null==t&&(null==e||e===this.target))return this._enabled(!1,!1);e="string"!=typeof e?e||this._targets||this.target:O.selector(e)||e;var i,s,r,n,a,o,h,l;if((p(e)||D(e))&&"number"!=typeof e[0])for(i=e.length;--i>-1;)this._kill(t,e[i])&&(o=!0);else{if(this._targets){for(i=this._targets.length;--i>-1;)if(e===this._targets[i]){a=this._propLookup[i]||{},this._overwrittenProps=this._overwrittenProps||[],s=this._overwrittenProps[i]=t?this._overwrittenProps[i]||{}:"all";break}}else{if(e!==this.target)return!1;a=this._propLookup,s=this._overwrittenProps=t?this._overwrittenProps||{}:"all"}if(a){h=t||a,l=t!==s&&"all"!==s&&t!==a&&("object"!=typeof t||!t._tempKill);for(r in h)(n=a[r])&&(n.pg&&n.t._kill(h)&&(o=!0),n.pg&&0!==n.t._overwriteProps.length||(n._prev?n._prev._next=n._next:n===this._firstPT&&(this._firstPT=n._next),n._next&&(n._next._prev=n._prev),n._next=n._prev=null),delete a[r]),l&&(s[r]=1);!this._firstPT&&this._initted&&this._enabled(!1,!1)}}return o},r.invalidate=function(){return this._notifyPluginsOfEnabled&&O._onPluginEvent("_onDisable",this),this._firstPT=null,this._overwrittenProps=null,this._onUpdate=null,this._startAt=null,this._initted=this._active=this._notifyPluginsOfEnabled=!1,this._propLookup=this._targets?{}:[],this},r._enabled=function(t,e){if(a||n.wake(),t&&this._gc){var i,s=this._targets;if(s)for(i=s.length;--i>-1;)this._siblings[i]=Y(s[i],this,!0);else this._siblings=Y(this.target,this,!0)}return R.prototype._enabled.call(this,t,e),this._notifyPluginsOfEnabled&&this._firstPT?O._onPluginEvent(t?"_onEnable":"_onDisable",this):!1}
vendor: 4,954 bytes, lines 52510-52552
52510,O.to=function(t,e,i){return new O(t,e,i)},O.from=function(t,e,i){return i.runBackwards=!0,i.immediateRender=0!=i.immediateRender,new O(t,e,i)},O.fromTo=function(t,e,i,s){return s.startAt=i,s.immediateRender=0!=s.immediateRender&&0!=i.immediateRender,new O(t,e,s)},O.delayedCall=function(t,e,i,s,r){return new O(e,0,{delay:t,onComplete:e,onCompleteParams:i,onCompleteScope:s,onReverseComplete:e,onReverseCompleteParams:i,onReverseCompleteScope:s,immediateRender:!1,useFrames:r,overwrite:0})},O.set=function(t,e){return new O(t,0,e)},O.getTweensOf=function(t,e){if(null==t)return[];t="string"!=typeof t?t:O.selector(t)||t;var i,s,r,n;if((p(t)||D(t))&&"number"!=typeof t[0]){for(i=t.length,s=[];--i>-1;)s=s.concat(O.getTweensOf(t[i],e));for(i=s.length;--i>-1;)for(n=s[i],r=i;--r>-1;)n===s[r]&&s.splice(i,1)}else for(s=Y(t).concat(),i=s.length;--i>-1;)(s[i]._gc||e&&!s[i].isActive())&&s.splice(i,1);return s},O.killTweensOf=O.killDelayedCallsTo=function(t,e,i){"object"==typeof e&&(i=e,e=!1);for(var s=O.getTweensOf(t,e),r=s.length;--r>-1;)s[r]._kill(i,t)};var q=d("plugins.TweenPlugin",function(t,e){this._overwriteProps=(t||"").split(","),this._propName=this._overwriteProps[0],this._priority=e||0,this._super=q.prototype},!0);if(r=q.prototype,q.version="1.10.1",q.API=2,r._firstPT=null,r._addTween=function(t,e,i,s,r,n){var a,o;return null!=s&&(a="number"==typeof s||"="!==s.charAt(1)?Number(s)-i:parseInt(s.charAt(0)+"1",10)*Number(s.substr(2)))?(this._firstPT=o={_next:this._firstPT,t:t,p:e,s:i,c:a,f:"function"==typeof t[e],n:r||e,r:n},o._next&&(o._next._prev=o),o):void 0},r.setRatio=function(t){for(var e,i=this._firstPT,s=1e-6;i;)e=i.c*t+i.s,i.r?e=0|e+(e>0?.5:-.5):s>e&&e>-s&&(e=0),i.f?i.t[i.p](e):i.t[i.p]=e,i=i._next},r._kill=function(t){var e,i=this._overwriteProps,s=this._firstPT;if(null!=t[this._propName])this._overwriteProps=[];else for(e=i.length;--e>-1;)null!=t[i[e]]&&i.splice(e,1);for(;s;)null!=t[s.n]&&(s._next&&(s._next._prev=s._prev),s._prev?(s._prev._next=s._next,s._prev=null):this._firstPT===s&&(this._firstPT=s._next)),s=s._next;return!1},r._roundProps=function(t,e){for(var i=this._firstPT;i;)(t[this._propName]||null!=i.n&&t[i.n.split(this._propName+"_").join("")])&&(i.r=e),i=i._next},O._onPluginEvent=function(t,e){var i,s,r,n,a,o=e._firstPT;if("_onInitAllProps"===t){for(;o;){for(a=o._next,s=r;s&&s.pr>o.pr;)s=s._next;(o._prev=s?s._prev:n)?o._prev._next=o:r=o,(o._next=s)?s._prev=o:n=o,o=a}o=e._firstPT=r}for(;o;)o.pg&&"function"==typeof o.t[t]&&o.t[t]()&&(i=!0),o=o._next;return i},q.activate=function(t){for(var e=t.length;--e>-1;)t[e].API===q.API&&(E[(new t[e])._propName]=t[e]);return!0},m.plugin=function(t){if(!(t&&t.propName&&t.init&&t.API))throw"illegal plugin definition.";var e,i=t.propName,s=t.priority||0,r=t.overwriteProps,n={init:"_onInitTween",set:"setRatio",kill:"_kill",round:"_roundProps",initAll:"_onInitAllProps"},a=d("plugins."+i.charAt(0).toUpperCase()+i.substr(1)+"Plugin",function(){q.call(this,i,s),this._overwriteProps=r||[]},t.global===!0),o=a.prototype=new q(i);o.constructor=a,a.API=t.API;for(e in n)"function"==typeof t[e]&&(o[n[e]]=t[e]);return a.version=t.version,q.activate([a]),a},i=t._gsQueue){for(s=0;i.length>s;s++)i[s]();for(r in f)f[r].func||t.console.log("GSAP encountered missing dependency: com.greensock."+r)}a=!1}}(window);
52511/**
52512@file
52513JS for the WIS? (and what-is-dianetics.*) pages.
52514*/
52515
52516// don't clobber any settings in individual HTML files
52517if (!window.globalSlideshowOptionsOverride) {
52518    // always set circular autosliding
52519    globalSlideshowOptionsOverride = {
52520        circularClone: true,
52521    }
52522}
52523
52524/*
52525 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
52526 *
52527 * Uses the built in easing capabilities added In jQuery 1.1
52528 * to offer multiple easing options
52529 *
52530 * TERMS OF USE - jQuery Easing
52531 * 
52532 * Open source under the BSD License. 
52533 * 
52534 * Copyright © 2008 George McGinley Smith
52535 * All rights reserved.
52536 * 
52537 * Redistribution and use in source and binary forms, with or without modification, 
52538 * are permitted provided that the following conditions are met:
52539 * 
52540 * Redistributions of source code must retain the above copyright notice, this list of 
52541 * conditions and the following disclaimer.
52542 * Redistributions in binary form must reproduce the above copyright notice, this list 
52543 * of conditions and the following disclaimer in the documentation and/or other materials 
52544 * provided with the distribution.
52545 * 
52546 * Neither the name of the author nor the names of contributors may be used to endorse 
52547 * or promote products derived from this software without specific prior written permission.
52548 * 
52549 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
52550 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
52551 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
52552 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
vendor: 5,091 bytes, lines 52553-52698
52553 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
52554 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
52555 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
52556 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
52557 * OF THE POSSIBILITY OF SUCH DAMAGE. 
52558 *
52559*/
52560
52561// t: current time, b: begInnIng value, c: change In value, d: duration
52562jQuery.easing['jswing'] = jQuery.easing['swing'];
52563
52564jQuery.extend( jQuery.easing,
52565{
52566	def: 'easeOutQuad',
52567	swing: function (x, t, b, c, d) {
52568		//alert(jQuery.easing.default);
52569		return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
52570	},
52571	easeInQuad: function (x, t, b, c, d) {
52572		return c*(t/=d)*t + b;
52573	},
52574	easeOutQuad: function (x, t, b, c, d) {
52575		return -c *(t/=d)*(t-2) + b;
52576	},
52577	easeInOutQuad: function (x, t, b, c, d) {
52578		if ((t/=d/2) < 1) return c/2*t*t + b;
52579		return -c/2 * ((--t)*(t-2) - 1) + b;
52580	},
52581	easeInCubic: function (x, t, b, c, d) {
52582		return c*(t/=d)*t*t + b;
52583	},
52584	easeOutCubic: function (x, t, b, c, d) {
52585		return c*((t=t/d-1)*t*t + 1) + b;
52586	},
52587	easeInOutCubic: function (x, t, b, c, d) {
52588		if ((t/=d/2) < 1) return c/2*t*t*t + b;
52589		return c/2*((t-=2)*t*t + 2) + b;
52590	},
52591	easeInQuart: function (x, t, b, c, d) {
52592		return c*(t/=d)*t*t*t + b;
52593	},
52594	easeOutQuart: function (x, t, b, c, d) {
52595		return -c * ((t=t/d-1)*t*t*t - 1) + b;
52596	},
52597	easeInOutQuart: function (x, t, b, c, d) {
52598		if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
52599		return -c/2 * ((t-=2)*t*t*t - 2) + b;
52600	},
52601	easeInQuint: function (x, t, b, c, d) {
52602		return c*(t/=d)*t*t*t*t + b;
52603	},
52604	easeOutQuint: function (x, t, b, c, d) {
52605		return c*((t=t/d-1)*t*t*t*t + 1) + b;
52606	},
52607	easeInOutQuint: function (x, t, b, c, d) {
52608		if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
52609		return c/2*((t-=2)*t*t*t*t + 2) + b;
52610	},
52611	easeInSine: function (x, t, b, c, d) {
52612		return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
52613	},
52614	easeOutSine: function (x, t, b, c, d) {
52615		return c * Math.sin(t/d * (Math.PI/2)) + b;
52616	},
52617	easeInOutSine: function (x, t, b, c, d) {
52618		return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
52619	},
52620	easeInExpo: function (x, t, b, c, d) {
52621		return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
52622	},
52623	easeOutExpo: function (x, t, b, c, d) {
52624		return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
52625	},
52626	easeInOutExpo: function (x, t, b, c, d) {
52627		if (t==0) return b;
52628		if (t==d) return b+c;
52629		if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
52630		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
52631	},
52632	easeInCirc: function (x, t, b, c, d) {
52633		return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
52634	},
52635	easeOutCirc: function (x, t, b, c, d) {
52636		return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
52637	},
52638	easeInOutCirc: function (x, t, b, c, d) {
52639		if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
52640		return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
52641	},
52642	easeInElastic: function (x, t, b, c, d) {
52643		var s=1.70158;var p=0;var a=c;
52644		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
52645		if (a < Math.abs(c)) { a=c; var s=p/4; }
52646		else var s = p/(2*Math.PI) * Math.asin (c/a);
52647		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
52648	},
52649	easeOutElastic: function (x, t, b, c, d) {
52650		var s=1.70158;var p=0;var a=c;
52651		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
52652		if (a < Math.abs(c)) { a=c; var s=p/4; }
52653		else var s = p/(2*Math.PI) * Math.asin (c/a);
52654		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
52655	},
52656	easeInOutElastic: function (x, t, b, c, d) {
52657		var s=1.70158;var p=0;var a=c;
52658		if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
52659		if (a < Math.abs(c)) { a=c; var s=p/4; }
52660		else var s = p/(2*Math.PI) * Math.asin (c/a);
52661		if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
52662		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
52663	},
52664	easeInBack: function (x, t, b, c, d, s) {
52665		if (s == undefined) s = 1.70158;
52666		return c*(t/=d)*t*((s+1)*t - s) + b;
52667	},
52668	easeOutBack: function (x, t, b, c, d, s) {
52669		if (s == undefined) s = 1.70158;
52670		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
52671	},
52672	easeInOutBack: function (x, t, b, c, d, s) {
52673		if (s == undefined) s = 1.70158; 
52674		if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
52675		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
52676	},
52677	easeInBounce: function (x, t, b, c, d) {
52678		return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
52679	},
52680	easeOutBounce: function (x, t, b, c, d) {
52681		if ((t/=d) < (1/2.75)) {
52682			return c*(7.5625*t*t) + b;
52683		} else if (t < (2/2.75)) {
52684			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
52685		} else if (t < (2.5/2.75)) {
52686			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
52687		} else {
52688			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
52689		}
52690	},
52691	easeInOutBounce: function (x, t, b, c, d) {
52692		if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
52693		return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
52694	}
52695});
52696
52697/*
52698 *
52699 * TERMS OF USE - EASING EQUATIONS
52700 * 
52701 * Open source under the BSD License. 
52702 * 
52703 * Copyright © 2001 Robert Penner
52704 * All rights reserved.
52705 * 
52706 * Redistribution and use in source and binary forms, with or without modification, 
52707 * are permitted provided that the following conditions are met:
52708 * 
52709 * Redistributions of source code must retain the above copyright notice, this list of 
52710 * conditions and the following disclaimer.
52711 * Redistributions in binary form must reproduce the above copyright notice, this list 
52712 * of conditions and the following disclaimer in the documentation and/or other materials 
52713 * provided with the distribution.
52714 * 
52715 * Neither the name of the author nor the names of contributors may be used to endorse 
52716 * or promote products derived from this software without specific prior written permission.
52717 * 
52718 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
52719 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
52720 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
52721 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
52722 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
52723 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
52724 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
52725 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
52726 * OF THE POSSIBILITY OF SUCH DAMAGE. 
52727 *
52728 */

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.