` codec string with the standard
+ * `avc1.`
+ *
+ * @param {string} codec
+ * Codec string to translate
+ * @return {string}
+ * The translated codec string
+ */
+
+var translateLegacyCodec = function translateLegacyCodec(codec) {
+ if (!codec) {
+ return codec;
+ }
+
+ return codec.replace(/avc1\.(\d+)\.(\d+)/i, function (orig, profile, avcLevel) {
+ var profileHex = ('00' + Number(profile).toString(16)).slice(-2);
+ var avcLevelHex = ('00' + Number(avcLevel).toString(16)).slice(-2);
+ return 'avc1.' + profileHex + '00' + avcLevelHex;
+ });
+};
+/**
+ * Replace the old apple-style `avc1.
.
` codec strings with the standard
+ * `avc1.`
+ *
+ * @param {string[]} codecs
+ * An array of codec strings to translate
+ * @return {string[]}
+ * The translated array of codec strings
+ */
+
+var translateLegacyCodecs = function translateLegacyCodecs(codecs) {
+ return codecs.map(translateLegacyCodec);
+};
+/**
+ * Replace codecs in the codec string with the old apple-style `avc1.
.
` to the
+ * standard `avc1.`.
+ *
+ * @param {string} codecString
+ * The codec string
+ * @return {string}
+ * The codec string with old apple-style codecs replaced
+ *
+ * @private
+ */
+
+var mapLegacyAvcCodecs = function mapLegacyAvcCodecs(codecString) {
+ return codecString.replace(/avc1\.(\d+)\.(\d+)/i, function (match) {
+ return translateLegacyCodecs([match])[0];
+ });
+};
+/**
+ * @typedef {Object} ParsedCodecInfo
+ * @property {number} codecCount
+ * Number of codecs parsed
+ * @property {string} [videoCodec]
+ * Parsed video codec (if found)
+ * @property {string} [videoObjectTypeIndicator]
+ * Video object type indicator (if found)
+ * @property {string|null} audioProfile
+ * Audio profile
+ */
+
+/**
+ * Parses a codec string to retrieve the number of codecs specified, the video codec and
+ * object type indicator, and the audio profile.
+ *
+ * @param {string} [codecString]
+ * The codec string to parse
+ * @return {ParsedCodecInfo}
+ * Parsed codec info
+ */
+
+var parseCodecs = function parseCodecs(codecString) {
+ if (codecString === void 0) {
+ codecString = '';
+ }
+
+ var codecs = codecString.split(',');
+ var result = {};
+ var unknown = [];
+ codecs.forEach(function (codec) {
+ codec = codec.trim();
+ var codecType;
+ mediaTypes.forEach(function (name) {
+ var match = regexs[name].exec(codec.toLowerCase());
+
+ if (!match || match.length <= 1) {
+ return;
+ }
+
+ codecType = name; // maintain codec case
+
+ var type = codec.substring(0, match[1].length);
+ var details = codec.replace(type, '');
+ result[name] = {
+ type: type,
+ details: details
+ };
+ });
+
+ if (!codecType) {
+ unknown.push(codec);
+ }
+ });
+
+ if (unknown.length) {
+ result.unknown = unknown;
+ }
+
+ return result;
+};
+/**
+ * Returns a ParsedCodecInfo object for the default alternate audio playlist if there is
+ * a default alternate audio playlist for the provided audio group.
+ *
+ * @param {Object} master
+ * The master playlist
+ * @param {string} audioGroupId
+ * ID of the audio group for which to find the default codec info
+ * @return {ParsedCodecInfo}
+ * Parsed codec info
+ */
+
+var codecsFromDefault = function codecsFromDefault(master, audioGroupId) {
+ if (!master.mediaGroups.AUDIO || !audioGroupId) {
+ return null;
+ }
+
+ var audioGroup = master.mediaGroups.AUDIO[audioGroupId];
+
+ if (!audioGroup) {
+ return null;
+ }
+
+ for (var name in audioGroup) {
+ var audioType = audioGroup[name];
+
+ if (audioType.default && audioType.playlists) {
+ // codec should be the same for all playlists within the audio type
+ return parseCodecs(audioType.playlists[0].attributes.CODECS);
+ }
+ }
+
+ return null;
+};
+var isVideoCodec = function isVideoCodec(codec) {
+ if (codec === void 0) {
+ codec = '';
+ }
+
+ return regexs.video.test(codec.trim().toLowerCase());
+};
+var isAudioCodec = function isAudioCodec(codec) {
+ if (codec === void 0) {
+ codec = '';
+ }
+
+ return regexs.audio.test(codec.trim().toLowerCase());
+};
+var isTextCodec = function isTextCodec(codec) {
+ if (codec === void 0) {
+ codec = '';
+ }
+
+ return regexs.text.test(codec.trim().toLowerCase());
+};
+var getMimeForCodec = function getMimeForCodec(codecString) {
+ if (!codecString || typeof codecString !== 'string') {
+ return;
+ }
+
+ var codecs = codecString.toLowerCase().split(',').map(function (c) {
+ return translateLegacyCodec(c.trim());
+ }); // default to video type
+
+ var type = 'video'; // only change to audio type if the only codec we have is
+ // audio
+
+ if (codecs.length === 1 && isAudioCodec(codecs[0])) {
+ type = 'audio';
+ } else if (codecs.length === 1 && isTextCodec(codecs[0])) {
+ // text uses application/ for now
+ type = 'application';
+ } // default the container to mp4
+
+
+ var container = 'mp4'; // every codec must be able to go into the container
+ // for that container to be the correct one
+
+ if (codecs.every(function (c) {
+ return regexs.mp4.test(c);
+ })) {
+ container = 'mp4';
+ } else if (codecs.every(function (c) {
+ return regexs.webm.test(c);
+ })) {
+ container = 'webm';
+ } else if (codecs.every(function (c) {
+ return regexs.ogg.test(c);
+ })) {
+ container = 'ogg';
+ }
+
+ return type + "/" + container + ";codecs=\"" + codecString + "\"";
+};
+var browserSupportsCodec = function browserSupportsCodec(codecString) {
+ if (codecString === void 0) {
+ codecString = '';
+ }
+
+ return window.MediaSource && window.MediaSource.isTypeSupported && window.MediaSource.isTypeSupported(getMimeForCodec(codecString)) || false;
+};
+var muxerSupportsCodec = function muxerSupportsCodec(codecString) {
+ if (codecString === void 0) {
+ codecString = '';
+ }
+
+ return codecString.toLowerCase().split(',').every(function (codec) {
+ codec = codec.trim(); // any match is supported.
+
+ for (var i = 0; i < upperMediaTypes.length; i++) {
+ var type = upperMediaTypes[i];
+
+ if (regexs["muxer" + type].test(codec)) {
+ return true;
+ }
+ }
+
+ return false;
+ });
+};
+var DEFAULT_AUDIO_CODEC = 'mp4a.40.2';
+var DEFAULT_VIDEO_CODEC = 'avc1.4d400d';
+
+exports.DEFAULT_AUDIO_CODEC = DEFAULT_AUDIO_CODEC;
+exports.DEFAULT_VIDEO_CODEC = DEFAULT_VIDEO_CODEC;
+exports.browserSupportsCodec = browserSupportsCodec;
+exports.codecsFromDefault = codecsFromDefault;
+exports.getMimeForCodec = getMimeForCodec;
+exports.isAudioCodec = isAudioCodec;
+exports.isTextCodec = isTextCodec;
+exports.isVideoCodec = isVideoCodec;
+exports.mapLegacyAvcCodecs = mapLegacyAvcCodecs;
+exports.muxerSupportsCodec = muxerSupportsCodec;
+exports.parseCodecs = parseCodecs;
+exports.translateLegacyCodec = translateLegacyCodec;
+exports.translateLegacyCodecs = translateLegacyCodecs;
+
+
+/***/ }),
+
+/***/ "./node_modules/@videojs/vhs-utils/dist/containers.js":
+/*!************************************************************!*\
+ !*** ./node_modules/@videojs/vhs-utils/dist/containers.js ***!
+ \************************************************************/
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+/*! @name @videojs/vhs-utils @version 2.3.0 @license MIT */
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+
+var toUint8 = function toUint8(bytes) {
+ return bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes && bytes.buffer || bytes, bytes && bytes.byteOffset || 0, bytes && bytes.byteLength || 0);
+};
+var bytesToString = function bytesToString(bytes) {
+ if (!bytes) {
+ return '';
+ }
+
+ bytes = Array.prototype.slice.call(bytes);
+ var string = String.fromCharCode.apply(null, toUint8(bytes));
+
+ try {
+ return decodeURIComponent(escape(string));
+ } catch (e) {// if decodeURIComponent/escape fails, we are dealing with partial
+ // or full non string data. Just return the potentially garbled string.
+ }
+
+ return string;
+};
+
+var id3Size = function id3Size(bytes, offset) {
+ if (offset === void 0) {
+ offset = 0;
+ }
+
+ bytes = toUint8(bytes);
+ var returnSize = bytes[offset + 6] << 21 | bytes[offset + 7] << 14 | bytes[offset + 8] << 7 | bytes[offset + 9];
+ var flags = bytes[offset + 5];
+ var footerPresent = (flags & 16) >> 4;
+
+ if (footerPresent) {
+ return returnSize + 20;
+ }
+
+ return returnSize + 10;
+};
+var getId3Offset = function getId3Offset(bytes, offset) {
+ if (offset === void 0) {
+ offset = 0;
+ }
+
+ bytes = toUint8(bytes);
+
+ if (bytes.length - offset < 10 || bytesToString(bytes.subarray(offset, offset + 3)) !== 'ID3') {
+ return offset;
+ }
+
+ offset += id3Size(bytes, offset); // recursive check for id3 tags as some files
+ // have multiple ID3 tag sections even though
+ // they should not.
+
+ return getId3Offset(bytes, offset);
+};
+var isLikely = {
+ aac: function aac(bytes) {
+ var offset = getId3Offset(bytes);
+ return bytes.length >= offset + 2 && (bytes[offset] & 0xFF) === 0xFF && (bytes[offset + 1] & 0xE0) === 0xE0 && (bytes[offset + 1] & 0x16) === 0x10;
+ },
+ mp3: function mp3(bytes) {
+ var offset = getId3Offset(bytes);
+ return bytes.length >= offset + 2 && (bytes[offset] & 0xFF) === 0xFF && (bytes[offset + 1] & 0xE0) === 0xE0 && (bytes[offset + 1] & 0x06) === 0x02;
+ },
+ webm: function webm(bytes) {
+ return bytes.length >= 4 && (bytes[0] & 0xFF) === 0x1A && (bytes[1] & 0xFF) === 0x45 && (bytes[2] & 0xFF) === 0xDF && (bytes[3] & 0xFF) === 0xA3;
+ },
+ mp4: function mp4(bytes) {
+ return bytes.length >= 8 && /^(f|s)typ$/.test(bytesToString(bytes.subarray(4, 8))) && // not 3gp data
+ !/^ftyp3g$/.test(bytesToString(bytes.subarray(4, 10)));
+ },
+ '3gp': function gp(bytes) {
+ return bytes.length >= 10 && /^ftyp3g$/.test(bytesToString(bytes.subarray(4, 10)));
+ },
+ ts: function ts(bytes) {
+ if (bytes.length < 189 && bytes.length >= 1) {
+ return bytes[0] === 0x47;
+ }
+
+ var i = 0; // check the first 376 bytes for two matching sync bytes
+
+ while (i + 188 < bytes.length && i < 188) {
+ if (bytes[i] === 0x47 && bytes[i + 188] === 0x47) {
+ return true;
+ }
+
+ i += 1;
+ }
+
+ return false;
+ },
+ flac: function flac(bytes) {
+ return bytes.length >= 4 && /^fLaC$/.test(bytesToString(bytes.subarray(0, 4)));
+ },
+ ogg: function ogg(bytes) {
+ return bytes.length >= 4 && /^OggS$/.test(bytesToString(bytes.subarray(0, 4)));
+ }
+}; // get all the isLikely functions
+// but make sure 'ts' is at the bottom
+// as it is the least specific
+
+var isLikelyTypes = Object.keys(isLikely) // remove ts
+.filter(function (t) {
+ return t !== 'ts';
+}) // add it back to the bottom
+.concat('ts'); // make sure we are dealing with uint8 data.
+
+isLikelyTypes.forEach(function (type) {
+ var isLikelyFn = isLikely[type];
+
+ isLikely[type] = function (bytes) {
+ return isLikelyFn(toUint8(bytes));
+ };
+}); // A useful list of file signatures can be found here
+// https://en.wikipedia.org/wiki/List_of_file_signatures
+
+var detectContainerForBytes = function detectContainerForBytes(bytes) {
+ bytes = toUint8(bytes);
+
+ for (var i = 0; i < isLikelyTypes.length; i++) {
+ var type = isLikelyTypes[i];
+
+ if (isLikely[type](bytes)) {
+ return type;
+ }
+ }
+
+ return '';
+}; // fmp4 is not a container
+
+var isLikelyFmp4MediaSegment = function isLikelyFmp4MediaSegment(bytes) {
+ bytes = toUint8(bytes);
+ var i = 0;
+
+ while (i < bytes.length) {
+ var size = (bytes[i] << 24 | bytes[i + 1] << 16 | bytes[i + 2] << 8 | bytes[i + 3]) >>> 0;
+ var type = bytesToString(bytes.subarray(i + 4, i + 8));
+
+ if (type === 'moof') {
+ return true;
+ }
+
+ if (size === 0 || size + i > bytes.length) {
+ i = bytes.length;
+ } else {
+ i += size;
+ }
+ }
+
+ return false;
+};
+
+exports.detectContainerForBytes = detectContainerForBytes;
+exports.getId3Offset = getId3Offset;
+exports.id3Size = id3Size;
+exports.isLikely = isLikely;
+exports.isLikelyFmp4MediaSegment = isLikelyFmp4MediaSegment;
+
+
+/***/ }),
+
+/***/ "./node_modules/@videojs/vhs-utils/dist/decode-b64-to-uint8-array.js":
+/*!***************************************************************************!*\
+ !*** ./node_modules/@videojs/vhs-utils/dist/decode-b64-to-uint8-array.js ***!
+ \***************************************************************************/
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+"use strict";
+/* provided dependency */ var Buffer = __webpack_require__(/*! buffer */ "./node_modules/buffer/index.js")["Buffer"];
+/*! @name @videojs/vhs-utils @version 2.3.0 @license MIT */
+
+
+function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
+
+var window = _interopDefault(__webpack_require__(/*! global/window */ "./node_modules/global/window.js"));
+
+var atob = function atob(s) {
+ return window.atob ? window.atob(s) : Buffer.from(s, 'base64').toString('binary');
+};
+
+function decodeB64ToUint8Array(b64Text) {
+ var decodedString = atob(b64Text);
+ var array = new Uint8Array(decodedString.length);
+
+ for (var i = 0; i < decodedString.length; i++) {
+ array[i] = decodedString.charCodeAt(i);
+ }
+
+ return array;
+}
+
+module.exports = decodeB64ToUint8Array;
+
+
+/***/ }),
+
+/***/ "./node_modules/@videojs/vhs-utils/dist/media-types.js":
+/*!*************************************************************!*\
+ !*** ./node_modules/@videojs/vhs-utils/dist/media-types.js ***!
+ \*************************************************************/
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+/*! @name @videojs/vhs-utils @version 2.3.0 @license MIT */
+
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+
+var MPEGURL_REGEX = /^(audio|video|application)\/(x-|vnd\.apple\.)?mpegurl/i;
+var DASH_REGEX = /^application\/dash\+xml/i;
+/**
+ * Returns a string that describes the type of source based on a video source object's
+ * media type.
+ *
+ * @see {@link https://dev.w3.org/html5/pf-summary/video.html#dom-source-type|Source Type}
+ *
+ * @param {string} type
+ * Video source object media type
+ * @return {('hls'|'dash'|'vhs-json'|null)}
+ * VHS source type string
+ */
+
+var simpleTypeFromSourceType = function simpleTypeFromSourceType(type) {
+ if (MPEGURL_REGEX.test(type)) {
+ return 'hls';
+ }
+
+ if (DASH_REGEX.test(type)) {
+ return 'dash';
+ } // Denotes the special case of a manifest object passed to http-streaming instead of a
+ // source URL.
+ //
+ // See https://en.wikipedia.org/wiki/Media_type for details on specifying media types.
+ //
+ // In this case, vnd stands for vendor, video.js for the organization, VHS for this
+ // project, and the +json suffix identifies the structure of the media type.
+
+
+ if (type === 'application/vnd.videojs.vhs+json') {
+ return 'vhs-json';
+ }
+
+ return null;
+};
+
+exports.simpleTypeFromSourceType = simpleTypeFromSourceType;
+
+
+/***/ }),
+
+/***/ "./node_modules/@videojs/vhs-utils/dist/resolve-url.js":
+/*!*************************************************************!*\
+ !*** ./node_modules/@videojs/vhs-utils/dist/resolve-url.js ***!
+ \*************************************************************/
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+"use strict";
+/*! @name @videojs/vhs-utils @version 2.3.0 @license MIT */
+
+
+function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
+
+var URLToolkit = _interopDefault(__webpack_require__(/*! url-toolkit */ "./node_modules/url-toolkit/src/url-toolkit.js"));
+var window = _interopDefault(__webpack_require__(/*! global/window */ "./node_modules/global/window.js"));
+
+var resolveUrl = function resolveUrl(baseUrl, relativeUrl) {
+ // return early if we don't need to resolve
+ if (/^[a-z]+:/i.test(relativeUrl)) {
+ return relativeUrl;
+ } // if the base URL is relative then combine with the current location
+
+
+ if (!/\/\//i.test(baseUrl)) {
+ baseUrl = URLToolkit.buildAbsoluteURL(window.location && window.location.href || '', baseUrl);
+ }
+
+ return URLToolkit.buildAbsoluteURL(baseUrl, relativeUrl);
+};
+
+module.exports = resolveUrl;
+
+
+/***/ }),
+
+/***/ "./node_modules/@videojs/vhs-utils/dist/stream.js":
+/*!********************************************************!*\
+ !*** ./node_modules/@videojs/vhs-utils/dist/stream.js ***!
+ \********************************************************/
+/***/ ((module) => {
+
+"use strict";
+/*! @name @videojs/vhs-utils @version 2.3.0 @license MIT */
+
+
+/**
+ * @file stream.js
+ */
+
+/**
+ * A lightweight readable stream implemention that handles event dispatching.
+ *
+ * @class Stream
+ */
+var Stream =
+/*#__PURE__*/
+function () {
+ function Stream() {
+ this.listeners = {};
+ }
+ /**
+ * Add a listener for a specified event type.
+ *
+ * @param {string} type the event name
+ * @param {Function} listener the callback to be invoked when an event of
+ * the specified type occurs
+ */
+
+
+ var _proto = Stream.prototype;
+
+ _proto.on = function on(type, listener) {
+ if (!this.listeners[type]) {
+ this.listeners[type] = [];
+ }
+
+ this.listeners[type].push(listener);
+ }
+ /**
+ * Remove a listener for a specified event type.
+ *
+ * @param {string} type the event name
+ * @param {Function} listener a function previously registered for this
+ * type of event through `on`
+ * @return {boolean} if we could turn it off or not
+ */
+ ;
+
+ _proto.off = function off(type, listener) {
+ if (!this.listeners[type]) {
+ return false;
+ }
+
+ var index = this.listeners[type].indexOf(listener); // TODO: which is better?
+ // In Video.js we slice listener functions
+ // on trigger so that it does not mess up the order
+ // while we loop through.
+ //
+ // Here we slice on off so that the loop in trigger
+ // can continue using it's old reference to loop without
+ // messing up the order.
+
+ this.listeners[type] = this.listeners[type].slice(0);
+ this.listeners[type].splice(index, 1);
+ return index > -1;
+ }
+ /**
+ * Trigger an event of the specified type on this stream. Any additional
+ * arguments to this function are passed as parameters to event listeners.
+ *
+ * @param {string} type the event name
+ */
+ ;
+
+ _proto.trigger = function trigger(type) {
+ var callbacks = this.listeners[type];
+
+ if (!callbacks) {
+ return;
+ } // Slicing the arguments on every invocation of this method
+ // can add a significant amount of overhead. Avoid the
+ // intermediate object creation for the common case of a
+ // single callback argument
+
+
+ if (arguments.length === 2) {
+ var length = callbacks.length;
+
+ for (var i = 0; i < length; ++i) {
+ callbacks[i].call(this, arguments[1]);
+ }
+ } else {
+ var args = Array.prototype.slice.call(arguments, 1);
+ var _length = callbacks.length;
+
+ for (var _i = 0; _i < _length; ++_i) {
+ callbacks[_i].apply(this, args);
+ }
+ }
+ }
+ /**
+ * Destroys the stream and cleans up.
+ */
+ ;
+
+ _proto.dispose = function dispose() {
+ this.listeners = {};
+ }
+ /**
+ * Forwards all `data` events on this stream to the destination stream. The
+ * destination stream should provide a method `push` to receive the data
+ * events as they arrive.
+ *
+ * @param {Stream} destination the stream that will receive all `data` events
+ * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
+ */
+ ;
+
+ _proto.pipe = function pipe(destination) {
+ this.on('data', function (data) {
+ destination.push(data);
+ });
+ };
+
+ return Stream;
+}();
+
+module.exports = Stream;
+
+
+/***/ }),
+
+/***/ "./node_modules/@videojs/xhr/index.js":
+/*!********************************************!*\
+ !*** ./node_modules/@videojs/xhr/index.js ***!
+ \********************************************/
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+"use strict";
+
+var window = __webpack_require__(/*! global/window */ "./node_modules/global/window.js")
+var _extends = __webpack_require__(/*! @babel/runtime/helpers/extends */ "./node_modules/@babel/runtime/helpers/extends.js");
+var isFunction = __webpack_require__(/*! is-function */ "./node_modules/is-function/index.js");
+
+/**
+ * @license
+ * slighly modified parse-headers 2.0.2
+ * Copyright (c) 2014 David Björklund
+ * Available under the MIT license
+ *
+ */
+
+var parseHeaders = function(headers) {
+ var result = {};
+
+ if (!headers) {
+ return result;
+ }
+
+ headers.trim().split('\n').forEach(function(row) {
+ var index = row.indexOf(':');
+ var key = row.slice(0, index).trim().toLowerCase();
+ var value = row.slice(index + 1).trim();
+
+ if (typeof(result[key]) === 'undefined') {
+ result[key] = value
+ } else if (Array.isArray(result[key])) {
+ result[key].push(value)
+ } else {
+ result[key] = [ result[key], value ]
+ }
+ });
+
+ return result;
+};
+
+module.exports = createXHR
+// Allow use of default import syntax in TypeScript
+module.exports.default = createXHR;
+createXHR.XMLHttpRequest = window.XMLHttpRequest || noop
+createXHR.XDomainRequest = "withCredentials" in (new createXHR.XMLHttpRequest()) ? createXHR.XMLHttpRequest : window.XDomainRequest
+
+forEachArray(["get", "put", "post", "patch", "head", "delete"], function(method) {
+ createXHR[method === "delete" ? "del" : method] = function(uri, options, callback) {
+ options = initParams(uri, options, callback)
+ options.method = method.toUpperCase()
+ return _createXHR(options)
+ }
+})
+
+function forEachArray(array, iterator) {
+ for (var i = 0; i < array.length; i++) {
+ iterator(array[i])
+ }
+}
+
+function isEmpty(obj){
+ for(var i in obj){
+ if(obj.hasOwnProperty(i)) return false
+ }
+ return true
+}
+
+function initParams(uri, options, callback) {
+ var params = uri
+
+ if (isFunction(options)) {
+ callback = options
+ if (typeof uri === "string") {
+ params = {uri:uri}
+ }
+ } else {
+ params = _extends({}, options, {uri: uri})
+ }
+
+ params.callback = callback
+ return params
+}
+
+function createXHR(uri, options, callback) {
+ options = initParams(uri, options, callback)
+ return _createXHR(options)
+}
+
+function _createXHR(options) {
+ if(typeof options.callback === "undefined"){
+ throw new Error("callback argument missing")
+ }
+
+ var called = false
+ var callback = function cbOnce(err, response, body){
+ if(!called){
+ called = true
+ options.callback(err, response, body)
+ }
+ }
+
+ function readystatechange() {
+ if (xhr.readyState === 4) {
+ setTimeout(loadFunc, 0)
+ }
+ }
+
+ function getBody() {
+ // Chrome with requestType=blob throws errors arround when even testing access to responseText
+ var body = undefined
+
+ if (xhr.response) {
+ body = xhr.response
+ } else {
+ body = xhr.responseText || getXml(xhr)
+ }
+
+ if (isJson) {
+ try {
+ body = JSON.parse(body)
+ } catch (e) {}
+ }
+
+ return body
+ }
+
+ function errorFunc(evt) {
+ clearTimeout(timeoutTimer)
+ if(!(evt instanceof Error)){
+ evt = new Error("" + (evt || "Unknown XMLHttpRequest Error") )
+ }
+ evt.statusCode = 0
+ return callback(evt, failureResponse)
+ }
+
+ // will load the data & process the response in a special response object
+ function loadFunc() {
+ if (aborted) return
+ var status
+ clearTimeout(timeoutTimer)
+ if(options.useXDR && xhr.status===undefined) {
+ //IE8 CORS GET successful response doesn't have a status field, but body is fine
+ status = 200
+ } else {
+ status = (xhr.status === 1223 ? 204 : xhr.status)
+ }
+ var response = failureResponse
+ var err = null
+
+ if (status !== 0){
+ response = {
+ body: getBody(),
+ statusCode: status,
+ method: method,
+ headers: {},
+ url: uri,
+ rawRequest: xhr
+ }
+ if(xhr.getAllResponseHeaders){ //remember xhr can in fact be XDR for CORS in IE
+ response.headers = parseHeaders(xhr.getAllResponseHeaders())
+ }
+ } else {
+ err = new Error("Internal XMLHttpRequest Error")
+ }
+ return callback(err, response, response.body)
+ }
+
+ var xhr = options.xhr || null
+
+ if (!xhr) {
+ if (options.cors || options.useXDR) {
+ xhr = new createXHR.XDomainRequest()
+ }else{
+ xhr = new createXHR.XMLHttpRequest()
+ }
+ }
+
+ var key
+ var aborted
+ var uri = xhr.url = options.uri || options.url
+ var method = xhr.method = options.method || "GET"
+ var body = options.body || options.data
+ var headers = xhr.headers = options.headers || {}
+ var sync = !!options.sync
+ var isJson = false
+ var timeoutTimer
+ var failureResponse = {
+ body: undefined,
+ headers: {},
+ statusCode: 0,
+ method: method,
+ url: uri,
+ rawRequest: xhr
+ }
+
+ if ("json" in options && options.json !== false) {
+ isJson = true
+ headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json") //Don't override existing accept header declared by user
+ if (method !== "GET" && method !== "HEAD") {
+ headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json") //Don't override existing accept header declared by user
+ body = JSON.stringify(options.json === true ? body : options.json)
+ }
+ }
+
+ xhr.onreadystatechange = readystatechange
+ xhr.onload = loadFunc
+ xhr.onerror = errorFunc
+ // IE9 must have onprogress be set to a unique function.
+ xhr.onprogress = function () {
+ // IE must die
+ }
+ xhr.onabort = function(){
+ aborted = true;
+ }
+ xhr.ontimeout = errorFunc
+ xhr.open(method, uri, !sync, options.username, options.password)
+ //has to be after open
+ if(!sync) {
+ xhr.withCredentials = !!options.withCredentials
+ }
+ // Cannot set timeout with sync request
+ // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly
+ // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent
+ if (!sync && options.timeout > 0 ) {
+ timeoutTimer = setTimeout(function(){
+ if (aborted) return
+ aborted = true//IE9 may still call readystatechange
+ xhr.abort("timeout")
+ var e = new Error("XMLHttpRequest timeout")
+ e.code = "ETIMEDOUT"
+ errorFunc(e)
+ }, options.timeout )
+ }
+
+ if (xhr.setRequestHeader) {
+ for(key in headers){
+ if(headers.hasOwnProperty(key)){
+ xhr.setRequestHeader(key, headers[key])
+ }
+ }
+ } else if (options.headers && !isEmpty(options.headers)) {
+ throw new Error("Headers cannot be set on an XDomainRequest object")
+ }
+
+ if ("responseType" in options) {
+ xhr.responseType = options.responseType
+ }
+
+ if ("beforeSend" in options &&
+ typeof options.beforeSend === "function"
+ ) {
+ options.beforeSend(xhr)
+ }
+
+ // Microsoft Edge browser sends "undefined" when send is called with undefined value.
+ // XMLHttpRequest spec says to pass null as body to indicate no body
+ // See https://github.com/naugtur/xhr/issues/100.
+ xhr.send(body || null)
+
+ return xhr
+
+
+}
+
+function getXml(xhr) {
+ // xhr.responseXML will throw Exception "InvalidStateError" or "DOMException"
+ // See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseXML.
+ try {
+ if (xhr.responseType === "document") {
+ return xhr.responseXML
+ }
+ var firefoxBugTakenEffect = xhr.responseXML && xhr.responseXML.documentElement.nodeName === "parsererror"
+ if (xhr.responseType === "" && !firefoxBugTakenEffect) {
+ return xhr.responseXML
+ }
+ } catch (e) {}
+
+ return null
+}
+
+function noop() {}
+
+
+/***/ }),
+
+/***/ "./resources/js/app.js":
+/*!*****************************!*\
+ !*** ./resources/js/app.js ***!
+ \*****************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ "./node_modules/video.js/dist/video.es.js");
+
+
+/***/ }),
+
+/***/ "./node_modules/base64-js/index.js":
+/*!*****************************************!*\
+ !*** ./node_modules/base64-js/index.js ***!
+ \*****************************************/
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+
+exports.byteLength = byteLength
+exports.toByteArray = toByteArray
+exports.fromByteArray = fromByteArray
+
+var lookup = []
+var revLookup = []
+var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
+
+var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+for (var i = 0, len = code.length; i < len; ++i) {
+ lookup[i] = code[i]
+ revLookup[code.charCodeAt(i)] = i
+}
+
+// Support decoding URL-safe base64 strings, as Node.js does.
+// See: https://en.wikipedia.org/wiki/Base64#URL_applications
+revLookup['-'.charCodeAt(0)] = 62
+revLookup['_'.charCodeAt(0)] = 63
+
+function getLens (b64) {
+ var len = b64.length
+
+ if (len % 4 > 0) {
+ throw new Error('Invalid string. Length must be a multiple of 4')
+ }
+
+ // Trim off extra bytes after placeholder bytes are found
+ // See: https://github.com/beatgammit/base64-js/issues/42
+ var validLen = b64.indexOf('=')
+ if (validLen === -1) validLen = len
+
+ var placeHoldersLen = validLen === len
+ ? 0
+ : 4 - (validLen % 4)
+
+ return [validLen, placeHoldersLen]
+}
+
+// base64 is 4/3 + up to two characters of the original data
+function byteLength (b64) {
+ var lens = getLens(b64)
+ var validLen = lens[0]
+ var placeHoldersLen = lens[1]
+ return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
+}
+
+function _byteLength (b64, validLen, placeHoldersLen) {
+ return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
+}
+
+function toByteArray (b64) {
+ var tmp
+ var lens = getLens(b64)
+ var validLen = lens[0]
+ var placeHoldersLen = lens[1]
+
+ var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))
+
+ var curByte = 0
+
+ // if there are placeholders, only get up to the last complete 4 chars
+ var len = placeHoldersLen > 0
+ ? validLen - 4
+ : validLen
+
+ var i
+ for (i = 0; i < len; i += 4) {
+ tmp =
+ (revLookup[b64.charCodeAt(i)] << 18) |
+ (revLookup[b64.charCodeAt(i + 1)] << 12) |
+ (revLookup[b64.charCodeAt(i + 2)] << 6) |
+ revLookup[b64.charCodeAt(i + 3)]
+ arr[curByte++] = (tmp >> 16) & 0xFF
+ arr[curByte++] = (tmp >> 8) & 0xFF
+ arr[curByte++] = tmp & 0xFF
+ }
+
+ if (placeHoldersLen === 2) {
+ tmp =
+ (revLookup[b64.charCodeAt(i)] << 2) |
+ (revLookup[b64.charCodeAt(i + 1)] >> 4)
+ arr[curByte++] = tmp & 0xFF
+ }
+
+ if (placeHoldersLen === 1) {
+ tmp =
+ (revLookup[b64.charCodeAt(i)] << 10) |
+ (revLookup[b64.charCodeAt(i + 1)] << 4) |
+ (revLookup[b64.charCodeAt(i + 2)] >> 2)
+ arr[curByte++] = (tmp >> 8) & 0xFF
+ arr[curByte++] = tmp & 0xFF
+ }
+
+ return arr
+}
+
+function tripletToBase64 (num) {
+ return lookup[num >> 18 & 0x3F] +
+ lookup[num >> 12 & 0x3F] +
+ lookup[num >> 6 & 0x3F] +
+ lookup[num & 0x3F]
+}
+
+function encodeChunk (uint8, start, end) {
+ var tmp
+ var output = []
+ for (var i = start; i < end; i += 3) {
+ tmp =
+ ((uint8[i] << 16) & 0xFF0000) +
+ ((uint8[i + 1] << 8) & 0xFF00) +
+ (uint8[i + 2] & 0xFF)
+ output.push(tripletToBase64(tmp))
+ }
+ return output.join('')
+}
+
+function fromByteArray (uint8) {
+ var tmp
+ var len = uint8.length
+ var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
+ var parts = []
+ var maxChunkLength = 16383 // must be multiple of 3
+
+ // go through the array every three bytes, we'll deal with trailing stuff later
+ for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
+ parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
+ }
+
+ // pad the end with zeros, but make sure to not forget the extra bytes
+ if (extraBytes === 1) {
+ tmp = uint8[len - 1]
+ parts.push(
+ lookup[tmp >> 2] +
+ lookup[(tmp << 4) & 0x3F] +
+ '=='
+ )
+ } else if (extraBytes === 2) {
+ tmp = (uint8[len - 2] << 8) + uint8[len - 1]
+ parts.push(
+ lookup[tmp >> 10] +
+ lookup[(tmp >> 4) & 0x3F] +
+ lookup[(tmp << 2) & 0x3F] +
+ '='
+ )
+ }
+
+ return parts.join('')
+}
+
+
+/***/ }),
+
+/***/ "./node_modules/buffer/index.js":
+/*!**************************************!*\
+ !*** ./node_modules/buffer/index.js ***!
+ \**************************************/
+/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
+
+"use strict";
+/*!
+ * The buffer module from node.js, for the browser.
+ *
+ * @author Feross Aboukhadijeh
+ * @license MIT
+ */
+/* eslint-disable no-proto */
+
+
+
+var base64 = __webpack_require__(/*! base64-js */ "./node_modules/base64-js/index.js")
+var ieee754 = __webpack_require__(/*! ieee754 */ "./node_modules/ieee754/index.js")
+var isArray = __webpack_require__(/*! isarray */ "./node_modules/isarray/index.js")
+
+exports.Buffer = Buffer
+exports.SlowBuffer = SlowBuffer
+exports.INSPECT_MAX_BYTES = 50
+
+/**
+ * If `Buffer.TYPED_ARRAY_SUPPORT`:
+ * === true Use Uint8Array implementation (fastest)
+ * === false Use Object implementation (most compatible, even IE6)
+ *
+ * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
+ * Opera 11.6+, iOS 4.2+.
+ *
+ * Due to various browser bugs, sometimes the Object implementation will be used even
+ * when the browser supports typed arrays.
+ *
+ * Note:
+ *
+ * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,
+ * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
+ *
+ * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
+ *
+ * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
+ * incorrect length in some situations.
+
+ * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they
+ * get the Object implementation, which is slower but behaves correctly.
+ */
+Buffer.TYPED_ARRAY_SUPPORT = __webpack_require__.g.TYPED_ARRAY_SUPPORT !== undefined
+ ? __webpack_require__.g.TYPED_ARRAY_SUPPORT
+ : typedArraySupport()
+
+/*
+ * Export kMaxLength after typed array support is determined.
+ */
+exports.kMaxLength = kMaxLength()
+
+function typedArraySupport () {
+ try {
+ var arr = new Uint8Array(1)
+ arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}
+ return arr.foo() === 42 && // typed array instances can be augmented
+ typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
+ arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
+ } catch (e) {
+ return false
+ }
+}
+
+function kMaxLength () {
+ return Buffer.TYPED_ARRAY_SUPPORT
+ ? 0x7fffffff
+ : 0x3fffffff
+}
+
+function createBuffer (that, length) {
+ if (kMaxLength() < length) {
+ throw new RangeError('Invalid typed array length')
+ }
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ // Return an augmented `Uint8Array` instance, for best performance
+ that = new Uint8Array(length)
+ that.__proto__ = Buffer.prototype
+ } else {
+ // Fallback: Return an object instance of the Buffer class
+ if (that === null) {
+ that = new Buffer(length)
+ }
+ that.length = length
+ }
+
+ return that
+}
+
+/**
+ * The Buffer constructor returns instances of `Uint8Array` that have their
+ * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
+ * `Uint8Array`, so the returned instances will have all the node `Buffer` methods
+ * and the `Uint8Array` methods. Square bracket notation works as expected -- it
+ * returns a single octet.
+ *
+ * The `Uint8Array` prototype remains unmodified.
+ */
+
+function Buffer (arg, encodingOrOffset, length) {
+ if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {
+ return new Buffer(arg, encodingOrOffset, length)
+ }
+
+ // Common case.
+ if (typeof arg === 'number') {
+ if (typeof encodingOrOffset === 'string') {
+ throw new Error(
+ 'If encoding is specified then the first argument must be a string'
+ )
+ }
+ return allocUnsafe(this, arg)
+ }
+ return from(this, arg, encodingOrOffset, length)
+}
+
+Buffer.poolSize = 8192 // not used by this implementation
+
+// TODO: Legacy, not needed anymore. Remove in next major version.
+Buffer._augment = function (arr) {
+ arr.__proto__ = Buffer.prototype
+ return arr
+}
+
+function from (that, value, encodingOrOffset, length) {
+ if (typeof value === 'number') {
+ throw new TypeError('"value" argument must not be a number')
+ }
+
+ if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
+ return fromArrayBuffer(that, value, encodingOrOffset, length)
+ }
+
+ if (typeof value === 'string') {
+ return fromString(that, value, encodingOrOffset)
+ }
+
+ return fromObject(that, value)
+}
+
+/**
+ * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
+ * if value is a number.
+ * Buffer.from(str[, encoding])
+ * Buffer.from(array)
+ * Buffer.from(buffer)
+ * Buffer.from(arrayBuffer[, byteOffset[, length]])
+ **/
+Buffer.from = function (value, encodingOrOffset, length) {
+ return from(null, value, encodingOrOffset, length)
+}
+
+if (Buffer.TYPED_ARRAY_SUPPORT) {
+ Buffer.prototype.__proto__ = Uint8Array.prototype
+ Buffer.__proto__ = Uint8Array
+ if (typeof Symbol !== 'undefined' && Symbol.species &&
+ Buffer[Symbol.species] === Buffer) {
+ // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
+ Object.defineProperty(Buffer, Symbol.species, {
+ value: null,
+ configurable: true
+ })
+ }
+}
+
+function assertSize (size) {
+ if (typeof size !== 'number') {
+ throw new TypeError('"size" argument must be a number')
+ } else if (size < 0) {
+ throw new RangeError('"size" argument must not be negative')
+ }
+}
+
+function alloc (that, size, fill, encoding) {
+ assertSize(size)
+ if (size <= 0) {
+ return createBuffer(that, size)
+ }
+ if (fill !== undefined) {
+ // Only pay attention to encoding if it's a string. This
+ // prevents accidentally sending in a number that would
+ // be interpretted as a start offset.
+ return typeof encoding === 'string'
+ ? createBuffer(that, size).fill(fill, encoding)
+ : createBuffer(that, size).fill(fill)
+ }
+ return createBuffer(that, size)
+}
+
+/**
+ * Creates a new filled Buffer instance.
+ * alloc(size[, fill[, encoding]])
+ **/
+Buffer.alloc = function (size, fill, encoding) {
+ return alloc(null, size, fill, encoding)
+}
+
+function allocUnsafe (that, size) {
+ assertSize(size)
+ that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)
+ if (!Buffer.TYPED_ARRAY_SUPPORT) {
+ for (var i = 0; i < size; ++i) {
+ that[i] = 0
+ }
+ }
+ return that
+}
+
+/**
+ * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
+ * */
+Buffer.allocUnsafe = function (size) {
+ return allocUnsafe(null, size)
+}
+/**
+ * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
+ */
+Buffer.allocUnsafeSlow = function (size) {
+ return allocUnsafe(null, size)
+}
+
+function fromString (that, string, encoding) {
+ if (typeof encoding !== 'string' || encoding === '') {
+ encoding = 'utf8'
+ }
+
+ if (!Buffer.isEncoding(encoding)) {
+ throw new TypeError('"encoding" must be a valid string encoding')
+ }
+
+ var length = byteLength(string, encoding) | 0
+ that = createBuffer(that, length)
+
+ var actual = that.write(string, encoding)
+
+ if (actual !== length) {
+ // Writing a hex string, for example, that contains invalid characters will
+ // cause everything after the first invalid character to be ignored. (e.g.
+ // 'abxxcd' will be treated as 'ab')
+ that = that.slice(0, actual)
+ }
+
+ return that
+}
+
+function fromArrayLike (that, array) {
+ var length = array.length < 0 ? 0 : checked(array.length) | 0
+ that = createBuffer(that, length)
+ for (var i = 0; i < length; i += 1) {
+ that[i] = array[i] & 255
+ }
+ return that
+}
+
+function fromArrayBuffer (that, array, byteOffset, length) {
+ array.byteLength // this throws if `array` is not a valid ArrayBuffer
+
+ if (byteOffset < 0 || array.byteLength < byteOffset) {
+ throw new RangeError('\'offset\' is out of bounds')
+ }
+
+ if (array.byteLength < byteOffset + (length || 0)) {
+ throw new RangeError('\'length\' is out of bounds')
+ }
+
+ if (byteOffset === undefined && length === undefined) {
+ array = new Uint8Array(array)
+ } else if (length === undefined) {
+ array = new Uint8Array(array, byteOffset)
+ } else {
+ array = new Uint8Array(array, byteOffset, length)
+ }
+
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ // Return an augmented `Uint8Array` instance, for best performance
+ that = array
+ that.__proto__ = Buffer.prototype
+ } else {
+ // Fallback: Return an object instance of the Buffer class
+ that = fromArrayLike(that, array)
+ }
+ return that
+}
+
+function fromObject (that, obj) {
+ if (Buffer.isBuffer(obj)) {
+ var len = checked(obj.length) | 0
+ that = createBuffer(that, len)
+
+ if (that.length === 0) {
+ return that
+ }
+
+ obj.copy(that, 0, 0, len)
+ return that
+ }
+
+ if (obj) {
+ if ((typeof ArrayBuffer !== 'undefined' &&
+ obj.buffer instanceof ArrayBuffer) || 'length' in obj) {
+ if (typeof obj.length !== 'number' || isnan(obj.length)) {
+ return createBuffer(that, 0)
+ }
+ return fromArrayLike(that, obj)
+ }
+
+ if (obj.type === 'Buffer' && isArray(obj.data)) {
+ return fromArrayLike(that, obj.data)
+ }
+ }
+
+ throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')
+}
+
+function checked (length) {
+ // Note: cannot use `length < kMaxLength()` here because that fails when
+ // length is NaN (which is otherwise coerced to zero.)
+ if (length >= kMaxLength()) {
+ throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
+ 'size: 0x' + kMaxLength().toString(16) + ' bytes')
+ }
+ return length | 0
+}
+
+function SlowBuffer (length) {
+ if (+length != length) { // eslint-disable-line eqeqeq
+ length = 0
+ }
+ return Buffer.alloc(+length)
+}
+
+Buffer.isBuffer = function isBuffer (b) {
+ return !!(b != null && b._isBuffer)
+}
+
+Buffer.compare = function compare (a, b) {
+ if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
+ throw new TypeError('Arguments must be Buffers')
+ }
+
+ if (a === b) return 0
+
+ var x = a.length
+ var y = b.length
+
+ for (var i = 0, len = Math.min(x, y); i < len; ++i) {
+ if (a[i] !== b[i]) {
+ x = a[i]
+ y = b[i]
+ break
+ }
+ }
+
+ if (x < y) return -1
+ if (y < x) return 1
+ return 0
+}
+
+Buffer.isEncoding = function isEncoding (encoding) {
+ switch (String(encoding).toLowerCase()) {
+ case 'hex':
+ case 'utf8':
+ case 'utf-8':
+ case 'ascii':
+ case 'latin1':
+ case 'binary':
+ case 'base64':
+ case 'ucs2':
+ case 'ucs-2':
+ case 'utf16le':
+ case 'utf-16le':
+ return true
+ default:
+ return false
+ }
+}
+
+Buffer.concat = function concat (list, length) {
+ if (!isArray(list)) {
+ throw new TypeError('"list" argument must be an Array of Buffers')
+ }
+
+ if (list.length === 0) {
+ return Buffer.alloc(0)
+ }
+
+ var i
+ if (length === undefined) {
+ length = 0
+ for (i = 0; i < list.length; ++i) {
+ length += list[i].length
+ }
+ }
+
+ var buffer = Buffer.allocUnsafe(length)
+ var pos = 0
+ for (i = 0; i < list.length; ++i) {
+ var buf = list[i]
+ if (!Buffer.isBuffer(buf)) {
+ throw new TypeError('"list" argument must be an Array of Buffers')
+ }
+ buf.copy(buffer, pos)
+ pos += buf.length
+ }
+ return buffer
+}
+
+function byteLength (string, encoding) {
+ if (Buffer.isBuffer(string)) {
+ return string.length
+ }
+ if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&
+ (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {
+ return string.byteLength
+ }
+ if (typeof string !== 'string') {
+ string = '' + string
+ }
+
+ var len = string.length
+ if (len === 0) return 0
+
+ // Use a for loop to avoid recursion
+ var loweredCase = false
+ for (;;) {
+ switch (encoding) {
+ case 'ascii':
+ case 'latin1':
+ case 'binary':
+ return len
+ case 'utf8':
+ case 'utf-8':
+ case undefined:
+ return utf8ToBytes(string).length
+ case 'ucs2':
+ case 'ucs-2':
+ case 'utf16le':
+ case 'utf-16le':
+ return len * 2
+ case 'hex':
+ return len >>> 1
+ case 'base64':
+ return base64ToBytes(string).length
+ default:
+ if (loweredCase) return utf8ToBytes(string).length // assume utf8
+ encoding = ('' + encoding).toLowerCase()
+ loweredCase = true
+ }
+ }
+}
+Buffer.byteLength = byteLength
+
+function slowToString (encoding, start, end) {
+ var loweredCase = false
+
+ // No need to verify that "this.length <= MAX_UINT32" since it's a read-only
+ // property of a typed array.
+
+ // This behaves neither like String nor Uint8Array in that we set start/end
+ // to their upper/lower bounds if the value passed is out of range.
+ // undefined is handled specially as per ECMA-262 6th Edition,
+ // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
+ if (start === undefined || start < 0) {
+ start = 0
+ }
+ // Return early if start > this.length. Done here to prevent potential uint32
+ // coercion fail below.
+ if (start > this.length) {
+ return ''
+ }
+
+ if (end === undefined || end > this.length) {
+ end = this.length
+ }
+
+ if (end <= 0) {
+ return ''
+ }
+
+ // Force coersion to uint32. This will also coerce falsey/NaN values to 0.
+ end >>>= 0
+ start >>>= 0
+
+ if (end <= start) {
+ return ''
+ }
+
+ if (!encoding) encoding = 'utf8'
+
+ while (true) {
+ switch (encoding) {
+ case 'hex':
+ return hexSlice(this, start, end)
+
+ case 'utf8':
+ case 'utf-8':
+ return utf8Slice(this, start, end)
+
+ case 'ascii':
+ return asciiSlice(this, start, end)
+
+ case 'latin1':
+ case 'binary':
+ return latin1Slice(this, start, end)
+
+ case 'base64':
+ return base64Slice(this, start, end)
+
+ case 'ucs2':
+ case 'ucs-2':
+ case 'utf16le':
+ case 'utf-16le':
+ return utf16leSlice(this, start, end)
+
+ default:
+ if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
+ encoding = (encoding + '').toLowerCase()
+ loweredCase = true
+ }
+ }
+}
+
+// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect
+// Buffer instances.
+Buffer.prototype._isBuffer = true
+
+function swap (b, n, m) {
+ var i = b[n]
+ b[n] = b[m]
+ b[m] = i
+}
+
+Buffer.prototype.swap16 = function swap16 () {
+ var len = this.length
+ if (len % 2 !== 0) {
+ throw new RangeError('Buffer size must be a multiple of 16-bits')
+ }
+ for (var i = 0; i < len; i += 2) {
+ swap(this, i, i + 1)
+ }
+ return this
+}
+
+Buffer.prototype.swap32 = function swap32 () {
+ var len = this.length
+ if (len % 4 !== 0) {
+ throw new RangeError('Buffer size must be a multiple of 32-bits')
+ }
+ for (var i = 0; i < len; i += 4) {
+ swap(this, i, i + 3)
+ swap(this, i + 1, i + 2)
+ }
+ return this
+}
+
+Buffer.prototype.swap64 = function swap64 () {
+ var len = this.length
+ if (len % 8 !== 0) {
+ throw new RangeError('Buffer size must be a multiple of 64-bits')
+ }
+ for (var i = 0; i < len; i += 8) {
+ swap(this, i, i + 7)
+ swap(this, i + 1, i + 6)
+ swap(this, i + 2, i + 5)
+ swap(this, i + 3, i + 4)
+ }
+ return this
+}
+
+Buffer.prototype.toString = function toString () {
+ var length = this.length | 0
+ if (length === 0) return ''
+ if (arguments.length === 0) return utf8Slice(this, 0, length)
+ return slowToString.apply(this, arguments)
+}
+
+Buffer.prototype.equals = function equals (b) {
+ if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
+ if (this === b) return true
+ return Buffer.compare(this, b) === 0
+}
+
+Buffer.prototype.inspect = function inspect () {
+ var str = ''
+ var max = exports.INSPECT_MAX_BYTES
+ if (this.length > 0) {
+ str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')
+ if (this.length > max) str += ' ... '
+ }
+ return ''
+}
+
+Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
+ if (!Buffer.isBuffer(target)) {
+ throw new TypeError('Argument must be a Buffer')
+ }
+
+ if (start === undefined) {
+ start = 0
+ }
+ if (end === undefined) {
+ end = target ? target.length : 0
+ }
+ if (thisStart === undefined) {
+ thisStart = 0
+ }
+ if (thisEnd === undefined) {
+ thisEnd = this.length
+ }
+
+ if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
+ throw new RangeError('out of range index')
+ }
+
+ if (thisStart >= thisEnd && start >= end) {
+ return 0
+ }
+ if (thisStart >= thisEnd) {
+ return -1
+ }
+ if (start >= end) {
+ return 1
+ }
+
+ start >>>= 0
+ end >>>= 0
+ thisStart >>>= 0
+ thisEnd >>>= 0
+
+ if (this === target) return 0
+
+ var x = thisEnd - thisStart
+ var y = end - start
+ var len = Math.min(x, y)
+
+ var thisCopy = this.slice(thisStart, thisEnd)
+ var targetCopy = target.slice(start, end)
+
+ for (var i = 0; i < len; ++i) {
+ if (thisCopy[i] !== targetCopy[i]) {
+ x = thisCopy[i]
+ y = targetCopy[i]
+ break
+ }
+ }
+
+ if (x < y) return -1
+ if (y < x) return 1
+ return 0
+}
+
+// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
+// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
+//
+// Arguments:
+// - buffer - a Buffer to search
+// - val - a string, Buffer, or number
+// - byteOffset - an index into `buffer`; will be clamped to an int32
+// - encoding - an optional encoding, relevant is val is a string
+// - dir - true for indexOf, false for lastIndexOf
+function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
+ // Empty buffer means no match
+ if (buffer.length === 0) return -1
+
+ // Normalize byteOffset
+ if (typeof byteOffset === 'string') {
+ encoding = byteOffset
+ byteOffset = 0
+ } else if (byteOffset > 0x7fffffff) {
+ byteOffset = 0x7fffffff
+ } else if (byteOffset < -0x80000000) {
+ byteOffset = -0x80000000
+ }
+ byteOffset = +byteOffset // Coerce to Number.
+ if (isNaN(byteOffset)) {
+ // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
+ byteOffset = dir ? 0 : (buffer.length - 1)
+ }
+
+ // Normalize byteOffset: negative offsets start from the end of the buffer
+ if (byteOffset < 0) byteOffset = buffer.length + byteOffset
+ if (byteOffset >= buffer.length) {
+ if (dir) return -1
+ else byteOffset = buffer.length - 1
+ } else if (byteOffset < 0) {
+ if (dir) byteOffset = 0
+ else return -1
+ }
+
+ // Normalize val
+ if (typeof val === 'string') {
+ val = Buffer.from(val, encoding)
+ }
+
+ // Finally, search either indexOf (if dir is true) or lastIndexOf
+ if (Buffer.isBuffer(val)) {
+ // Special case: looking for empty string/buffer always fails
+ if (val.length === 0) {
+ return -1
+ }
+ return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
+ } else if (typeof val === 'number') {
+ val = val & 0xFF // Search for a byte value [0-255]
+ if (Buffer.TYPED_ARRAY_SUPPORT &&
+ typeof Uint8Array.prototype.indexOf === 'function') {
+ if (dir) {
+ return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
+ } else {
+ return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
+ }
+ }
+ return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)
+ }
+
+ throw new TypeError('val must be string, number or Buffer')
+}
+
+function arrayIndexOf (arr, val, byteOffset, encoding, dir) {
+ var indexSize = 1
+ var arrLength = arr.length
+ var valLength = val.length
+
+ if (encoding !== undefined) {
+ encoding = String(encoding).toLowerCase()
+ if (encoding === 'ucs2' || encoding === 'ucs-2' ||
+ encoding === 'utf16le' || encoding === 'utf-16le') {
+ if (arr.length < 2 || val.length < 2) {
+ return -1
+ }
+ indexSize = 2
+ arrLength /= 2
+ valLength /= 2
+ byteOffset /= 2
+ }
+ }
+
+ function read (buf, i) {
+ if (indexSize === 1) {
+ return buf[i]
+ } else {
+ return buf.readUInt16BE(i * indexSize)
+ }
+ }
+
+ var i
+ if (dir) {
+ var foundIndex = -1
+ for (i = byteOffset; i < arrLength; i++) {
+ if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
+ if (foundIndex === -1) foundIndex = i
+ if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
+ } else {
+ if (foundIndex !== -1) i -= i - foundIndex
+ foundIndex = -1
+ }
+ }
+ } else {
+ if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength
+ for (i = byteOffset; i >= 0; i--) {
+ var found = true
+ for (var j = 0; j < valLength; j++) {
+ if (read(arr, i + j) !== read(val, j)) {
+ found = false
+ break
+ }
+ }
+ if (found) return i
+ }
+ }
+
+ return -1
+}
+
+Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
+ return this.indexOf(val, byteOffset, encoding) !== -1
+}
+
+Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
+ return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
+}
+
+Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
+ return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
+}
+
+function hexWrite (buf, string, offset, length) {
+ offset = Number(offset) || 0
+ var remaining = buf.length - offset
+ if (!length) {
+ length = remaining
+ } else {
+ length = Number(length)
+ if (length > remaining) {
+ length = remaining
+ }
+ }
+
+ // must be an even number of digits
+ var strLen = string.length
+ if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')
+
+ if (length > strLen / 2) {
+ length = strLen / 2
+ }
+ for (var i = 0; i < length; ++i) {
+ var parsed = parseInt(string.substr(i * 2, 2), 16)
+ if (isNaN(parsed)) return i
+ buf[offset + i] = parsed
+ }
+ return i
+}
+
+function utf8Write (buf, string, offset, length) {
+ return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
+}
+
+function asciiWrite (buf, string, offset, length) {
+ return blitBuffer(asciiToBytes(string), buf, offset, length)
+}
+
+function latin1Write (buf, string, offset, length) {
+ return asciiWrite(buf, string, offset, length)
+}
+
+function base64Write (buf, string, offset, length) {
+ return blitBuffer(base64ToBytes(string), buf, offset, length)
+}
+
+function ucs2Write (buf, string, offset, length) {
+ return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
+}
+
+Buffer.prototype.write = function write (string, offset, length, encoding) {
+ // Buffer#write(string)
+ if (offset === undefined) {
+ encoding = 'utf8'
+ length = this.length
+ offset = 0
+ // Buffer#write(string, encoding)
+ } else if (length === undefined && typeof offset === 'string') {
+ encoding = offset
+ length = this.length
+ offset = 0
+ // Buffer#write(string, offset[, length][, encoding])
+ } else if (isFinite(offset)) {
+ offset = offset | 0
+ if (isFinite(length)) {
+ length = length | 0
+ if (encoding === undefined) encoding = 'utf8'
+ } else {
+ encoding = length
+ length = undefined
+ }
+ // legacy write(string, encoding, offset, length) - remove in v0.13
+ } else {
+ throw new Error(
+ 'Buffer.write(string, encoding, offset[, length]) is no longer supported'
+ )
+ }
+
+ var remaining = this.length - offset
+ if (length === undefined || length > remaining) length = remaining
+
+ if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
+ throw new RangeError('Attempt to write outside buffer bounds')
+ }
+
+ if (!encoding) encoding = 'utf8'
+
+ var loweredCase = false
+ for (;;) {
+ switch (encoding) {
+ case 'hex':
+ return hexWrite(this, string, offset, length)
+
+ case 'utf8':
+ case 'utf-8':
+ return utf8Write(this, string, offset, length)
+
+ case 'ascii':
+ return asciiWrite(this, string, offset, length)
+
+ case 'latin1':
+ case 'binary':
+ return latin1Write(this, string, offset, length)
+
+ case 'base64':
+ // Warning: maxLength not taken into account in base64Write
+ return base64Write(this, string, offset, length)
+
+ case 'ucs2':
+ case 'ucs-2':
+ case 'utf16le':
+ case 'utf-16le':
+ return ucs2Write(this, string, offset, length)
+
+ default:
+ if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
+ encoding = ('' + encoding).toLowerCase()
+ loweredCase = true
+ }
+ }
+}
+
+Buffer.prototype.toJSON = function toJSON () {
+ return {
+ type: 'Buffer',
+ data: Array.prototype.slice.call(this._arr || this, 0)
+ }
+}
+
+function base64Slice (buf, start, end) {
+ if (start === 0 && end === buf.length) {
+ return base64.fromByteArray(buf)
+ } else {
+ return base64.fromByteArray(buf.slice(start, end))
+ }
+}
+
+function utf8Slice (buf, start, end) {
+ end = Math.min(buf.length, end)
+ var res = []
+
+ var i = start
+ while (i < end) {
+ var firstByte = buf[i]
+ var codePoint = null
+ var bytesPerSequence = (firstByte > 0xEF) ? 4
+ : (firstByte > 0xDF) ? 3
+ : (firstByte > 0xBF) ? 2
+ : 1
+
+ if (i + bytesPerSequence <= end) {
+ var secondByte, thirdByte, fourthByte, tempCodePoint
+
+ switch (bytesPerSequence) {
+ case 1:
+ if (firstByte < 0x80) {
+ codePoint = firstByte
+ }
+ break
+ case 2:
+ secondByte = buf[i + 1]
+ if ((secondByte & 0xC0) === 0x80) {
+ tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
+ if (tempCodePoint > 0x7F) {
+ codePoint = tempCodePoint
+ }
+ }
+ break
+ case 3:
+ secondByte = buf[i + 1]
+ thirdByte = buf[i + 2]
+ if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
+ tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
+ if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
+ codePoint = tempCodePoint
+ }
+ }
+ break
+ case 4:
+ secondByte = buf[i + 1]
+ thirdByte = buf[i + 2]
+ fourthByte = buf[i + 3]
+ if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
+ tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
+ if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
+ codePoint = tempCodePoint
+ }
+ }
+ }
+ }
+
+ if (codePoint === null) {
+ // we did not generate a valid codePoint so insert a
+ // replacement char (U+FFFD) and advance only 1 byte
+ codePoint = 0xFFFD
+ bytesPerSequence = 1
+ } else if (codePoint > 0xFFFF) {
+ // encode to utf16 (surrogate pair dance)
+ codePoint -= 0x10000
+ res.push(codePoint >>> 10 & 0x3FF | 0xD800)
+ codePoint = 0xDC00 | codePoint & 0x3FF
+ }
+
+ res.push(codePoint)
+ i += bytesPerSequence
+ }
+
+ return decodeCodePointsArray(res)
+}
+
+// Based on http://stackoverflow.com/a/22747272/680742, the browser with
+// the lowest limit is Chrome, with 0x10000 args.
+// We go 1 magnitude less, for safety
+var MAX_ARGUMENTS_LENGTH = 0x1000
+
+function decodeCodePointsArray (codePoints) {
+ var len = codePoints.length
+ if (len <= MAX_ARGUMENTS_LENGTH) {
+ return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
+ }
+
+ // Decode in chunks to avoid "call stack size exceeded".
+ var res = ''
+ var i = 0
+ while (i < len) {
+ res += String.fromCharCode.apply(
+ String,
+ codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
+ )
+ }
+ return res
+}
+
+function asciiSlice (buf, start, end) {
+ var ret = ''
+ end = Math.min(buf.length, end)
+
+ for (var i = start; i < end; ++i) {
+ ret += String.fromCharCode(buf[i] & 0x7F)
+ }
+ return ret
+}
+
+function latin1Slice (buf, start, end) {
+ var ret = ''
+ end = Math.min(buf.length, end)
+
+ for (var i = start; i < end; ++i) {
+ ret += String.fromCharCode(buf[i])
+ }
+ return ret
+}
+
+function hexSlice (buf, start, end) {
+ var len = buf.length
+
+ if (!start || start < 0) start = 0
+ if (!end || end < 0 || end > len) end = len
+
+ var out = ''
+ for (var i = start; i < end; ++i) {
+ out += toHex(buf[i])
+ }
+ return out
+}
+
+function utf16leSlice (buf, start, end) {
+ var bytes = buf.slice(start, end)
+ var res = ''
+ for (var i = 0; i < bytes.length; i += 2) {
+ res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)
+ }
+ return res
+}
+
+Buffer.prototype.slice = function slice (start, end) {
+ var len = this.length
+ start = ~~start
+ end = end === undefined ? len : ~~end
+
+ if (start < 0) {
+ start += len
+ if (start < 0) start = 0
+ } else if (start > len) {
+ start = len
+ }
+
+ if (end < 0) {
+ end += len
+ if (end < 0) end = 0
+ } else if (end > len) {
+ end = len
+ }
+
+ if (end < start) end = start
+
+ var newBuf
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ newBuf = this.subarray(start, end)
+ newBuf.__proto__ = Buffer.prototype
+ } else {
+ var sliceLen = end - start
+ newBuf = new Buffer(sliceLen, undefined)
+ for (var i = 0; i < sliceLen; ++i) {
+ newBuf[i] = this[i + start]
+ }
+ }
+
+ return newBuf
+}
+
+/*
+ * Need to make sure that buffer isn't trying to write out of bounds.
+ */
+function checkOffset (offset, ext, length) {
+ if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
+ if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
+}
+
+Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
+ offset = offset | 0
+ byteLength = byteLength | 0
+ if (!noAssert) checkOffset(offset, byteLength, this.length)
+
+ var val = this[offset]
+ var mul = 1
+ var i = 0
+ while (++i < byteLength && (mul *= 0x100)) {
+ val += this[offset + i] * mul
+ }
+
+ return val
+}
+
+Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
+ offset = offset | 0
+ byteLength = byteLength | 0
+ if (!noAssert) {
+ checkOffset(offset, byteLength, this.length)
+ }
+
+ var val = this[offset + --byteLength]
+ var mul = 1
+ while (byteLength > 0 && (mul *= 0x100)) {
+ val += this[offset + --byteLength] * mul
+ }
+
+ return val
+}
+
+Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 1, this.length)
+ return this[offset]
+}
+
+Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 2, this.length)
+ return this[offset] | (this[offset + 1] << 8)
+}
+
+Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 2, this.length)
+ return (this[offset] << 8) | this[offset + 1]
+}
+
+Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 4, this.length)
+
+ return ((this[offset]) |
+ (this[offset + 1] << 8) |
+ (this[offset + 2] << 16)) +
+ (this[offset + 3] * 0x1000000)
+}
+
+Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 4, this.length)
+
+ return (this[offset] * 0x1000000) +
+ ((this[offset + 1] << 16) |
+ (this[offset + 2] << 8) |
+ this[offset + 3])
+}
+
+Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
+ offset = offset | 0
+ byteLength = byteLength | 0
+ if (!noAssert) checkOffset(offset, byteLength, this.length)
+
+ var val = this[offset]
+ var mul = 1
+ var i = 0
+ while (++i < byteLength && (mul *= 0x100)) {
+ val += this[offset + i] * mul
+ }
+ mul *= 0x80
+
+ if (val >= mul) val -= Math.pow(2, 8 * byteLength)
+
+ return val
+}
+
+Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
+ offset = offset | 0
+ byteLength = byteLength | 0
+ if (!noAssert) checkOffset(offset, byteLength, this.length)
+
+ var i = byteLength
+ var mul = 1
+ var val = this[offset + --i]
+ while (i > 0 && (mul *= 0x100)) {
+ val += this[offset + --i] * mul
+ }
+ mul *= 0x80
+
+ if (val >= mul) val -= Math.pow(2, 8 * byteLength)
+
+ return val
+}
+
+Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 1, this.length)
+ if (!(this[offset] & 0x80)) return (this[offset])
+ return ((0xff - this[offset] + 1) * -1)
+}
+
+Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 2, this.length)
+ var val = this[offset] | (this[offset + 1] << 8)
+ return (val & 0x8000) ? val | 0xFFFF0000 : val
+}
+
+Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 2, this.length)
+ var val = this[offset + 1] | (this[offset] << 8)
+ return (val & 0x8000) ? val | 0xFFFF0000 : val
+}
+
+Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 4, this.length)
+
+ return (this[offset]) |
+ (this[offset + 1] << 8) |
+ (this[offset + 2] << 16) |
+ (this[offset + 3] << 24)
+}
+
+Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 4, this.length)
+
+ return (this[offset] << 24) |
+ (this[offset + 1] << 16) |
+ (this[offset + 2] << 8) |
+ (this[offset + 3])
+}
+
+Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 4, this.length)
+ return ieee754.read(this, offset, true, 23, 4)
+}
+
+Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 4, this.length)
+ return ieee754.read(this, offset, false, 23, 4)
+}
+
+Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 8, this.length)
+ return ieee754.read(this, offset, true, 52, 8)
+}
+
+Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
+ if (!noAssert) checkOffset(offset, 8, this.length)
+ return ieee754.read(this, offset, false, 52, 8)
+}
+
+function checkInt (buf, value, offset, ext, max, min) {
+ if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
+ if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
+ if (offset + ext > buf.length) throw new RangeError('Index out of range')
+}
+
+Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
+ value = +value
+ offset = offset | 0
+ byteLength = byteLength | 0
+ if (!noAssert) {
+ var maxBytes = Math.pow(2, 8 * byteLength) - 1
+ checkInt(this, value, offset, byteLength, maxBytes, 0)
+ }
+
+ var mul = 1
+ var i = 0
+ this[offset] = value & 0xFF
+ while (++i < byteLength && (mul *= 0x100)) {
+ this[offset + i] = (value / mul) & 0xFF
+ }
+
+ return offset + byteLength
+}
+
+Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
+ value = +value
+ offset = offset | 0
+ byteLength = byteLength | 0
+ if (!noAssert) {
+ var maxBytes = Math.pow(2, 8 * byteLength) - 1
+ checkInt(this, value, offset, byteLength, maxBytes, 0)
+ }
+
+ var i = byteLength - 1
+ var mul = 1
+ this[offset + i] = value & 0xFF
+ while (--i >= 0 && (mul *= 0x100)) {
+ this[offset + i] = (value / mul) & 0xFF
+ }
+
+ return offset + byteLength
+}
+
+Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
+ value = +value
+ offset = offset | 0
+ if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
+ if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
+ this[offset] = (value & 0xff)
+ return offset + 1
+}
+
+function objectWriteUInt16 (buf, value, offset, littleEndian) {
+ if (value < 0) value = 0xffff + value + 1
+ for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {
+ buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
+ (littleEndian ? i : 1 - i) * 8
+ }
+}
+
+Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
+ value = +value
+ offset = offset | 0
+ if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = (value & 0xff)
+ this[offset + 1] = (value >>> 8)
+ } else {
+ objectWriteUInt16(this, value, offset, true)
+ }
+ return offset + 2
+}
+
+Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
+ value = +value
+ offset = offset | 0
+ if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = (value >>> 8)
+ this[offset + 1] = (value & 0xff)
+ } else {
+ objectWriteUInt16(this, value, offset, false)
+ }
+ return offset + 2
+}
+
+function objectWriteUInt32 (buf, value, offset, littleEndian) {
+ if (value < 0) value = 0xffffffff + value + 1
+ for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {
+ buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
+ }
+}
+
+Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
+ value = +value
+ offset = offset | 0
+ if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset + 3] = (value >>> 24)
+ this[offset + 2] = (value >>> 16)
+ this[offset + 1] = (value >>> 8)
+ this[offset] = (value & 0xff)
+ } else {
+ objectWriteUInt32(this, value, offset, true)
+ }
+ return offset + 4
+}
+
+Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
+ value = +value
+ offset = offset | 0
+ if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = (value >>> 24)
+ this[offset + 1] = (value >>> 16)
+ this[offset + 2] = (value >>> 8)
+ this[offset + 3] = (value & 0xff)
+ } else {
+ objectWriteUInt32(this, value, offset, false)
+ }
+ return offset + 4
+}
+
+Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
+ value = +value
+ offset = offset | 0
+ if (!noAssert) {
+ var limit = Math.pow(2, 8 * byteLength - 1)
+
+ checkInt(this, value, offset, byteLength, limit - 1, -limit)
+ }
+
+ var i = 0
+ var mul = 1
+ var sub = 0
+ this[offset] = value & 0xFF
+ while (++i < byteLength && (mul *= 0x100)) {
+ if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
+ sub = 1
+ }
+ this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
+ }
+
+ return offset + byteLength
+}
+
+Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
+ value = +value
+ offset = offset | 0
+ if (!noAssert) {
+ var limit = Math.pow(2, 8 * byteLength - 1)
+
+ checkInt(this, value, offset, byteLength, limit - 1, -limit)
+ }
+
+ var i = byteLength - 1
+ var mul = 1
+ var sub = 0
+ this[offset + i] = value & 0xFF
+ while (--i >= 0 && (mul *= 0x100)) {
+ if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
+ sub = 1
+ }
+ this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
+ }
+
+ return offset + byteLength
+}
+
+Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
+ value = +value
+ offset = offset | 0
+ if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
+ if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
+ if (value < 0) value = 0xff + value + 1
+ this[offset] = (value & 0xff)
+ return offset + 1
+}
+
+Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
+ value = +value
+ offset = offset | 0
+ if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = (value & 0xff)
+ this[offset + 1] = (value >>> 8)
+ } else {
+ objectWriteUInt16(this, value, offset, true)
+ }
+ return offset + 2
+}
+
+Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
+ value = +value
+ offset = offset | 0
+ if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = (value >>> 8)
+ this[offset + 1] = (value & 0xff)
+ } else {
+ objectWriteUInt16(this, value, offset, false)
+ }
+ return offset + 2
+}
+
+Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
+ value = +value
+ offset = offset | 0
+ if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = (value & 0xff)
+ this[offset + 1] = (value >>> 8)
+ this[offset + 2] = (value >>> 16)
+ this[offset + 3] = (value >>> 24)
+ } else {
+ objectWriteUInt32(this, value, offset, true)
+ }
+ return offset + 4
+}
+
+Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
+ value = +value
+ offset = offset | 0
+ if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
+ if (value < 0) value = 0xffffffff + value + 1
+ if (Buffer.TYPED_ARRAY_SUPPORT) {
+ this[offset] = (value >>> 24)
+ this[offset + 1] = (value >>> 16)
+ this[offset + 2] = (value >>> 8)
+ this[offset + 3] = (value & 0xff)
+ } else {
+ objectWriteUInt32(this, value, offset, false)
+ }
+ return offset + 4
+}
+
+function checkIEEE754 (buf, value, offset, ext, max, min) {
+ if (offset + ext > buf.length) throw new RangeError('Index out of range')
+ if (offset < 0) throw new RangeError('Index out of range')
+}
+
+function writeFloat (buf, value, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
+ }
+ ieee754.write(buf, value, offset, littleEndian, 23, 4)
+ return offset + 4
+}
+
+Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
+ return writeFloat(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
+ return writeFloat(this, value, offset, false, noAssert)
+}
+
+function writeDouble (buf, value, offset, littleEndian, noAssert) {
+ if (!noAssert) {
+ checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
+ }
+ ieee754.write(buf, value, offset, littleEndian, 52, 8)
+ return offset + 8
+}
+
+Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
+ return writeDouble(this, value, offset, true, noAssert)
+}
+
+Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
+ return writeDouble(this, value, offset, false, noAssert)
+}
+
+// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
+Buffer.prototype.copy = function copy (target, targetStart, start, end) {
+ if (!start) start = 0
+ if (!end && end !== 0) end = this.length
+ if (targetStart >= target.length) targetStart = target.length
+ if (!targetStart) targetStart = 0
+ if (end > 0 && end < start) end = start
+
+ // Copy 0 bytes; we're done
+ if (end === start) return 0
+ if (target.length === 0 || this.length === 0) return 0
+
+ // Fatal error conditions
+ if (targetStart < 0) {
+ throw new RangeError('targetStart out of bounds')
+ }
+ if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')
+ if (end < 0) throw new RangeError('sourceEnd out of bounds')
+
+ // Are we oob?
+ if (end > this.length) end = this.length
+ if (target.length - targetStart < end - start) {
+ end = target.length - targetStart + start
+ }
+
+ var len = end - start
+ var i
+
+ if (this === target && start < targetStart && targetStart < end) {
+ // descending copy from end
+ for (i = len - 1; i >= 0; --i) {
+ target[i + targetStart] = this[i + start]
+ }
+ } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
+ // ascending copy from start
+ for (i = 0; i < len; ++i) {
+ target[i + targetStart] = this[i + start]
+ }
+ } else {
+ Uint8Array.prototype.set.call(
+ target,
+ this.subarray(start, start + len),
+ targetStart
+ )
+ }
+
+ return len
+}
+
+// Usage:
+// buffer.fill(number[, offset[, end]])
+// buffer.fill(buffer[, offset[, end]])
+// buffer.fill(string[, offset[, end]][, encoding])
+Buffer.prototype.fill = function fill (val, start, end, encoding) {
+ // Handle string cases:
+ if (typeof val === 'string') {
+ if (typeof start === 'string') {
+ encoding = start
+ start = 0
+ end = this.length
+ } else if (typeof end === 'string') {
+ encoding = end
+ end = this.length
+ }
+ if (val.length === 1) {
+ var code = val.charCodeAt(0)
+ if (code < 256) {
+ val = code
+ }
+ }
+ if (encoding !== undefined && typeof encoding !== 'string') {
+ throw new TypeError('encoding must be a string')
+ }
+ if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
+ throw new TypeError('Unknown encoding: ' + encoding)
+ }
+ } else if (typeof val === 'number') {
+ val = val & 255
+ }
+
+ // Invalid ranges are not set to a default, so can range check early.
+ if (start < 0 || this.length < start || this.length < end) {
+ throw new RangeError('Out of range index')
+ }
+
+ if (end <= start) {
+ return this
+ }
+
+ start = start >>> 0
+ end = end === undefined ? this.length : end >>> 0
+
+ if (!val) val = 0
+
+ var i
+ if (typeof val === 'number') {
+ for (i = start; i < end; ++i) {
+ this[i] = val
+ }
+ } else {
+ var bytes = Buffer.isBuffer(val)
+ ? val
+ : utf8ToBytes(new Buffer(val, encoding).toString())
+ var len = bytes.length
+ for (i = 0; i < end - start; ++i) {
+ this[i + start] = bytes[i % len]
+ }
+ }
+
+ return this
+}
+
+// HELPER FUNCTIONS
+// ================
+
+var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g
+
+function base64clean (str) {
+ // Node strips out invalid characters like \n and \t from the string, base64-js does not
+ str = stringtrim(str).replace(INVALID_BASE64_RE, '')
+ // Node converts strings with length < 2 to ''
+ if (str.length < 2) return ''
+ // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
+ while (str.length % 4 !== 0) {
+ str = str + '='
+ }
+ return str
+}
+
+function stringtrim (str) {
+ if (str.trim) return str.trim()
+ return str.replace(/^\s+|\s+$/g, '')
+}
+
+function toHex (n) {
+ if (n < 16) return '0' + n.toString(16)
+ return n.toString(16)
+}
+
+function utf8ToBytes (string, units) {
+ units = units || Infinity
+ var codePoint
+ var length = string.length
+ var leadSurrogate = null
+ var bytes = []
+
+ for (var i = 0; i < length; ++i) {
+ codePoint = string.charCodeAt(i)
+
+ // is surrogate component
+ if (codePoint > 0xD7FF && codePoint < 0xE000) {
+ // last char was a lead
+ if (!leadSurrogate) {
+ // no lead yet
+ if (codePoint > 0xDBFF) {
+ // unexpected trail
+ if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
+ continue
+ } else if (i + 1 === length) {
+ // unpaired lead
+ if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
+ continue
+ }
+
+ // valid lead
+ leadSurrogate = codePoint
+
+ continue
+ }
+
+ // 2 leads in a row
+ if (codePoint < 0xDC00) {
+ if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
+ leadSurrogate = codePoint
+ continue
+ }
+
+ // valid surrogate pair
+ codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
+ } else if (leadSurrogate) {
+ // valid bmp char, but last char was a lead
+ if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
+ }
+
+ leadSurrogate = null
+
+ // encode utf8
+ if (codePoint < 0x80) {
+ if ((units -= 1) < 0) break
+ bytes.push(codePoint)
+ } else if (codePoint < 0x800) {
+ if ((units -= 2) < 0) break
+ bytes.push(
+ codePoint >> 0x6 | 0xC0,
+ codePoint & 0x3F | 0x80
+ )
+ } else if (codePoint < 0x10000) {
+ if ((units -= 3) < 0) break
+ bytes.push(
+ codePoint >> 0xC | 0xE0,
+ codePoint >> 0x6 & 0x3F | 0x80,
+ codePoint & 0x3F | 0x80
+ )
+ } else if (codePoint < 0x110000) {
+ if ((units -= 4) < 0) break
+ bytes.push(
+ codePoint >> 0x12 | 0xF0,
+ codePoint >> 0xC & 0x3F | 0x80,
+ codePoint >> 0x6 & 0x3F | 0x80,
+ codePoint & 0x3F | 0x80
+ )
+ } else {
+ throw new Error('Invalid code point')
+ }
+ }
+
+ return bytes
+}
+
+function asciiToBytes (str) {
+ var byteArray = []
+ for (var i = 0; i < str.length; ++i) {
+ // Node's code seems to be doing this and not & 0x7F..
+ byteArray.push(str.charCodeAt(i) & 0xFF)
+ }
+ return byteArray
+}
+
+function utf16leToBytes (str, units) {
+ var c, hi, lo
+ var byteArray = []
+ for (var i = 0; i < str.length; ++i) {
+ if ((units -= 2) < 0) break
+
+ c = str.charCodeAt(i)
+ hi = c >> 8
+ lo = c % 256
+ byteArray.push(lo)
+ byteArray.push(hi)
+ }
+
+ return byteArray
+}
+
+function base64ToBytes (str) {
+ return base64.toByteArray(base64clean(str))
+}
+
+function blitBuffer (src, dst, offset, length) {
+ for (var i = 0; i < length; ++i) {
+ if ((i + offset >= dst.length) || (i >= src.length)) break
+ dst[i + offset] = src[i]
+ }
+ return i
+}
+
+function isnan (val) {
+ return val !== val // eslint-disable-line no-self-compare
+}
+
+
+/***/ }),
+
+/***/ "./node_modules/global/document.js":
+/*!*****************************************!*\
+ !*** ./node_modules/global/document.js ***!
+ \*****************************************/
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+var topLevel = typeof __webpack_require__.g !== 'undefined' ? __webpack_require__.g :
+ typeof window !== 'undefined' ? window : {}
+var minDoc = __webpack_require__(/*! min-document */ "?facd");
+
+var doccy;
+
+if (typeof document !== 'undefined') {
+ doccy = document;
+} else {
+ doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
+
+ if (!doccy) {
+ doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
+ }
+}
+
+module.exports = doccy;
+
+
+/***/ }),
+
+/***/ "./node_modules/global/window.js":
+/*!***************************************!*\
+ !*** ./node_modules/global/window.js ***!
+ \***************************************/
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+var win;
+
+if (typeof window !== "undefined") {
+ win = window;
+} else if (typeof __webpack_require__.g !== "undefined") {
+ win = __webpack_require__.g;
+} else if (typeof self !== "undefined"){
+ win = self;
+} else {
+ win = {};
+}
+
+module.exports = win;
+
+
+/***/ }),
+
+/***/ "./node_modules/ieee754/index.js":
+/*!***************************************!*\
+ !*** ./node_modules/ieee754/index.js ***!
+ \***************************************/
+/***/ ((__unused_webpack_module, exports) => {
+
+/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */
+exports.read = function (buffer, offset, isLE, mLen, nBytes) {
+ var e, m
+ var eLen = (nBytes * 8) - mLen - 1
+ var eMax = (1 << eLen) - 1
+ var eBias = eMax >> 1
+ var nBits = -7
+ var i = isLE ? (nBytes - 1) : 0
+ var d = isLE ? -1 : 1
+ var s = buffer[offset + i]
+
+ i += d
+
+ e = s & ((1 << (-nBits)) - 1)
+ s >>= (-nBits)
+ nBits += eLen
+ for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {}
+
+ m = e & ((1 << (-nBits)) - 1)
+ e >>= (-nBits)
+ nBits += mLen
+ for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {}
+
+ if (e === 0) {
+ e = 1 - eBias
+ } else if (e === eMax) {
+ return m ? NaN : ((s ? -1 : 1) * Infinity)
+ } else {
+ m = m + Math.pow(2, mLen)
+ e = e - eBias
+ }
+ return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
+}
+
+exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
+ var e, m, c
+ var eLen = (nBytes * 8) - mLen - 1
+ var eMax = (1 << eLen) - 1
+ var eBias = eMax >> 1
+ var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
+ var i = isLE ? 0 : (nBytes - 1)
+ var d = isLE ? 1 : -1
+ var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
+
+ value = Math.abs(value)
+
+ if (isNaN(value) || value === Infinity) {
+ m = isNaN(value) ? 1 : 0
+ e = eMax
+ } else {
+ e = Math.floor(Math.log(value) / Math.LN2)
+ if (value * (c = Math.pow(2, -e)) < 1) {
+ e--
+ c *= 2
+ }
+ if (e + eBias >= 1) {
+ value += rt / c
+ } else {
+ value += rt * Math.pow(2, 1 - eBias)
+ }
+ if (value * c >= 2) {
+ e++
+ c /= 2
+ }
+
+ if (e + eBias >= eMax) {
+ m = 0
+ e = eMax
+ } else if (e + eBias >= 1) {
+ m = ((value * c) - 1) * Math.pow(2, mLen)
+ e = e + eBias
+ } else {
+ m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
+ e = 0
+ }
+ }
+
+ for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
+
+ e = (e << mLen) | m
+ eLen += mLen
+ for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
+
+ buffer[offset + i - d] |= s * 128
+}
+
+
+/***/ }),
+
+/***/ "./node_modules/is-function/index.js":
+/*!*******************************************!*\
+ !*** ./node_modules/is-function/index.js ***!
+ \*******************************************/
+/***/ ((module) => {
+
+module.exports = isFunction
+
+var toString = Object.prototype.toString
+
+function isFunction (fn) {
+ if (!fn) {
+ return false
+ }
+ var string = toString.call(fn)
+ return string === '[object Function]' ||
+ (typeof fn === 'function' && string !== '[object RegExp]') ||
+ (typeof window !== 'undefined' &&
+ // IE8 and below
+ (fn === window.setTimeout ||
+ fn === window.alert ||
+ fn === window.confirm ||
+ fn === window.prompt))
+};
+
+
+/***/ }),
+
+/***/ "./node_modules/isarray/index.js":
+/*!***************************************!*\
+ !*** ./node_modules/isarray/index.js ***!
+ \***************************************/
+/***/ ((module) => {
+
+var toString = {}.toString;
+
+module.exports = Array.isArray || function (arr) {
+ return toString.call(arr) == '[object Array]';
+};
+
+
+/***/ }),
+
+/***/ "./node_modules/keycode/index.js":
+/*!***************************************!*\
+ !*** ./node_modules/keycode/index.js ***!
+ \***************************************/
+/***/ ((module, exports) => {
+
+// Source: http://jsfiddle.net/vWx8V/
+// http://stackoverflow.com/questions/5603195/full-list-of-javascript-keycodes
+
+/**
+ * Conenience method returns corresponding value for given keyName or keyCode.
+ *
+ * @param {Mixed} keyCode {Number} or keyName {String}
+ * @return {Mixed}
+ * @api public
+ */
+
+function keyCode(searchInput) {
+ // Keyboard Events
+ if (searchInput && 'object' === typeof searchInput) {
+ var hasKeyCode = searchInput.which || searchInput.keyCode || searchInput.charCode
+ if (hasKeyCode) searchInput = hasKeyCode
+ }
+
+ // Numbers
+ if ('number' === typeof searchInput) return names[searchInput]
+
+ // Everything else (cast to string)
+ var search = String(searchInput)
+
+ // check codes
+ var foundNamedKey = codes[search.toLowerCase()]
+ if (foundNamedKey) return foundNamedKey
+
+ // check aliases
+ var foundNamedKey = aliases[search.toLowerCase()]
+ if (foundNamedKey) return foundNamedKey
+
+ // weird character?
+ if (search.length === 1) return search.charCodeAt(0)
+
+ return undefined
+}
+
+/**
+ * Compares a keyboard event with a given keyCode or keyName.
+ *
+ * @param {Event} event Keyboard event that should be tested
+ * @param {Mixed} keyCode {Number} or keyName {String}
+ * @return {Boolean}
+ * @api public
+ */
+keyCode.isEventKey = function isEventKey(event, nameOrCode) {
+ if (event && 'object' === typeof event) {
+ var keyCode = event.which || event.keyCode || event.charCode
+ if (keyCode === null || keyCode === undefined) { return false; }
+ if (typeof nameOrCode === 'string') {
+ // check codes
+ var foundNamedKey = codes[nameOrCode.toLowerCase()]
+ if (foundNamedKey) { return foundNamedKey === keyCode; }
+
+ // check aliases
+ var foundNamedKey = aliases[nameOrCode.toLowerCase()]
+ if (foundNamedKey) { return foundNamedKey === keyCode; }
+ } else if (typeof nameOrCode === 'number') {
+ return nameOrCode === keyCode;
+ }
+ return false;
+ }
+}
+
+exports = module.exports = keyCode;
+
+/**
+ * Get by name
+ *
+ * exports.code['enter'] // => 13
+ */
+
+var codes = exports.code = exports.codes = {
+ 'backspace': 8,
+ 'tab': 9,
+ 'enter': 13,
+ 'shift': 16,
+ 'ctrl': 17,
+ 'alt': 18,
+ 'pause/break': 19,
+ 'caps lock': 20,
+ 'esc': 27,
+ 'space': 32,
+ 'page up': 33,
+ 'page down': 34,
+ 'end': 35,
+ 'home': 36,
+ 'left': 37,
+ 'up': 38,
+ 'right': 39,
+ 'down': 40,
+ 'insert': 45,
+ 'delete': 46,
+ 'command': 91,
+ 'left command': 91,
+ 'right command': 93,
+ 'numpad *': 106,
+ 'numpad +': 107,
+ 'numpad -': 109,
+ 'numpad .': 110,
+ 'numpad /': 111,
+ 'num lock': 144,
+ 'scroll lock': 145,
+ 'my computer': 182,
+ 'my calculator': 183,
+ ';': 186,
+ '=': 187,
+ ',': 188,
+ '-': 189,
+ '.': 190,
+ '/': 191,
+ '`': 192,
+ '[': 219,
+ '\\': 220,
+ ']': 221,
+ "'": 222
+}
+
+// Helper aliases
+
+var aliases = exports.aliases = {
+ 'windows': 91,
+ '⇧': 16,
+ '⌥': 18,
+ '⌃': 17,
+ '⌘': 91,
+ 'ctl': 17,
+ 'control': 17,
+ 'option': 18,
+ 'pause': 19,
+ 'break': 19,
+ 'caps': 20,
+ 'return': 13,
+ 'escape': 27,
+ 'spc': 32,
+ 'spacebar': 32,
+ 'pgup': 33,
+ 'pgdn': 34,
+ 'ins': 45,
+ 'del': 46,
+ 'cmd': 91
+}
+
+/*!
+ * Programatically add the following
+ */
+
+// lower case chars
+for (i = 97; i < 123; i++) codes[String.fromCharCode(i)] = i - 32
+
+// numbers
+for (var i = 48; i < 58; i++) codes[i - 48] = i
+
+// function keys
+for (i = 1; i < 13; i++) codes['f'+i] = i + 111
+
+// numpad keys
+for (i = 0; i < 10; i++) codes['numpad '+i] = i + 96
+
+/**
+ * Get by code
+ *
+ * exports.name[13] // => 'Enter'
+ */
+
+var names = exports.names = exports.title = {} // title for backward compat
+
+// Create reverse mapping
+for (i in codes) names[codes[i]] = i
+
+// Add aliases
+for (var alias in aliases) {
+ codes[alias] = aliases[alias]
+}
+
+
+/***/ }),
+
+/***/ "./node_modules/m3u8-parser/dist/m3u8-parser.es.js":
+/*!*********************************************************!*\
+ !*** ./node_modules/m3u8-parser/dist/m3u8-parser.es.js ***!
+ \*********************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */ "LineStream": () => /* binding */ LineStream,
+/* harmony export */ "ParseStream": () => /* binding */ ParseStream,
+/* harmony export */ "Parser": () => /* binding */ Parser
+/* harmony export */ });
+/* harmony import */ var _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime/helpers/inheritsLoose */ "./node_modules/@babel/runtime/helpers/inheritsLoose.js");
+/* harmony import */ var _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var _videojs_vhs_utils_dist_stream_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @videojs/vhs-utils/dist/stream.js */ "./node_modules/@videojs/vhs-utils/dist/stream.js");
+/* harmony import */ var _videojs_vhs_utils_dist_stream_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_videojs_vhs_utils_dist_stream_js__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @babel/runtime/helpers/extends */ "./node_modules/@babel/runtime/helpers/extends.js");
+/* harmony import */ var _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @babel/runtime/helpers/assertThisInitialized */ "./node_modules/@babel/runtime/helpers/assertThisInitialized.js");
+/* harmony import */ var _babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3__);
+/* harmony import */ var _videojs_vhs_utils_dist_decode_b64_to_uint8_array_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @videojs/vhs-utils/dist/decode-b64-to-uint8-array.js */ "./node_modules/@videojs/vhs-utils/dist/decode-b64-to-uint8-array.js");
+/* harmony import */ var _videojs_vhs_utils_dist_decode_b64_to_uint8_array_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_videojs_vhs_utils_dist_decode_b64_to_uint8_array_js__WEBPACK_IMPORTED_MODULE_4__);
+/*! @name m3u8-parser @version 4.5.0 @license Apache-2.0 */
+
+
+
+
+
+
+/**
+ * A stream that buffers string input and generates a `data` event for each
+ * line.
+ *
+ * @class LineStream
+ * @extends Stream
+ */
+
+var LineStream =
+/*#__PURE__*/
+function (_Stream) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_0___default()(LineStream, _Stream);
+
+ function LineStream() {
+ var _this;
+
+ _this = _Stream.call(this) || this;
+ _this.buffer = '';
+ return _this;
+ }
+ /**
+ * Add new data to be parsed.
+ *
+ * @param {string} data the text to process
+ */
+
+
+ var _proto = LineStream.prototype;
+
+ _proto.push = function push(data) {
+ var nextNewline;
+ this.buffer += data;
+ nextNewline = this.buffer.indexOf('\n');
+
+ for (; nextNewline > -1; nextNewline = this.buffer.indexOf('\n')) {
+ this.trigger('data', this.buffer.substring(0, nextNewline));
+ this.buffer = this.buffer.substring(nextNewline + 1);
+ }
+ };
+
+ return LineStream;
+}((_videojs_vhs_utils_dist_stream_js__WEBPACK_IMPORTED_MODULE_1___default()));
+
+/**
+ * "forgiving" attribute list psuedo-grammar:
+ * attributes -> keyvalue (',' keyvalue)*
+ * keyvalue -> key '=' value
+ * key -> [^=]*
+ * value -> '"' [^"]* '"' | [^,]*
+ */
+
+var attributeSeparator = function attributeSeparator() {
+ var key = '[^=]*';
+ var value = '"[^"]*"|[^,]*';
+ var keyvalue = '(?:' + key + ')=(?:' + value + ')';
+ return new RegExp('(?:^|,)(' + keyvalue + ')');
+};
+/**
+ * Parse attributes from a line given the separator
+ *
+ * @param {string} attributes the attribute line to parse
+ */
+
+
+var parseAttributes = function parseAttributes(attributes) {
+ // split the string using attributes as the separator
+ var attrs = attributes.split(attributeSeparator());
+ var result = {};
+ var i = attrs.length;
+ var attr;
+
+ while (i--) {
+ // filter out unmatched portions of the string
+ if (attrs[i] === '') {
+ continue;
+ } // split the key and value
+
+
+ attr = /([^=]*)=(.*)/.exec(attrs[i]).slice(1); // trim whitespace and remove optional quotes around the value
+
+ attr[0] = attr[0].replace(/^\s+|\s+$/g, '');
+ attr[1] = attr[1].replace(/^\s+|\s+$/g, '');
+ attr[1] = attr[1].replace(/^['"](.*)['"]$/g, '$1');
+ result[attr[0]] = attr[1];
+ }
+
+ return result;
+};
+/**
+ * A line-level M3U8 parser event stream. It expects to receive input one
+ * line at a time and performs a context-free parse of its contents. A stream
+ * interpretation of a manifest can be useful if the manifest is expected to
+ * be too large to fit comfortably into memory or the entirety of the input
+ * is not immediately available. Otherwise, it's probably much easier to work
+ * with a regular `Parser` object.
+ *
+ * Produces `data` events with an object that captures the parser's
+ * interpretation of the input. That object has a property `tag` that is one
+ * of `uri`, `comment`, or `tag`. URIs only have a single additional
+ * property, `line`, which captures the entirety of the input without
+ * interpretation. Comments similarly have a single additional property
+ * `text` which is the input without the leading `#`.
+ *
+ * Tags always have a property `tagType` which is the lower-cased version of
+ * the M3U8 directive without the `#EXT` or `#EXT-X-` prefix. For instance,
+ * `#EXT-X-MEDIA-SEQUENCE` becomes `media-sequence` when parsed. Unrecognized
+ * tags are given the tag type `unknown` and a single additional property
+ * `data` with the remainder of the input.
+ *
+ * @class ParseStream
+ * @extends Stream
+ */
+
+
+var ParseStream =
+/*#__PURE__*/
+function (_Stream) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_0___default()(ParseStream, _Stream);
+
+ function ParseStream() {
+ var _this;
+
+ _this = _Stream.call(this) || this;
+ _this.customParsers = [];
+ _this.tagMappers = [];
+ return _this;
+ }
+ /**
+ * Parses an additional line of input.
+ *
+ * @param {string} line a single line of an M3U8 file to parse
+ */
+
+
+ var _proto = ParseStream.prototype;
+
+ _proto.push = function push(line) {
+ var _this2 = this;
+
+ var match;
+ var event; // strip whitespace
+
+ line = line.trim();
+
+ if (line.length === 0) {
+ // ignore empty lines
+ return;
+ } // URIs
+
+
+ if (line[0] !== '#') {
+ this.trigger('data', {
+ type: 'uri',
+ uri: line
+ });
+ return;
+ } // map tags
+
+
+ var newLines = this.tagMappers.reduce(function (acc, mapper) {
+ var mappedLine = mapper(line); // skip if unchanged
+
+ if (mappedLine === line) {
+ return acc;
+ }
+
+ return acc.concat([mappedLine]);
+ }, [line]);
+ newLines.forEach(function (newLine) {
+ for (var i = 0; i < _this2.customParsers.length; i++) {
+ if (_this2.customParsers[i].call(_this2, newLine)) {
+ return;
+ }
+ } // Comments
+
+
+ if (newLine.indexOf('#EXT') !== 0) {
+ _this2.trigger('data', {
+ type: 'comment',
+ text: newLine.slice(1)
+ });
+
+ return;
+ } // strip off any carriage returns here so the regex matching
+ // doesn't have to account for them.
+
+
+ newLine = newLine.replace('\r', ''); // Tags
+
+ match = /^#EXTM3U/.exec(newLine);
+
+ if (match) {
+ _this2.trigger('data', {
+ type: 'tag',
+ tagType: 'm3u'
+ });
+
+ return;
+ }
+
+ match = /^#EXTINF:?([0-9\.]*)?,?(.*)?$/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'inf'
+ };
+
+ if (match[1]) {
+ event.duration = parseFloat(match[1]);
+ }
+
+ if (match[2]) {
+ event.title = match[2];
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-TARGETDURATION:?([0-9.]*)?/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'targetduration'
+ };
+
+ if (match[1]) {
+ event.duration = parseInt(match[1], 10);
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#ZEN-TOTAL-DURATION:?([0-9.]*)?/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'totalduration'
+ };
+
+ if (match[1]) {
+ event.duration = parseInt(match[1], 10);
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-VERSION:?([0-9.]*)?/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'version'
+ };
+
+ if (match[1]) {
+ event.version = parseInt(match[1], 10);
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-MEDIA-SEQUENCE:?(\-?[0-9.]*)?/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'media-sequence'
+ };
+
+ if (match[1]) {
+ event.number = parseInt(match[1], 10);
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-DISCONTINUITY-SEQUENCE:?(\-?[0-9.]*)?/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'discontinuity-sequence'
+ };
+
+ if (match[1]) {
+ event.number = parseInt(match[1], 10);
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-PLAYLIST-TYPE:?(.*)?$/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'playlist-type'
+ };
+
+ if (match[1]) {
+ event.playlistType = match[1];
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-BYTERANGE:?([0-9.]*)?@?([0-9.]*)?/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'byterange'
+ };
+
+ if (match[1]) {
+ event.length = parseInt(match[1], 10);
+ }
+
+ if (match[2]) {
+ event.offset = parseInt(match[2], 10);
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-ALLOW-CACHE:?(YES|NO)?/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'allow-cache'
+ };
+
+ if (match[1]) {
+ event.allowed = !/NO/.test(match[1]);
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-MAP:?(.*)$/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'map'
+ };
+
+ if (match[1]) {
+ var attributes = parseAttributes(match[1]);
+
+ if (attributes.URI) {
+ event.uri = attributes.URI;
+ }
+
+ if (attributes.BYTERANGE) {
+ var _attributes$BYTERANGE = attributes.BYTERANGE.split('@'),
+ length = _attributes$BYTERANGE[0],
+ offset = _attributes$BYTERANGE[1];
+
+ event.byterange = {};
+
+ if (length) {
+ event.byterange.length = parseInt(length, 10);
+ }
+
+ if (offset) {
+ event.byterange.offset = parseInt(offset, 10);
+ }
+ }
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-STREAM-INF:?(.*)$/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'stream-inf'
+ };
+
+ if (match[1]) {
+ event.attributes = parseAttributes(match[1]);
+
+ if (event.attributes.RESOLUTION) {
+ var split = event.attributes.RESOLUTION.split('x');
+ var resolution = {};
+
+ if (split[0]) {
+ resolution.width = parseInt(split[0], 10);
+ }
+
+ if (split[1]) {
+ resolution.height = parseInt(split[1], 10);
+ }
+
+ event.attributes.RESOLUTION = resolution;
+ }
+
+ if (event.attributes.BANDWIDTH) {
+ event.attributes.BANDWIDTH = parseInt(event.attributes.BANDWIDTH, 10);
+ }
+
+ if (event.attributes['PROGRAM-ID']) {
+ event.attributes['PROGRAM-ID'] = parseInt(event.attributes['PROGRAM-ID'], 10);
+ }
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-MEDIA:?(.*)$/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'media'
+ };
+
+ if (match[1]) {
+ event.attributes = parseAttributes(match[1]);
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-ENDLIST/.exec(newLine);
+
+ if (match) {
+ _this2.trigger('data', {
+ type: 'tag',
+ tagType: 'endlist'
+ });
+
+ return;
+ }
+
+ match = /^#EXT-X-DISCONTINUITY/.exec(newLine);
+
+ if (match) {
+ _this2.trigger('data', {
+ type: 'tag',
+ tagType: 'discontinuity'
+ });
+
+ return;
+ }
+
+ match = /^#EXT-X-PROGRAM-DATE-TIME:?(.*)$/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'program-date-time'
+ };
+
+ if (match[1]) {
+ event.dateTimeString = match[1];
+ event.dateTimeObject = new Date(match[1]);
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-KEY:?(.*)$/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'key'
+ };
+
+ if (match[1]) {
+ event.attributes = parseAttributes(match[1]); // parse the IV string into a Uint32Array
+
+ if (event.attributes.IV) {
+ if (event.attributes.IV.substring(0, 2).toLowerCase() === '0x') {
+ event.attributes.IV = event.attributes.IV.substring(2);
+ }
+
+ event.attributes.IV = event.attributes.IV.match(/.{8}/g);
+ event.attributes.IV[0] = parseInt(event.attributes.IV[0], 16);
+ event.attributes.IV[1] = parseInt(event.attributes.IV[1], 16);
+ event.attributes.IV[2] = parseInt(event.attributes.IV[2], 16);
+ event.attributes.IV[3] = parseInt(event.attributes.IV[3], 16);
+ event.attributes.IV = new Uint32Array(event.attributes.IV);
+ }
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-START:?(.*)$/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'start'
+ };
+
+ if (match[1]) {
+ event.attributes = parseAttributes(match[1]);
+ event.attributes['TIME-OFFSET'] = parseFloat(event.attributes['TIME-OFFSET']);
+ event.attributes.PRECISE = /YES/.test(event.attributes.PRECISE);
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-CUE-OUT-CONT:?(.*)?$/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'cue-out-cont'
+ };
+
+ if (match[1]) {
+ event.data = match[1];
+ } else {
+ event.data = '';
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-CUE-OUT:?(.*)?$/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'cue-out'
+ };
+
+ if (match[1]) {
+ event.data = match[1];
+ } else {
+ event.data = '';
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ }
+
+ match = /^#EXT-X-CUE-IN:?(.*)?$/.exec(newLine);
+
+ if (match) {
+ event = {
+ type: 'tag',
+ tagType: 'cue-in'
+ };
+
+ if (match[1]) {
+ event.data = match[1];
+ } else {
+ event.data = '';
+ }
+
+ _this2.trigger('data', event);
+
+ return;
+ } // unknown tag type
+
+
+ _this2.trigger('data', {
+ type: 'tag',
+ data: newLine.slice(4)
+ });
+ });
+ }
+ /**
+ * Add a parser for custom headers
+ *
+ * @param {Object} options a map of options for the added parser
+ * @param {RegExp} options.expression a regular expression to match the custom header
+ * @param {string} options.customType the custom type to register to the output
+ * @param {Function} [options.dataParser] function to parse the line into an object
+ * @param {boolean} [options.segment] should tag data be attached to the segment object
+ */
+ ;
+
+ _proto.addParser = function addParser(_ref) {
+ var _this3 = this;
+
+ var expression = _ref.expression,
+ customType = _ref.customType,
+ dataParser = _ref.dataParser,
+ segment = _ref.segment;
+
+ if (typeof dataParser !== 'function') {
+ dataParser = function dataParser(line) {
+ return line;
+ };
+ }
+
+ this.customParsers.push(function (line) {
+ var match = expression.exec(line);
+
+ if (match) {
+ _this3.trigger('data', {
+ type: 'custom',
+ data: dataParser(line),
+ customType: customType,
+ segment: segment
+ });
+
+ return true;
+ }
+ });
+ }
+ /**
+ * Add a custom header mapper
+ *
+ * @param {Object} options
+ * @param {RegExp} options.expression a regular expression to match the custom header
+ * @param {Function} options.map function to translate tag into a different tag
+ */
+ ;
+
+ _proto.addTagMapper = function addTagMapper(_ref2) {
+ var expression = _ref2.expression,
+ map = _ref2.map;
+
+ var mapFn = function mapFn(line) {
+ if (expression.test(line)) {
+ return map(line);
+ }
+
+ return line;
+ };
+
+ this.tagMappers.push(mapFn);
+ };
+
+ return ParseStream;
+}((_videojs_vhs_utils_dist_stream_js__WEBPACK_IMPORTED_MODULE_1___default()));
+
+/**
+ * A parser for M3U8 files. The current interpretation of the input is
+ * exposed as a property `manifest` on parser objects. It's just two lines to
+ * create and parse a manifest once you have the contents available as a string:
+ *
+ * ```js
+ * var parser = new m3u8.Parser();
+ * parser.push(xhr.responseText);
+ * ```
+ *
+ * New input can later be applied to update the manifest object by calling
+ * `push` again.
+ *
+ * The parser attempts to create a usable manifest object even if the
+ * underlying input is somewhat nonsensical. It emits `info` and `warning`
+ * events during the parse if it encounters input that seems invalid or
+ * requires some property of the manifest object to be defaulted.
+ *
+ * @class Parser
+ * @extends Stream
+ */
+
+var Parser =
+/*#__PURE__*/
+function (_Stream) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_0___default()(Parser, _Stream);
+
+ function Parser() {
+ var _this;
+
+ _this = _Stream.call(this) || this;
+ _this.lineStream = new LineStream();
+ _this.parseStream = new ParseStream();
+
+ _this.lineStream.pipe(_this.parseStream);
+ /* eslint-disable consistent-this */
+
+
+ var self = _babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3___default()(_this);
+ /* eslint-enable consistent-this */
+
+
+ var uris = [];
+ var currentUri = {}; // if specified, the active EXT-X-MAP definition
+
+ var currentMap; // if specified, the active decryption key
+
+ var _key;
+
+ var noop = function noop() {};
+
+ var defaultMediaGroups = {
+ 'AUDIO': {},
+ 'VIDEO': {},
+ 'CLOSED-CAPTIONS': {},
+ 'SUBTITLES': {}
+ }; // This is the Widevine UUID from DASH IF IOP. The same exact string is
+ // used in MPDs with Widevine encrypted streams.
+
+ var widevineUuid = 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed'; // group segments into numbered timelines delineated by discontinuities
+
+ var currentTimeline = 0; // the manifest is empty until the parse stream begins delivering data
+
+ _this.manifest = {
+ allowCache: true,
+ discontinuityStarts: [],
+ segments: []
+ }; // keep track of the last seen segment's byte range end, as segments are not required
+ // to provide the offset, in which case it defaults to the next byte after the
+ // previous segment
+
+ var lastByterangeEnd = 0; // update the manifest with the m3u8 entry from the parse stream
+
+ _this.parseStream.on('data', function (entry) {
+ var mediaGroup;
+ var rendition;
+ ({
+ tag: function tag() {
+ // switch based on the tag type
+ (({
+ 'allow-cache': function allowCache() {
+ this.manifest.allowCache = entry.allowed;
+
+ if (!('allowed' in entry)) {
+ this.trigger('info', {
+ message: 'defaulting allowCache to YES'
+ });
+ this.manifest.allowCache = true;
+ }
+ },
+ byterange: function byterange() {
+ var byterange = {};
+
+ if ('length' in entry) {
+ currentUri.byterange = byterange;
+ byterange.length = entry.length;
+
+ if (!('offset' in entry)) {
+ /*
+ * From the latest spec (as of this writing):
+ * https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.2.2
+ *
+ * Same text since EXT-X-BYTERANGE's introduction in draft 7:
+ * https://tools.ietf.org/html/draft-pantos-http-live-streaming-07#section-3.3.1)
+ *
+ * "If o [offset] is not present, the sub-range begins at the next byte
+ * following the sub-range of the previous media segment."
+ */
+ entry.offset = lastByterangeEnd;
+ }
+ }
+
+ if ('offset' in entry) {
+ currentUri.byterange = byterange;
+ byterange.offset = entry.offset;
+ }
+
+ lastByterangeEnd = byterange.offset + byterange.length;
+ },
+ endlist: function endlist() {
+ this.manifest.endList = true;
+ },
+ inf: function inf() {
+ if (!('mediaSequence' in this.manifest)) {
+ this.manifest.mediaSequence = 0;
+ this.trigger('info', {
+ message: 'defaulting media sequence to zero'
+ });
+ }
+
+ if (!('discontinuitySequence' in this.manifest)) {
+ this.manifest.discontinuitySequence = 0;
+ this.trigger('info', {
+ message: 'defaulting discontinuity sequence to zero'
+ });
+ }
+
+ if (entry.duration > 0) {
+ currentUri.duration = entry.duration;
+ }
+
+ if (entry.duration === 0) {
+ currentUri.duration = 0.01;
+ this.trigger('info', {
+ message: 'updating zero segment duration to a small value'
+ });
+ }
+
+ this.manifest.segments = uris;
+ },
+ key: function key() {
+ if (!entry.attributes) {
+ this.trigger('warn', {
+ message: 'ignoring key declaration without attribute list'
+ });
+ return;
+ } // clear the active encryption key
+
+
+ if (entry.attributes.METHOD === 'NONE') {
+ _key = null;
+ return;
+ }
+
+ if (!entry.attributes.URI) {
+ this.trigger('warn', {
+ message: 'ignoring key declaration without URI'
+ });
+ return;
+ } // check if the content is encrypted for Widevine
+ // Widevine/HLS spec: https://storage.googleapis.com/wvdocs/Widevine_DRM_HLS.pdf
+
+
+ if (entry.attributes.KEYFORMAT === widevineUuid) {
+ var VALID_METHODS = ['SAMPLE-AES', 'SAMPLE-AES-CTR', 'SAMPLE-AES-CENC'];
+
+ if (VALID_METHODS.indexOf(entry.attributes.METHOD) === -1) {
+ this.trigger('warn', {
+ message: 'invalid key method provided for Widevine'
+ });
+ return;
+ }
+
+ if (entry.attributes.METHOD === 'SAMPLE-AES-CENC') {
+ this.trigger('warn', {
+ message: 'SAMPLE-AES-CENC is deprecated, please use SAMPLE-AES-CTR instead'
+ });
+ }
+
+ if (entry.attributes.URI.substring(0, 23) !== 'data:text/plain;base64,') {
+ this.trigger('warn', {
+ message: 'invalid key URI provided for Widevine'
+ });
+ return;
+ }
+
+ if (!(entry.attributes.KEYID && entry.attributes.KEYID.substring(0, 2) === '0x')) {
+ this.trigger('warn', {
+ message: 'invalid key ID provided for Widevine'
+ });
+ return;
+ } // if Widevine key attributes are valid, store them as `contentProtection`
+ // on the manifest to emulate Widevine tag structure in a DASH mpd
+
+
+ this.manifest.contentProtection = {
+ 'com.widevine.alpha': {
+ attributes: {
+ schemeIdUri: entry.attributes.KEYFORMAT,
+ // remove '0x' from the key id string
+ keyId: entry.attributes.KEYID.substring(2)
+ },
+ // decode the base64-encoded PSSH box
+ pssh: _videojs_vhs_utils_dist_decode_b64_to_uint8_array_js__WEBPACK_IMPORTED_MODULE_4___default()(entry.attributes.URI.split(',')[1])
+ }
+ };
+ return;
+ }
+
+ if (!entry.attributes.METHOD) {
+ this.trigger('warn', {
+ message: 'defaulting key method to AES-128'
+ });
+ } // setup an encryption key for upcoming segments
+
+
+ _key = {
+ method: entry.attributes.METHOD || 'AES-128',
+ uri: entry.attributes.URI
+ };
+
+ if (typeof entry.attributes.IV !== 'undefined') {
+ _key.iv = entry.attributes.IV;
+ }
+ },
+ 'media-sequence': function mediaSequence() {
+ if (!isFinite(entry.number)) {
+ this.trigger('warn', {
+ message: 'ignoring invalid media sequence: ' + entry.number
+ });
+ return;
+ }
+
+ this.manifest.mediaSequence = entry.number;
+ },
+ 'discontinuity-sequence': function discontinuitySequence() {
+ if (!isFinite(entry.number)) {
+ this.trigger('warn', {
+ message: 'ignoring invalid discontinuity sequence: ' + entry.number
+ });
+ return;
+ }
+
+ this.manifest.discontinuitySequence = entry.number;
+ currentTimeline = entry.number;
+ },
+ 'playlist-type': function playlistType() {
+ if (!/VOD|EVENT/.test(entry.playlistType)) {
+ this.trigger('warn', {
+ message: 'ignoring unknown playlist type: ' + entry.playlist
+ });
+ return;
+ }
+
+ this.manifest.playlistType = entry.playlistType;
+ },
+ map: function map() {
+ currentMap = {};
+
+ if (entry.uri) {
+ currentMap.uri = entry.uri;
+ }
+
+ if (entry.byterange) {
+ currentMap.byterange = entry.byterange;
+ }
+ },
+ 'stream-inf': function streamInf() {
+ this.manifest.playlists = uris;
+ this.manifest.mediaGroups = this.manifest.mediaGroups || defaultMediaGroups;
+
+ if (!entry.attributes) {
+ this.trigger('warn', {
+ message: 'ignoring empty stream-inf attributes'
+ });
+ return;
+ }
+
+ if (!currentUri.attributes) {
+ currentUri.attributes = {};
+ }
+
+ _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_2___default()(currentUri.attributes, entry.attributes);
+ },
+ media: function media() {
+ this.manifest.mediaGroups = this.manifest.mediaGroups || defaultMediaGroups;
+
+ if (!(entry.attributes && entry.attributes.TYPE && entry.attributes['GROUP-ID'] && entry.attributes.NAME)) {
+ this.trigger('warn', {
+ message: 'ignoring incomplete or missing media group'
+ });
+ return;
+ } // find the media group, creating defaults as necessary
+
+
+ var mediaGroupType = this.manifest.mediaGroups[entry.attributes.TYPE];
+ mediaGroupType[entry.attributes['GROUP-ID']] = mediaGroupType[entry.attributes['GROUP-ID']] || {};
+ mediaGroup = mediaGroupType[entry.attributes['GROUP-ID']]; // collect the rendition metadata
+
+ rendition = {
+ default: /yes/i.test(entry.attributes.DEFAULT)
+ };
+
+ if (rendition.default) {
+ rendition.autoselect = true;
+ } else {
+ rendition.autoselect = /yes/i.test(entry.attributes.AUTOSELECT);
+ }
+
+ if (entry.attributes.LANGUAGE) {
+ rendition.language = entry.attributes.LANGUAGE;
+ }
+
+ if (entry.attributes.URI) {
+ rendition.uri = entry.attributes.URI;
+ }
+
+ if (entry.attributes['INSTREAM-ID']) {
+ rendition.instreamId = entry.attributes['INSTREAM-ID'];
+ }
+
+ if (entry.attributes.CHARACTERISTICS) {
+ rendition.characteristics = entry.attributes.CHARACTERISTICS;
+ }
+
+ if (entry.attributes.FORCED) {
+ rendition.forced = /yes/i.test(entry.attributes.FORCED);
+ } // insert the new rendition
+
+
+ mediaGroup[entry.attributes.NAME] = rendition;
+ },
+ discontinuity: function discontinuity() {
+ currentTimeline += 1;
+ currentUri.discontinuity = true;
+ this.manifest.discontinuityStarts.push(uris.length);
+ },
+ 'program-date-time': function programDateTime() {
+ if (typeof this.manifest.dateTimeString === 'undefined') {
+ // PROGRAM-DATE-TIME is a media-segment tag, but for backwards
+ // compatibility, we add the first occurence of the PROGRAM-DATE-TIME tag
+ // to the manifest object
+ // TODO: Consider removing this in future major version
+ this.manifest.dateTimeString = entry.dateTimeString;
+ this.manifest.dateTimeObject = entry.dateTimeObject;
+ }
+
+ currentUri.dateTimeString = entry.dateTimeString;
+ currentUri.dateTimeObject = entry.dateTimeObject;
+ },
+ targetduration: function targetduration() {
+ if (!isFinite(entry.duration) || entry.duration < 0) {
+ this.trigger('warn', {
+ message: 'ignoring invalid target duration: ' + entry.duration
+ });
+ return;
+ }
+
+ this.manifest.targetDuration = entry.duration;
+ },
+ totalduration: function totalduration() {
+ if (!isFinite(entry.duration) || entry.duration < 0) {
+ this.trigger('warn', {
+ message: 'ignoring invalid total duration: ' + entry.duration
+ });
+ return;
+ }
+
+ this.manifest.totalDuration = entry.duration;
+ },
+ start: function start() {
+ if (!entry.attributes || isNaN(entry.attributes['TIME-OFFSET'])) {
+ this.trigger('warn', {
+ message: 'ignoring start declaration without appropriate attribute list'
+ });
+ return;
+ }
+
+ this.manifest.start = {
+ timeOffset: entry.attributes['TIME-OFFSET'],
+ precise: entry.attributes.PRECISE
+ };
+ },
+ 'cue-out': function cueOut() {
+ currentUri.cueOut = entry.data;
+ },
+ 'cue-out-cont': function cueOutCont() {
+ currentUri.cueOutCont = entry.data;
+ },
+ 'cue-in': function cueIn() {
+ currentUri.cueIn = entry.data;
+ }
+ })[entry.tagType] || noop).call(self);
+ },
+ uri: function uri() {
+ currentUri.uri = entry.uri;
+ uris.push(currentUri); // if no explicit duration was declared, use the target duration
+
+ if (this.manifest.targetDuration && !('duration' in currentUri)) {
+ this.trigger('warn', {
+ message: 'defaulting segment duration to the target duration'
+ });
+ currentUri.duration = this.manifest.targetDuration;
+ } // annotate with encryption information, if necessary
+
+
+ if (_key) {
+ currentUri.key = _key;
+ }
+
+ currentUri.timeline = currentTimeline; // annotate with initialization segment information, if necessary
+
+ if (currentMap) {
+ currentUri.map = currentMap;
+ } // prepare for the next URI
+
+
+ currentUri = {};
+ },
+ comment: function comment() {// comments are not important for playback
+ },
+ custom: function custom() {
+ // if this is segment-level data attach the output to the segment
+ if (entry.segment) {
+ currentUri.custom = currentUri.custom || {};
+ currentUri.custom[entry.customType] = entry.data; // if this is manifest-level data attach to the top level manifest object
+ } else {
+ this.manifest.custom = this.manifest.custom || {};
+ this.manifest.custom[entry.customType] = entry.data;
+ }
+ }
+ })[entry.type].call(self);
+ });
+
+ return _this;
+ }
+ /**
+ * Parse the input string and update the manifest object.
+ *
+ * @param {string} chunk a potentially incomplete portion of the manifest
+ */
+
+
+ var _proto = Parser.prototype;
+
+ _proto.push = function push(chunk) {
+ this.lineStream.push(chunk);
+ }
+ /**
+ * Flush any remaining input. This can be handy if the last line of an M3U8
+ * manifest did not contain a trailing newline but the file has been
+ * completely received.
+ */
+ ;
+
+ _proto.end = function end() {
+ // flush any buffered input
+ this.lineStream.push('\n');
+ }
+ /**
+ * Add an additional parser for non-standard tags
+ *
+ * @param {Object} options a map of options for the added parser
+ * @param {RegExp} options.expression a regular expression to match the custom header
+ * @param {string} options.type the type to register to the output
+ * @param {Function} [options.dataParser] function to parse the line into an object
+ * @param {boolean} [options.segment] should tag data be attached to the segment object
+ */
+ ;
+
+ _proto.addParser = function addParser(options) {
+ this.parseStream.addParser(options);
+ }
+ /**
+ * Add a custom header mapper
+ *
+ * @param {Object} options
+ * @param {RegExp} options.expression a regular expression to match the custom header
+ * @param {Function} options.map function to translate tag into a different tag
+ */
+ ;
+
+ _proto.addTagMapper = function addTagMapper(options) {
+ this.parseStream.addTagMapper(options);
+ };
+
+ return Parser;
+}((_videojs_vhs_utils_dist_stream_js__WEBPACK_IMPORTED_MODULE_1___default()));
+
+
+
+
+/***/ }),
+
+/***/ "./resources/css/app.css":
+/*!*******************************!*\
+ !*** ./resources/css/app.css ***!
+ \*******************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+// extracted by mini-css-extract-plugin
+
+
+/***/ }),
+
+/***/ "./node_modules/mpd-parser/dist/mpd-parser.es.js":
+/*!*******************************************************!*\
+ !*** ./node_modules/mpd-parser/dist/mpd-parser.es.js ***!
+ \*******************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */ "VERSION": () => /* binding */ VERSION,
+/* harmony export */ "inheritAttributes": () => /* binding */ inheritAttributes,
+/* harmony export */ "parse": () => /* binding */ parse,
+/* harmony export */ "parseUTCTiming": () => /* binding */ parseUTCTiming,
+/* harmony export */ "stringToMpdXml": () => /* binding */ stringToMpdXml,
+/* harmony export */ "toM3u8": () => /* binding */ toM3u8,
+/* harmony export */ "toPlaylists": () => /* binding */ toPlaylists
+/* harmony export */ });
+/* harmony import */ var _videojs_vhs_utils_dist_resolve_url__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @videojs/vhs-utils/dist/resolve-url */ "./node_modules/@videojs/vhs-utils/dist/resolve-url.js");
+/* harmony import */ var _videojs_vhs_utils_dist_resolve_url__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_videojs_vhs_utils_dist_resolve_url__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var global_window__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! global/window */ "./node_modules/global/window.js");
+/* harmony import */ var global_window__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(global_window__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _videojs_vhs_utils_dist_decode_b64_to_uint8_array__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @videojs/vhs-utils/dist/decode-b64-to-uint8-array */ "./node_modules/@videojs/vhs-utils/dist/decode-b64-to-uint8-array.js");
+/* harmony import */ var _videojs_vhs_utils_dist_decode_b64_to_uint8_array__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_videojs_vhs_utils_dist_decode_b64_to_uint8_array__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var xmldom__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! xmldom */ "./node_modules/xmldom/dom-parser.js");
+/*! @name mpd-parser @version 0.14.0 @license Apache-2.0 */
+
+
+
+
+
+var version = "0.14.0";
+
+var isObject = function isObject(obj) {
+ return !!obj && typeof obj === 'object';
+};
+
+var merge = function merge() {
+ for (var _len = arguments.length, objects = new Array(_len), _key = 0; _key < _len; _key++) {
+ objects[_key] = arguments[_key];
+ }
+
+ return objects.reduce(function (result, source) {
+ Object.keys(source).forEach(function (key) {
+ if (Array.isArray(result[key]) && Array.isArray(source[key])) {
+ result[key] = result[key].concat(source[key]);
+ } else if (isObject(result[key]) && isObject(source[key])) {
+ result[key] = merge(result[key], source[key]);
+ } else {
+ result[key] = source[key];
+ }
+ });
+ return result;
+ }, {});
+};
+var values = function values(o) {
+ return Object.keys(o).map(function (k) {
+ return o[k];
+ });
+};
+
+var range = function range(start, end) {
+ var result = [];
+
+ for (var i = start; i < end; i++) {
+ result.push(i);
+ }
+
+ return result;
+};
+var flatten = function flatten(lists) {
+ return lists.reduce(function (x, y) {
+ return x.concat(y);
+ }, []);
+};
+var from = function from(list) {
+ if (!list.length) {
+ return [];
+ }
+
+ var result = [];
+
+ for (var i = 0; i < list.length; i++) {
+ result.push(list[i]);
+ }
+
+ return result;
+};
+var findIndexes = function findIndexes(l, key) {
+ return l.reduce(function (a, e, i) {
+ if (e[key]) {
+ a.push(i);
+ }
+
+ return a;
+ }, []);
+};
+
+var errors = {
+ INVALID_NUMBER_OF_PERIOD: 'INVALID_NUMBER_OF_PERIOD',
+ DASH_EMPTY_MANIFEST: 'DASH_EMPTY_MANIFEST',
+ DASH_INVALID_XML: 'DASH_INVALID_XML',
+ NO_BASE_URL: 'NO_BASE_URL',
+ MISSING_SEGMENT_INFORMATION: 'MISSING_SEGMENT_INFORMATION',
+ SEGMENT_TIME_UNSPECIFIED: 'SEGMENT_TIME_UNSPECIFIED',
+ UNSUPPORTED_UTC_TIMING_SCHEME: 'UNSUPPORTED_UTC_TIMING_SCHEME'
+};
+
+/**
+ * @typedef {Object} SingleUri
+ * @property {string} uri - relative location of segment
+ * @property {string} resolvedUri - resolved location of segment
+ * @property {Object} byterange - Object containing information on how to make byte range
+ * requests following byte-range-spec per RFC2616.
+ * @property {String} byterange.length - length of range request
+ * @property {String} byterange.offset - byte offset of range request
+ *
+ * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.1
+ */
+
+/**
+ * Converts a URLType node (5.3.9.2.3 Table 13) to a segment object
+ * that conforms to how m3u8-parser is structured
+ *
+ * @see https://github.com/videojs/m3u8-parser
+ *
+ * @param {string} baseUrl - baseUrl provided by nodes
+ * @param {string} source - source url for segment
+ * @param {string} range - optional range used for range calls,
+ * follows RFC 2616, Clause 14.35.1
+ * @return {SingleUri} full segment information transformed into a format similar
+ * to m3u8-parser
+ */
+
+var urlTypeToSegment = function urlTypeToSegment(_ref) {
+ var _ref$baseUrl = _ref.baseUrl,
+ baseUrl = _ref$baseUrl === void 0 ? '' : _ref$baseUrl,
+ _ref$source = _ref.source,
+ source = _ref$source === void 0 ? '' : _ref$source,
+ _ref$range = _ref.range,
+ range = _ref$range === void 0 ? '' : _ref$range,
+ _ref$indexRange = _ref.indexRange,
+ indexRange = _ref$indexRange === void 0 ? '' : _ref$indexRange;
+ var segment = {
+ uri: source,
+ resolvedUri: _videojs_vhs_utils_dist_resolve_url__WEBPACK_IMPORTED_MODULE_0___default()(baseUrl || '', source)
+ };
+
+ if (range || indexRange) {
+ var rangeStr = range ? range : indexRange;
+ var ranges = rangeStr.split('-');
+ var startRange = parseInt(ranges[0], 10);
+ var endRange = parseInt(ranges[1], 10); // byterange should be inclusive according to
+ // RFC 2616, Clause 14.35.1
+
+ segment.byterange = {
+ length: endRange - startRange + 1,
+ offset: startRange
+ };
+ }
+
+ return segment;
+};
+var byteRangeToString = function byteRangeToString(byterange) {
+ // `endRange` is one less than `offset + length` because the HTTP range
+ // header uses inclusive ranges
+ var endRange = byterange.offset + byterange.length - 1;
+ return byterange.offset + "-" + endRange;
+};
+
+/**
+ * Functions for calculating the range of available segments in static and dynamic
+ * manifests.
+ */
+
+var segmentRange = {
+ /**
+ * Returns the entire range of available segments for a static MPD
+ *
+ * @param {Object} attributes
+ * Inheritied MPD attributes
+ * @return {{ start: number, end: number }}
+ * The start and end numbers for available segments
+ */
+ static: function _static(attributes) {
+ var duration = attributes.duration,
+ _attributes$timescale = attributes.timescale,
+ timescale = _attributes$timescale === void 0 ? 1 : _attributes$timescale,
+ sourceDuration = attributes.sourceDuration;
+ return {
+ start: 0,
+ end: Math.ceil(sourceDuration / (duration / timescale))
+ };
+ },
+
+ /**
+ * Returns the current live window range of available segments for a dynamic MPD
+ *
+ * @param {Object} attributes
+ * Inheritied MPD attributes
+ * @return {{ start: number, end: number }}
+ * The start and end numbers for available segments
+ */
+ dynamic: function dynamic(attributes) {
+ var NOW = attributes.NOW,
+ clientOffset = attributes.clientOffset,
+ availabilityStartTime = attributes.availabilityStartTime,
+ _attributes$timescale2 = attributes.timescale,
+ timescale = _attributes$timescale2 === void 0 ? 1 : _attributes$timescale2,
+ duration = attributes.duration,
+ _attributes$start = attributes.start,
+ start = _attributes$start === void 0 ? 0 : _attributes$start,
+ _attributes$minimumUp = attributes.minimumUpdatePeriod,
+ minimumUpdatePeriod = _attributes$minimumUp === void 0 ? 0 : _attributes$minimumUp,
+ _attributes$timeShift = attributes.timeShiftBufferDepth,
+ timeShiftBufferDepth = _attributes$timeShift === void 0 ? Infinity : _attributes$timeShift;
+ var now = (NOW + clientOffset) / 1000;
+ var periodStartWC = availabilityStartTime + start;
+ var periodEndWC = now + minimumUpdatePeriod;
+ var periodDuration = periodEndWC - periodStartWC;
+ var segmentCount = Math.ceil(periodDuration * timescale / duration);
+ var availableStart = Math.floor((now - periodStartWC - timeShiftBufferDepth) * timescale / duration);
+ var availableEnd = Math.floor((now - periodStartWC) * timescale / duration);
+ return {
+ start: Math.max(0, availableStart),
+ end: Math.min(segmentCount, availableEnd)
+ };
+ }
+};
+/**
+ * Maps a range of numbers to objects with information needed to build the corresponding
+ * segment list
+ *
+ * @name toSegmentsCallback
+ * @function
+ * @param {number} number
+ * Number of the segment
+ * @param {number} index
+ * Index of the number in the range list
+ * @return {{ number: Number, duration: Number, timeline: Number, time: Number }}
+ * Object with segment timing and duration info
+ */
+
+/**
+ * Returns a callback for Array.prototype.map for mapping a range of numbers to
+ * information needed to build the segment list.
+ *
+ * @param {Object} attributes
+ * Inherited MPD attributes
+ * @return {toSegmentsCallback}
+ * Callback map function
+ */
+
+var toSegments = function toSegments(attributes) {
+ return function (number, index) {
+ var duration = attributes.duration,
+ _attributes$timescale3 = attributes.timescale,
+ timescale = _attributes$timescale3 === void 0 ? 1 : _attributes$timescale3,
+ periodIndex = attributes.periodIndex,
+ _attributes$startNumb = attributes.startNumber,
+ startNumber = _attributes$startNumb === void 0 ? 1 : _attributes$startNumb;
+ return {
+ number: startNumber + number,
+ duration: duration / timescale,
+ timeline: periodIndex,
+ time: index * duration
+ };
+ };
+};
+/**
+ * Returns a list of objects containing segment timing and duration info used for
+ * building the list of segments. This uses the @duration attribute specified
+ * in the MPD manifest to derive the range of segments.
+ *
+ * @param {Object} attributes
+ * Inherited MPD attributes
+ * @return {{number: number, duration: number, time: number, timeline: number}[]}
+ * List of Objects with segment timing and duration info
+ */
+
+var parseByDuration = function parseByDuration(attributes) {
+ var _attributes$type = attributes.type,
+ type = _attributes$type === void 0 ? 'static' : _attributes$type,
+ duration = attributes.duration,
+ _attributes$timescale4 = attributes.timescale,
+ timescale = _attributes$timescale4 === void 0 ? 1 : _attributes$timescale4,
+ sourceDuration = attributes.sourceDuration;
+
+ var _segmentRange$type = segmentRange[type](attributes),
+ start = _segmentRange$type.start,
+ end = _segmentRange$type.end;
+
+ var segments = range(start, end).map(toSegments(attributes));
+
+ if (type === 'static') {
+ var index = segments.length - 1; // final segment may be less than full segment duration
+
+ segments[index].duration = sourceDuration - duration / timescale * index;
+ }
+
+ return segments;
+};
+
+/**
+ * Translates SegmentBase into a set of segments.
+ * (DASH SPEC Section 5.3.9.3.2) contains a set of nodes. Each
+ * node should be translated into segment.
+ *
+ * @param {Object} attributes
+ * Object containing all inherited attributes from parent elements with attribute
+ * names as keys
+ * @return {Object.} list of segments
+ */
+
+var segmentsFromBase = function segmentsFromBase(attributes) {
+ var baseUrl = attributes.baseUrl,
+ _attributes$initializ = attributes.initialization,
+ initialization = _attributes$initializ === void 0 ? {} : _attributes$initializ,
+ sourceDuration = attributes.sourceDuration,
+ _attributes$indexRang = attributes.indexRange,
+ indexRange = _attributes$indexRang === void 0 ? '' : _attributes$indexRang,
+ duration = attributes.duration; // base url is required for SegmentBase to work, per spec (Section 5.3.9.2.1)
+
+ if (!baseUrl) {
+ throw new Error(errors.NO_BASE_URL);
+ }
+
+ var initSegment = urlTypeToSegment({
+ baseUrl: baseUrl,
+ source: initialization.sourceURL,
+ range: initialization.range
+ });
+ var segment = urlTypeToSegment({
+ baseUrl: baseUrl,
+ source: baseUrl,
+ indexRange: indexRange
+ });
+ segment.map = initSegment; // If there is a duration, use it, otherwise use the given duration of the source
+ // (since SegmentBase is only for one total segment)
+
+ if (duration) {
+ var segmentTimeInfo = parseByDuration(attributes);
+
+ if (segmentTimeInfo.length) {
+ segment.duration = segmentTimeInfo[0].duration;
+ segment.timeline = segmentTimeInfo[0].timeline;
+ }
+ } else if (sourceDuration) {
+ segment.duration = sourceDuration;
+ segment.timeline = 0;
+ } // This is used for mediaSequence
+
+
+ segment.number = 0;
+ return [segment];
+};
+/**
+ * Given a playlist, a sidx box, and a baseUrl, update the segment list of the playlist
+ * according to the sidx information given.
+ *
+ * playlist.sidx has metadadata about the sidx where-as the sidx param
+ * is the parsed sidx box itself.
+ *
+ * @param {Object} playlist the playlist to update the sidx information for
+ * @param {Object} sidx the parsed sidx box
+ * @return {Object} the playlist object with the updated sidx information
+ */
+
+var addSegmentsToPlaylist = function addSegmentsToPlaylist(playlist, sidx, baseUrl) {
+ // Retain init segment information
+ var initSegment = playlist.sidx.map ? playlist.sidx.map : null; // Retain source duration from initial master manifest parsing
+
+ var sourceDuration = playlist.sidx.duration; // Retain source timeline
+
+ var timeline = playlist.timeline || 0;
+ var sidxByteRange = playlist.sidx.byterange;
+ var sidxEnd = sidxByteRange.offset + sidxByteRange.length; // Retain timescale of the parsed sidx
+
+ var timescale = sidx.timescale; // referenceType 1 refers to other sidx boxes
+
+ var mediaReferences = sidx.references.filter(function (r) {
+ return r.referenceType !== 1;
+ });
+ var segments = []; // firstOffset is the offset from the end of the sidx box
+
+ var startIndex = sidxEnd + sidx.firstOffset;
+
+ for (var i = 0; i < mediaReferences.length; i++) {
+ var reference = sidx.references[i]; // size of the referenced (sub)segment
+
+ var size = reference.referencedSize; // duration of the referenced (sub)segment, in the timescale
+ // this will be converted to seconds when generating segments
+
+ var duration = reference.subsegmentDuration; // should be an inclusive range
+
+ var endIndex = startIndex + size - 1;
+ var indexRange = startIndex + "-" + endIndex;
+ var attributes = {
+ baseUrl: baseUrl,
+ timescale: timescale,
+ timeline: timeline,
+ // this is used in parseByDuration
+ periodIndex: timeline,
+ duration: duration,
+ sourceDuration: sourceDuration,
+ indexRange: indexRange
+ };
+ var segment = segmentsFromBase(attributes)[0];
+
+ if (initSegment) {
+ segment.map = initSegment;
+ }
+
+ segments.push(segment);
+ startIndex += size;
+ }
+
+ playlist.segments = segments;
+ return playlist;
+};
+
+var mergeDiscontiguousPlaylists = function mergeDiscontiguousPlaylists(playlists) {
+ var mergedPlaylists = values(playlists.reduce(function (acc, playlist) {
+ // assuming playlist IDs are the same across periods
+ // TODO: handle multiperiod where representation sets are not the same
+ // across periods
+ var name = playlist.attributes.id + (playlist.attributes.lang || ''); // Periods after first
+
+ if (acc[name]) {
+ var _acc$name$segments;
+
+ // first segment of subsequent periods signal a discontinuity
+ if (playlist.segments[0]) {
+ playlist.segments[0].discontinuity = true;
+ }
+
+ (_acc$name$segments = acc[name].segments).push.apply(_acc$name$segments, playlist.segments); // bubble up contentProtection, this assumes all DRM content
+ // has the same contentProtection
+
+
+ if (playlist.attributes.contentProtection) {
+ acc[name].attributes.contentProtection = playlist.attributes.contentProtection;
+ }
+ } else {
+ // first Period
+ acc[name] = playlist;
+ }
+
+ return acc;
+ }, {}));
+ return mergedPlaylists.map(function (playlist) {
+ playlist.discontinuityStarts = findIndexes(playlist.segments, 'discontinuity');
+ return playlist;
+ });
+};
+
+var addSegmentInfoFromSidx = function addSegmentInfoFromSidx(playlists, sidxMapping) {
+ if (sidxMapping === void 0) {
+ sidxMapping = {};
+ }
+
+ if (!Object.keys(sidxMapping).length) {
+ return playlists;
+ }
+
+ for (var i in playlists) {
+ var playlist = playlists[i];
+
+ if (!playlist.sidx) {
+ continue;
+ }
+
+ var sidxKey = playlist.sidx.uri + '-' + byteRangeToString(playlist.sidx.byterange);
+ var sidxMatch = sidxMapping[sidxKey] && sidxMapping[sidxKey].sidx;
+
+ if (playlist.sidx && sidxMatch) {
+ addSegmentsToPlaylist(playlist, sidxMatch, playlist.sidx.resolvedUri);
+ }
+ }
+
+ return playlists;
+};
+
+var formatAudioPlaylist = function formatAudioPlaylist(_ref) {
+ var _attributes;
+
+ var attributes = _ref.attributes,
+ segments = _ref.segments,
+ sidx = _ref.sidx;
+ var playlist = {
+ attributes: (_attributes = {
+ NAME: attributes.id,
+ BANDWIDTH: attributes.bandwidth,
+ CODECS: attributes.codecs
+ }, _attributes['PROGRAM-ID'] = 1, _attributes),
+ uri: '',
+ endList: (attributes.type || 'static') === 'static',
+ timeline: attributes.periodIndex,
+ resolvedUri: '',
+ targetDuration: attributes.duration,
+ segments: segments,
+ mediaSequence: segments.length ? segments[0].number : 1
+ };
+
+ if (attributes.contentProtection) {
+ playlist.contentProtection = attributes.contentProtection;
+ }
+
+ if (sidx) {
+ playlist.sidx = sidx;
+ }
+
+ return playlist;
+};
+var formatVttPlaylist = function formatVttPlaylist(_ref2) {
+ var _m3u8Attributes;
+
+ var attributes = _ref2.attributes,
+ segments = _ref2.segments;
+
+ if (typeof segments === 'undefined') {
+ // vtt tracks may use single file in BaseURL
+ segments = [{
+ uri: attributes.baseUrl,
+ timeline: attributes.periodIndex,
+ resolvedUri: attributes.baseUrl || '',
+ duration: attributes.sourceDuration,
+ number: 0
+ }]; // targetDuration should be the same duration as the only segment
+
+ attributes.duration = attributes.sourceDuration;
+ }
+
+ var m3u8Attributes = (_m3u8Attributes = {
+ NAME: attributes.id,
+ BANDWIDTH: attributes.bandwidth
+ }, _m3u8Attributes['PROGRAM-ID'] = 1, _m3u8Attributes);
+
+ if (attributes.codecs) {
+ m3u8Attributes.CODECS = attributes.codecs;
+ }
+
+ return {
+ attributes: m3u8Attributes,
+ uri: '',
+ endList: (attributes.type || 'static') === 'static',
+ timeline: attributes.periodIndex,
+ resolvedUri: attributes.baseUrl || '',
+ targetDuration: attributes.duration,
+ segments: segments,
+ mediaSequence: segments.length ? segments[0].number : 1
+ };
+};
+var organizeAudioPlaylists = function organizeAudioPlaylists(playlists, sidxMapping) {
+ if (sidxMapping === void 0) {
+ sidxMapping = {};
+ }
+
+ var mainPlaylist;
+ var formattedPlaylists = playlists.reduce(function (a, playlist) {
+ var role = playlist.attributes.role && playlist.attributes.role.value || '';
+ var language = playlist.attributes.lang || '';
+ var label = 'main';
+
+ if (language) {
+ var roleLabel = role ? " (" + role + ")" : '';
+ label = "" + playlist.attributes.lang + roleLabel;
+ } // skip if we already have the highest quality audio for a language
+
+
+ if (a[label] && a[label].playlists[0].attributes.BANDWIDTH > playlist.attributes.bandwidth) {
+ return a;
+ }
+
+ a[label] = {
+ language: language,
+ autoselect: true,
+ default: role === 'main',
+ playlists: addSegmentInfoFromSidx([formatAudioPlaylist(playlist)], sidxMapping),
+ uri: ''
+ };
+
+ if (typeof mainPlaylist === 'undefined' && role === 'main') {
+ mainPlaylist = playlist;
+ mainPlaylist.default = true;
+ }
+
+ return a;
+ }, {}); // if no playlists have role "main", mark the first as main
+
+ if (!mainPlaylist) {
+ var firstLabel = Object.keys(formattedPlaylists)[0];
+ formattedPlaylists[firstLabel].default = true;
+ }
+
+ return formattedPlaylists;
+};
+var organizeVttPlaylists = function organizeVttPlaylists(playlists, sidxMapping) {
+ if (sidxMapping === void 0) {
+ sidxMapping = {};
+ }
+
+ return playlists.reduce(function (a, playlist) {
+ var label = playlist.attributes.lang || 'text'; // skip if we already have subtitles
+
+ if (a[label]) {
+ return a;
+ }
+
+ a[label] = {
+ language: label,
+ default: false,
+ autoselect: false,
+ playlists: addSegmentInfoFromSidx([formatVttPlaylist(playlist)], sidxMapping),
+ uri: ''
+ };
+ return a;
+ }, {});
+};
+var formatVideoPlaylist = function formatVideoPlaylist(_ref3) {
+ var _attributes2;
+
+ var attributes = _ref3.attributes,
+ segments = _ref3.segments,
+ sidx = _ref3.sidx;
+ var playlist = {
+ attributes: (_attributes2 = {
+ NAME: attributes.id,
+ AUDIO: 'audio',
+ SUBTITLES: 'subs',
+ RESOLUTION: {
+ width: attributes.width,
+ height: attributes.height
+ },
+ CODECS: attributes.codecs,
+ BANDWIDTH: attributes.bandwidth
+ }, _attributes2['PROGRAM-ID'] = 1, _attributes2),
+ uri: '',
+ endList: (attributes.type || 'static') === 'static',
+ timeline: attributes.periodIndex,
+ resolvedUri: '',
+ targetDuration: attributes.duration,
+ segments: segments,
+ mediaSequence: segments.length ? segments[0].number : 1
+ };
+
+ if (attributes.contentProtection) {
+ playlist.contentProtection = attributes.contentProtection;
+ }
+
+ if (sidx) {
+ playlist.sidx = sidx;
+ }
+
+ return playlist;
+};
+var toM3u8 = function toM3u8(dashPlaylists, locations, sidxMapping) {
+ var _mediaGroups;
+
+ if (sidxMapping === void 0) {
+ sidxMapping = {};
+ }
+
+ if (!dashPlaylists.length) {
+ return {};
+ } // grab all master attributes
+
+
+ var _dashPlaylists$0$attr = dashPlaylists[0].attributes,
+ duration = _dashPlaylists$0$attr.sourceDuration,
+ _dashPlaylists$0$attr2 = _dashPlaylists$0$attr.type,
+ type = _dashPlaylists$0$attr2 === void 0 ? 'static' : _dashPlaylists$0$attr2,
+ suggestedPresentationDelay = _dashPlaylists$0$attr.suggestedPresentationDelay,
+ minimumUpdatePeriod = _dashPlaylists$0$attr.minimumUpdatePeriod;
+
+ var videoOnly = function videoOnly(_ref4) {
+ var attributes = _ref4.attributes;
+ return attributes.mimeType === 'video/mp4' || attributes.contentType === 'video';
+ };
+
+ var audioOnly = function audioOnly(_ref5) {
+ var attributes = _ref5.attributes;
+ return attributes.mimeType === 'audio/mp4' || attributes.contentType === 'audio';
+ };
+
+ var vttOnly = function vttOnly(_ref6) {
+ var attributes = _ref6.attributes;
+ return attributes.mimeType === 'text/vtt' || attributes.contentType === 'text';
+ };
+
+ var videoPlaylists = mergeDiscontiguousPlaylists(dashPlaylists.filter(videoOnly)).map(formatVideoPlaylist);
+ var audioPlaylists = mergeDiscontiguousPlaylists(dashPlaylists.filter(audioOnly));
+ var vttPlaylists = dashPlaylists.filter(vttOnly);
+ var master = {
+ allowCache: true,
+ discontinuityStarts: [],
+ segments: [],
+ endList: true,
+ mediaGroups: (_mediaGroups = {
+ AUDIO: {},
+ VIDEO: {}
+ }, _mediaGroups['CLOSED-CAPTIONS'] = {}, _mediaGroups.SUBTITLES = {}, _mediaGroups),
+ uri: '',
+ duration: duration,
+ playlists: addSegmentInfoFromSidx(videoPlaylists, sidxMapping)
+ };
+
+ if (minimumUpdatePeriod >= 0) {
+ master.minimumUpdatePeriod = minimumUpdatePeriod * 1000;
+ }
+
+ if (locations) {
+ master.locations = locations;
+ }
+
+ if (type === 'dynamic') {
+ master.suggestedPresentationDelay = suggestedPresentationDelay;
+ }
+
+ if (audioPlaylists.length) {
+ master.mediaGroups.AUDIO.audio = organizeAudioPlaylists(audioPlaylists, sidxMapping);
+ }
+
+ if (vttPlaylists.length) {
+ master.mediaGroups.SUBTITLES.subs = organizeVttPlaylists(vttPlaylists, sidxMapping);
+ }
+
+ return master;
+};
+
+/**
+ * Calculates the R (repetition) value for a live stream (for the final segment
+ * in a manifest where the r value is negative 1)
+ *
+ * @param {Object} attributes
+ * Object containing all inherited attributes from parent elements with attribute
+ * names as keys
+ * @param {number} time
+ * current time (typically the total time up until the final segment)
+ * @param {number} duration
+ * duration property for the given
+ *
+ * @return {number}
+ * R value to reach the end of the given period
+ */
+var getLiveRValue = function getLiveRValue(attributes, time, duration) {
+ var NOW = attributes.NOW,
+ clientOffset = attributes.clientOffset,
+ availabilityStartTime = attributes.availabilityStartTime,
+ _attributes$timescale = attributes.timescale,
+ timescale = _attributes$timescale === void 0 ? 1 : _attributes$timescale,
+ _attributes$start = attributes.start,
+ start = _attributes$start === void 0 ? 0 : _attributes$start,
+ _attributes$minimumUp = attributes.minimumUpdatePeriod,
+ minimumUpdatePeriod = _attributes$minimumUp === void 0 ? 0 : _attributes$minimumUp;
+ var now = (NOW + clientOffset) / 1000;
+ var periodStartWC = availabilityStartTime + start;
+ var periodEndWC = now + minimumUpdatePeriod;
+ var periodDuration = periodEndWC - periodStartWC;
+ return Math.ceil((periodDuration * timescale - time) / duration);
+};
+/**
+ * Uses information provided by SegmentTemplate.SegmentTimeline to determine segment
+ * timing and duration
+ *
+ * @param {Object} attributes
+ * Object containing all inherited attributes from parent elements with attribute
+ * names as keys
+ * @param {Object[]} segmentTimeline
+ * List of objects representing the attributes of each S element contained within
+ *
+ * @return {{number: number, duration: number, time: number, timeline: number}[]}
+ * List of Objects with segment timing and duration info
+ */
+
+
+var parseByTimeline = function parseByTimeline(attributes, segmentTimeline) {
+ var _attributes$type = attributes.type,
+ type = _attributes$type === void 0 ? 'static' : _attributes$type,
+ _attributes$minimumUp2 = attributes.minimumUpdatePeriod,
+ minimumUpdatePeriod = _attributes$minimumUp2 === void 0 ? 0 : _attributes$minimumUp2,
+ _attributes$media = attributes.media,
+ media = _attributes$media === void 0 ? '' : _attributes$media,
+ sourceDuration = attributes.sourceDuration,
+ _attributes$timescale2 = attributes.timescale,
+ timescale = _attributes$timescale2 === void 0 ? 1 : _attributes$timescale2,
+ _attributes$startNumb = attributes.startNumber,
+ startNumber = _attributes$startNumb === void 0 ? 1 : _attributes$startNumb,
+ timeline = attributes.periodIndex;
+ var segments = [];
+ var time = -1;
+
+ for (var sIndex = 0; sIndex < segmentTimeline.length; sIndex++) {
+ var S = segmentTimeline[sIndex];
+ var duration = S.d;
+ var repeat = S.r || 0;
+ var segmentTime = S.t || 0;
+
+ if (time < 0) {
+ // first segment
+ time = segmentTime;
+ }
+
+ if (segmentTime && segmentTime > time) {
+ // discontinuity
+ // TODO: How to handle this type of discontinuity
+ // timeline++ here would treat it like HLS discontuity and content would
+ // get appended without gap
+ // E.G.
+ //
+ //
+ //
+ //
+ // would have $Time$ values of [0, 1, 2, 5]
+ // should this be appened at time positions [0, 1, 2, 3],(#EXT-X-DISCONTINUITY)
+ // or [0, 1, 2, gap, gap, 5]? (#EXT-X-GAP)
+ // does the value of sourceDuration consider this when calculating arbitrary
+ // negative @r repeat value?
+ // E.G. Same elements as above with this added at the end
+ //
+ // with a sourceDuration of 10
+ // Would the 2 gaps be included in the time duration calculations resulting in
+ // 8 segments with $Time$ values of [0, 1, 2, 5, 6, 7, 8, 9] or 10 segments
+ // with $Time$ values of [0, 1, 2, 5, 6, 7, 8, 9, 10, 11] ?
+ time = segmentTime;
+ }
+
+ var count = void 0;
+
+ if (repeat < 0) {
+ var nextS = sIndex + 1;
+
+ if (nextS === segmentTimeline.length) {
+ // last segment
+ if (type === 'dynamic' && minimumUpdatePeriod > 0 && media.indexOf('$Number$') > 0) {
+ count = getLiveRValue(attributes, time, duration);
+ } else {
+ // TODO: This may be incorrect depending on conclusion of TODO above
+ count = (sourceDuration * timescale - time) / duration;
+ }
+ } else {
+ count = (segmentTimeline[nextS].t - time) / duration;
+ }
+ } else {
+ count = repeat + 1;
+ }
+
+ var end = startNumber + segments.length + count;
+ var number = startNumber + segments.length;
+
+ while (number < end) {
+ segments.push({
+ number: number,
+ duration: duration / timescale,
+ time: time,
+ timeline: timeline
+ });
+ time += duration;
+ number++;
+ }
+ }
+
+ return segments;
+};
+
+var identifierPattern = /\$([A-z]*)(?:(%0)([0-9]+)d)?\$/g;
+/**
+ * Replaces template identifiers with corresponding values. To be used as the callback
+ * for String.prototype.replace
+ *
+ * @name replaceCallback
+ * @function
+ * @param {string} match
+ * Entire match of identifier
+ * @param {string} identifier
+ * Name of matched identifier
+ * @param {string} format
+ * Format tag string. Its presence indicates that padding is expected
+ * @param {string} width
+ * Desired length of the replaced value. Values less than this width shall be left
+ * zero padded
+ * @return {string}
+ * Replacement for the matched identifier
+ */
+
+/**
+ * Returns a function to be used as a callback for String.prototype.replace to replace
+ * template identifiers
+ *
+ * @param {Obect} values
+ * Object containing values that shall be used to replace known identifiers
+ * @param {number} values.RepresentationID
+ * Value of the Representation@id attribute
+ * @param {number} values.Number
+ * Number of the corresponding segment
+ * @param {number} values.Bandwidth
+ * Value of the Representation@bandwidth attribute.
+ * @param {number} values.Time
+ * Timestamp value of the corresponding segment
+ * @return {replaceCallback}
+ * Callback to be used with String.prototype.replace to replace identifiers
+ */
+
+var identifierReplacement = function identifierReplacement(values) {
+ return function (match, identifier, format, width) {
+ if (match === '$$') {
+ // escape sequence
+ return '$';
+ }
+
+ if (typeof values[identifier] === 'undefined') {
+ return match;
+ }
+
+ var value = '' + values[identifier];
+
+ if (identifier === 'RepresentationID') {
+ // Format tag shall not be present with RepresentationID
+ return value;
+ }
+
+ if (!format) {
+ width = 1;
+ } else {
+ width = parseInt(width, 10);
+ }
+
+ if (value.length >= width) {
+ return value;
+ }
+
+ return "" + new Array(width - value.length + 1).join('0') + value;
+ };
+};
+/**
+ * Constructs a segment url from a template string
+ *
+ * @param {string} url
+ * Template string to construct url from
+ * @param {Obect} values
+ * Object containing values that shall be used to replace known identifiers
+ * @param {number} values.RepresentationID
+ * Value of the Representation@id attribute
+ * @param {number} values.Number
+ * Number of the corresponding segment
+ * @param {number} values.Bandwidth
+ * Value of the Representation@bandwidth attribute.
+ * @param {number} values.Time
+ * Timestamp value of the corresponding segment
+ * @return {string}
+ * Segment url with identifiers replaced
+ */
+
+var constructTemplateUrl = function constructTemplateUrl(url, values) {
+ return url.replace(identifierPattern, identifierReplacement(values));
+};
+/**
+ * Generates a list of objects containing timing and duration information about each
+ * segment needed to generate segment uris and the complete segment object
+ *
+ * @param {Object} attributes
+ * Object containing all inherited attributes from parent elements with attribute
+ * names as keys
+ * @param {Object[]|undefined} segmentTimeline
+ * List of objects representing the attributes of each S element contained within
+ * the SegmentTimeline element
+ * @return {{number: number, duration: number, time: number, timeline: number}[]}
+ * List of Objects with segment timing and duration info
+ */
+
+var parseTemplateInfo = function parseTemplateInfo(attributes, segmentTimeline) {
+ if (!attributes.duration && !segmentTimeline) {
+ // if neither @duration or SegmentTimeline are present, then there shall be exactly
+ // one media segment
+ return [{
+ number: attributes.startNumber || 1,
+ duration: attributes.sourceDuration,
+ time: 0,
+ timeline: attributes.periodIndex
+ }];
+ }
+
+ if (attributes.duration) {
+ return parseByDuration(attributes);
+ }
+
+ return parseByTimeline(attributes, segmentTimeline);
+};
+/**
+ * Generates a list of segments using information provided by the SegmentTemplate element
+ *
+ * @param {Object} attributes
+ * Object containing all inherited attributes from parent elements with attribute
+ * names as keys
+ * @param {Object[]|undefined} segmentTimeline
+ * List of objects representing the attributes of each S element contained within
+ * the SegmentTimeline element
+ * @return {Object[]}
+ * List of segment objects
+ */
+
+var segmentsFromTemplate = function segmentsFromTemplate(attributes, segmentTimeline) {
+ var templateValues = {
+ RepresentationID: attributes.id,
+ Bandwidth: attributes.bandwidth || 0
+ };
+ var _attributes$initializ = attributes.initialization,
+ initialization = _attributes$initializ === void 0 ? {
+ sourceURL: '',
+ range: ''
+ } : _attributes$initializ;
+ var mapSegment = urlTypeToSegment({
+ baseUrl: attributes.baseUrl,
+ source: constructTemplateUrl(initialization.sourceURL, templateValues),
+ range: initialization.range
+ });
+ var segments = parseTemplateInfo(attributes, segmentTimeline);
+ return segments.map(function (segment) {
+ templateValues.Number = segment.number;
+ templateValues.Time = segment.time;
+ var uri = constructTemplateUrl(attributes.media || '', templateValues);
+ return {
+ uri: uri,
+ timeline: segment.timeline,
+ duration: segment.duration,
+ resolvedUri: _videojs_vhs_utils_dist_resolve_url__WEBPACK_IMPORTED_MODULE_0___default()(attributes.baseUrl || '', uri),
+ map: mapSegment,
+ number: segment.number
+ };
+ });
+};
+
+/**
+ * Converts a (of type URLType from the DASH spec 5.3.9.2 Table 14)
+ * to an object that matches the output of a segment in videojs/mpd-parser
+ *
+ * @param {Object} attributes
+ * Object containing all inherited attributes from parent elements with attribute
+ * names as keys
+ * @param {Object} segmentUrl
+ * node to translate into a segment object
+ * @return {Object} translated segment object
+ */
+
+var SegmentURLToSegmentObject = function SegmentURLToSegmentObject(attributes, segmentUrl) {
+ var baseUrl = attributes.baseUrl,
+ _attributes$initializ = attributes.initialization,
+ initialization = _attributes$initializ === void 0 ? {} : _attributes$initializ;
+ var initSegment = urlTypeToSegment({
+ baseUrl: baseUrl,
+ source: initialization.sourceURL,
+ range: initialization.range
+ });
+ var segment = urlTypeToSegment({
+ baseUrl: baseUrl,
+ source: segmentUrl.media,
+ range: segmentUrl.mediaRange
+ });
+ segment.map = initSegment;
+ return segment;
+};
+/**
+ * Generates a list of segments using information provided by the SegmentList element
+ * SegmentList (DASH SPEC Section 5.3.9.3.2) contains a set of nodes. Each
+ * node should be translated into segment.
+ *
+ * @param {Object} attributes
+ * Object containing all inherited attributes from parent elements with attribute
+ * names as keys
+ * @param {Object[]|undefined} segmentTimeline
+ * List of objects representing the attributes of each S element contained within
+ * the SegmentTimeline element
+ * @return {Object.} list of segments
+ */
+
+
+var segmentsFromList = function segmentsFromList(attributes, segmentTimeline) {
+ var duration = attributes.duration,
+ _attributes$segmentUr = attributes.segmentUrls,
+ segmentUrls = _attributes$segmentUr === void 0 ? [] : _attributes$segmentUr; // Per spec (5.3.9.2.1) no way to determine segment duration OR
+ // if both SegmentTimeline and @duration are defined, it is outside of spec.
+
+ if (!duration && !segmentTimeline || duration && segmentTimeline) {
+ throw new Error(errors.SEGMENT_TIME_UNSPECIFIED);
+ }
+
+ var segmentUrlMap = segmentUrls.map(function (segmentUrlObject) {
+ return SegmentURLToSegmentObject(attributes, segmentUrlObject);
+ });
+ var segmentTimeInfo;
+
+ if (duration) {
+ segmentTimeInfo = parseByDuration(attributes);
+ }
+
+ if (segmentTimeline) {
+ segmentTimeInfo = parseByTimeline(attributes, segmentTimeline);
+ }
+
+ var segments = segmentTimeInfo.map(function (segmentTime, index) {
+ if (segmentUrlMap[index]) {
+ var segment = segmentUrlMap[index];
+ segment.timeline = segmentTime.timeline;
+ segment.duration = segmentTime.duration;
+ segment.number = segmentTime.number;
+ return segment;
+ } // Since we're mapping we should get rid of any blank segments (in case
+ // the given SegmentTimeline is handling for more elements than we have
+ // SegmentURLs for).
+
+ }).filter(function (segment) {
+ return segment;
+ });
+ return segments;
+};
+
+var generateSegments = function generateSegments(_ref) {
+ var attributes = _ref.attributes,
+ segmentInfo = _ref.segmentInfo;
+ var segmentAttributes;
+ var segmentsFn;
+
+ if (segmentInfo.template) {
+ segmentsFn = segmentsFromTemplate;
+ segmentAttributes = merge(attributes, segmentInfo.template);
+ } else if (segmentInfo.base) {
+ segmentsFn = segmentsFromBase;
+ segmentAttributes = merge(attributes, segmentInfo.base);
+ } else if (segmentInfo.list) {
+ segmentsFn = segmentsFromList;
+ segmentAttributes = merge(attributes, segmentInfo.list);
+ }
+
+ var segmentsInfo = {
+ attributes: attributes
+ };
+
+ if (!segmentsFn) {
+ return segmentsInfo;
+ }
+
+ var segments = segmentsFn(segmentAttributes, segmentInfo.timeline); // The @duration attribute will be used to determin the playlist's targetDuration which
+ // must be in seconds. Since we've generated the segment list, we no longer need
+ // @duration to be in @timescale units, so we can convert it here.
+
+ if (segmentAttributes.duration) {
+ var _segmentAttributes = segmentAttributes,
+ duration = _segmentAttributes.duration,
+ _segmentAttributes$ti = _segmentAttributes.timescale,
+ timescale = _segmentAttributes$ti === void 0 ? 1 : _segmentAttributes$ti;
+ segmentAttributes.duration = duration / timescale;
+ } else if (segments.length) {
+ // if there is no @duration attribute, use the largest segment duration as
+ // as target duration
+ segmentAttributes.duration = segments.reduce(function (max, segment) {
+ return Math.max(max, Math.ceil(segment.duration));
+ }, 0);
+ } else {
+ segmentAttributes.duration = 0;
+ }
+
+ segmentsInfo.attributes = segmentAttributes;
+ segmentsInfo.segments = segments; // This is a sidx box without actual segment information
+
+ if (segmentInfo.base && segmentAttributes.indexRange) {
+ segmentsInfo.sidx = segments[0];
+ segmentsInfo.segments = [];
+ }
+
+ return segmentsInfo;
+};
+var toPlaylists = function toPlaylists(representations) {
+ return representations.map(generateSegments);
+};
+
+var findChildren = function findChildren(element, name) {
+ return from(element.childNodes).filter(function (_ref) {
+ var tagName = _ref.tagName;
+ return tagName === name;
+ });
+};
+var getContent = function getContent(element) {
+ return element.textContent.trim();
+};
+
+var parseDuration = function parseDuration(str) {
+ var SECONDS_IN_YEAR = 365 * 24 * 60 * 60;
+ var SECONDS_IN_MONTH = 30 * 24 * 60 * 60;
+ var SECONDS_IN_DAY = 24 * 60 * 60;
+ var SECONDS_IN_HOUR = 60 * 60;
+ var SECONDS_IN_MIN = 60; // P10Y10M10DT10H10M10.1S
+
+ var durationRegex = /P(?:(\d*)Y)?(?:(\d*)M)?(?:(\d*)D)?(?:T(?:(\d*)H)?(?:(\d*)M)?(?:([\d.]*)S)?)?/;
+ var match = durationRegex.exec(str);
+
+ if (!match) {
+ return 0;
+ }
+
+ var _match$slice = match.slice(1),
+ year = _match$slice[0],
+ month = _match$slice[1],
+ day = _match$slice[2],
+ hour = _match$slice[3],
+ minute = _match$slice[4],
+ second = _match$slice[5];
+
+ return parseFloat(year || 0) * SECONDS_IN_YEAR + parseFloat(month || 0) * SECONDS_IN_MONTH + parseFloat(day || 0) * SECONDS_IN_DAY + parseFloat(hour || 0) * SECONDS_IN_HOUR + parseFloat(minute || 0) * SECONDS_IN_MIN + parseFloat(second || 0);
+};
+var parseDate = function parseDate(str) {
+ // Date format without timezone according to ISO 8601
+ // YYY-MM-DDThh:mm:ss.ssssss
+ var dateRegex = /^\d+-\d+-\d+T\d+:\d+:\d+(\.\d+)?$/; // If the date string does not specifiy a timezone, we must specifiy UTC. This is
+ // expressed by ending with 'Z'
+
+ if (dateRegex.test(str)) {
+ str += 'Z';
+ }
+
+ return Date.parse(str);
+};
+
+var parsers = {
+ /**
+ * Specifies the duration of the entire Media Presentation. Format is a duration string
+ * as specified in ISO 8601
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The duration in seconds
+ */
+ mediaPresentationDuration: function mediaPresentationDuration(value) {
+ return parseDuration(value);
+ },
+
+ /**
+ * Specifies the Segment availability start time for all Segments referred to in this
+ * MPD. For a dynamic manifest, it specifies the anchor for the earliest availability
+ * time. Format is a date string as specified in ISO 8601
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The date as seconds from unix epoch
+ */
+ availabilityStartTime: function availabilityStartTime(value) {
+ return parseDate(value) / 1000;
+ },
+
+ /**
+ * Specifies the smallest period between potential changes to the MPD. Format is a
+ * duration string as specified in ISO 8601
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The duration in seconds
+ */
+ minimumUpdatePeriod: function minimumUpdatePeriod(value) {
+ return parseDuration(value);
+ },
+
+ /**
+ * Specifies the suggested presentation delay. Format is a
+ * duration string as specified in ISO 8601
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The duration in seconds
+ */
+ suggestedPresentationDelay: function suggestedPresentationDelay(value) {
+ return parseDuration(value);
+ },
+
+ /**
+ * specifices the type of mpd. Can be either "static" or "dynamic"
+ *
+ * @param {string} value
+ * value of attribute as a string
+ *
+ * @return {string}
+ * The type as a string
+ */
+ type: function type(value) {
+ return value;
+ },
+
+ /**
+ * Specifies the duration of the smallest time shifting buffer for any Representation
+ * in the MPD. Format is a duration string as specified in ISO 8601
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The duration in seconds
+ */
+ timeShiftBufferDepth: function timeShiftBufferDepth(value) {
+ return parseDuration(value);
+ },
+
+ /**
+ * Specifies the PeriodStart time of the Period relative to the availabilityStarttime.
+ * Format is a duration string as specified in ISO 8601
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The duration in seconds
+ */
+ start: function start(value) {
+ return parseDuration(value);
+ },
+
+ /**
+ * Specifies the width of the visual presentation
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The parsed width
+ */
+ width: function width(value) {
+ return parseInt(value, 10);
+ },
+
+ /**
+ * Specifies the height of the visual presentation
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The parsed height
+ */
+ height: function height(value) {
+ return parseInt(value, 10);
+ },
+
+ /**
+ * Specifies the bitrate of the representation
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The parsed bandwidth
+ */
+ bandwidth: function bandwidth(value) {
+ return parseInt(value, 10);
+ },
+
+ /**
+ * Specifies the number of the first Media Segment in this Representation in the Period
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The parsed number
+ */
+ startNumber: function startNumber(value) {
+ return parseInt(value, 10);
+ },
+
+ /**
+ * Specifies the timescale in units per seconds
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The aprsed timescale
+ */
+ timescale: function timescale(value) {
+ return parseInt(value, 10);
+ },
+
+ /**
+ * Specifies the constant approximate Segment duration
+ * NOTE: The element also contains an @duration attribute. This duration
+ * specifies the duration of the Period. This attribute is currently not
+ * supported by the rest of the parser, however we still check for it to prevent
+ * errors.
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The parsed duration
+ */
+ duration: function duration(value) {
+ var parsedValue = parseInt(value, 10);
+
+ if (isNaN(parsedValue)) {
+ return parseDuration(value);
+ }
+
+ return parsedValue;
+ },
+
+ /**
+ * Specifies the Segment duration, in units of the value of the @timescale.
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The parsed duration
+ */
+ d: function d(value) {
+ return parseInt(value, 10);
+ },
+
+ /**
+ * Specifies the MPD start time, in @timescale units, the first Segment in the series
+ * starts relative to the beginning of the Period
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The parsed time
+ */
+ t: function t(value) {
+ return parseInt(value, 10);
+ },
+
+ /**
+ * Specifies the repeat count of the number of following contiguous Segments with the
+ * same duration expressed by the value of @d
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {number}
+ * The parsed number
+ */
+ r: function r(value) {
+ return parseInt(value, 10);
+ },
+
+ /**
+ * Default parser for all other attributes. Acts as a no-op and just returns the value
+ * as a string
+ *
+ * @param {string} value
+ * value of attribute as a string
+ * @return {string}
+ * Unparsed value
+ */
+ DEFAULT: function DEFAULT(value) {
+ return value;
+ }
+};
+/**
+ * Gets all the attributes and values of the provided node, parses attributes with known
+ * types, and returns an object with attribute names mapped to values.
+ *
+ * @param {Node} el
+ * The node to parse attributes from
+ * @return {Object}
+ * Object with all attributes of el parsed
+ */
+
+var parseAttributes = function parseAttributes(el) {
+ if (!(el && el.attributes)) {
+ return {};
+ }
+
+ return from(el.attributes).reduce(function (a, e) {
+ var parseFn = parsers[e.name] || parsers.DEFAULT;
+ a[e.name] = parseFn(e.value);
+ return a;
+ }, {});
+};
+
+var keySystemsMap = {
+ 'urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b': 'org.w3.clearkey',
+ 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed': 'com.widevine.alpha',
+ 'urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95': 'com.microsoft.playready',
+ 'urn:uuid:f239e769-efa3-4850-9c16-a903c6932efb': 'com.adobe.primetime'
+};
+/**
+ * Builds a list of urls that is the product of the reference urls and BaseURL values
+ *
+ * @param {string[]} referenceUrls
+ * List of reference urls to resolve to
+ * @param {Node[]} baseUrlElements
+ * List of BaseURL nodes from the mpd
+ * @return {string[]}
+ * List of resolved urls
+ */
+
+var buildBaseUrls = function buildBaseUrls(referenceUrls, baseUrlElements) {
+ if (!baseUrlElements.length) {
+ return referenceUrls;
+ }
+
+ return flatten(referenceUrls.map(function (reference) {
+ return baseUrlElements.map(function (baseUrlElement) {
+ return _videojs_vhs_utils_dist_resolve_url__WEBPACK_IMPORTED_MODULE_0___default()(reference, getContent(baseUrlElement));
+ });
+ }));
+};
+/**
+ * Contains all Segment information for its containing AdaptationSet
+ *
+ * @typedef {Object} SegmentInformation
+ * @property {Object|undefined} template
+ * Contains the attributes for the SegmentTemplate node
+ * @property {Object[]|undefined} timeline
+ * Contains a list of atrributes for each S node within the SegmentTimeline node
+ * @property {Object|undefined} list
+ * Contains the attributes for the SegmentList node
+ * @property {Object|undefined} base
+ * Contains the attributes for the SegmentBase node
+ */
+
+/**
+ * Returns all available Segment information contained within the AdaptationSet node
+ *
+ * @param {Node} adaptationSet
+ * The AdaptationSet node to get Segment information from
+ * @return {SegmentInformation}
+ * The Segment information contained within the provided AdaptationSet
+ */
+
+var getSegmentInformation = function getSegmentInformation(adaptationSet) {
+ var segmentTemplate = findChildren(adaptationSet, 'SegmentTemplate')[0];
+ var segmentList = findChildren(adaptationSet, 'SegmentList')[0];
+ var segmentUrls = segmentList && findChildren(segmentList, 'SegmentURL').map(function (s) {
+ return merge({
+ tag: 'SegmentURL'
+ }, parseAttributes(s));
+ });
+ var segmentBase = findChildren(adaptationSet, 'SegmentBase')[0];
+ var segmentTimelineParentNode = segmentList || segmentTemplate;
+ var segmentTimeline = segmentTimelineParentNode && findChildren(segmentTimelineParentNode, 'SegmentTimeline')[0];
+ var segmentInitializationParentNode = segmentList || segmentBase || segmentTemplate;
+ var segmentInitialization = segmentInitializationParentNode && findChildren(segmentInitializationParentNode, 'Initialization')[0]; // SegmentTemplate is handled slightly differently, since it can have both
+ // @initialization and an node. @initialization can be templated,
+ // while the node can have a url and range specified. If the has
+ // both @initialization and an subelement we opt to override with
+ // the node, as this interaction is not defined in the spec.
+
+ var template = segmentTemplate && parseAttributes(segmentTemplate);
+
+ if (template && segmentInitialization) {
+ template.initialization = segmentInitialization && parseAttributes(segmentInitialization);
+ } else if (template && template.initialization) {
+ // If it is @initialization we convert it to an object since this is the format that
+ // later functions will rely on for the initialization segment. This is only valid
+ // for
+ template.initialization = {
+ sourceURL: template.initialization
+ };
+ }
+
+ var segmentInfo = {
+ template: template,
+ timeline: segmentTimeline && findChildren(segmentTimeline, 'S').map(function (s) {
+ return parseAttributes(s);
+ }),
+ list: segmentList && merge(parseAttributes(segmentList), {
+ segmentUrls: segmentUrls,
+ initialization: parseAttributes(segmentInitialization)
+ }),
+ base: segmentBase && merge(parseAttributes(segmentBase), {
+ initialization: parseAttributes(segmentInitialization)
+ })
+ };
+ Object.keys(segmentInfo).forEach(function (key) {
+ if (!segmentInfo[key]) {
+ delete segmentInfo[key];
+ }
+ });
+ return segmentInfo;
+};
+/**
+ * Contains Segment information and attributes needed to construct a Playlist object
+ * from a Representation
+ *
+ * @typedef {Object} RepresentationInformation
+ * @property {SegmentInformation} segmentInfo
+ * Segment information for this Representation
+ * @property {Object} attributes
+ * Inherited attributes for this Representation
+ */
+
+/**
+ * Maps a Representation node to an object containing Segment information and attributes
+ *
+ * @name inheritBaseUrlsCallback
+ * @function
+ * @param {Node} representation
+ * Representation node from the mpd
+ * @return {RepresentationInformation}
+ * Representation information needed to construct a Playlist object
+ */
+
+/**
+ * Returns a callback for Array.prototype.map for mapping Representation nodes to
+ * Segment information and attributes using inherited BaseURL nodes.
+ *
+ * @param {Object} adaptationSetAttributes
+ * Contains attributes inherited by the AdaptationSet
+ * @param {string[]} adaptationSetBaseUrls
+ * Contains list of resolved base urls inherited by the AdaptationSet
+ * @param {SegmentInformation} adaptationSetSegmentInfo
+ * Contains Segment information for the AdaptationSet
+ * @return {inheritBaseUrlsCallback}
+ * Callback map function
+ */
+
+var inheritBaseUrls = function inheritBaseUrls(adaptationSetAttributes, adaptationSetBaseUrls, adaptationSetSegmentInfo) {
+ return function (representation) {
+ var repBaseUrlElements = findChildren(representation, 'BaseURL');
+ var repBaseUrls = buildBaseUrls(adaptationSetBaseUrls, repBaseUrlElements);
+ var attributes = merge(adaptationSetAttributes, parseAttributes(representation));
+ var representationSegmentInfo = getSegmentInformation(representation);
+ return repBaseUrls.map(function (baseUrl) {
+ return {
+ segmentInfo: merge(adaptationSetSegmentInfo, representationSegmentInfo),
+ attributes: merge(attributes, {
+ baseUrl: baseUrl
+ })
+ };
+ });
+ };
+};
+/**
+ * Tranforms a series of content protection nodes to
+ * an object containing pssh data by key system
+ *
+ * @param {Node[]} contentProtectionNodes
+ * Content protection nodes
+ * @return {Object}
+ * Object containing pssh data by key system
+ */
+
+var generateKeySystemInformation = function generateKeySystemInformation(contentProtectionNodes) {
+ return contentProtectionNodes.reduce(function (acc, node) {
+ var attributes = parseAttributes(node);
+ var keySystem = keySystemsMap[attributes.schemeIdUri];
+
+ if (keySystem) {
+ acc[keySystem] = {
+ attributes: attributes
+ };
+ var psshNode = findChildren(node, 'cenc:pssh')[0];
+
+ if (psshNode) {
+ var pssh = getContent(psshNode);
+ var psshBuffer = pssh && _videojs_vhs_utils_dist_decode_b64_to_uint8_array__WEBPACK_IMPORTED_MODULE_2___default()(pssh);
+ acc[keySystem].pssh = psshBuffer;
+ }
+ }
+
+ return acc;
+ }, {});
+};
+/**
+ * Maps an AdaptationSet node to a list of Representation information objects
+ *
+ * @name toRepresentationsCallback
+ * @function
+ * @param {Node} adaptationSet
+ * AdaptationSet node from the mpd
+ * @return {RepresentationInformation[]}
+ * List of objects containing Representaion information
+ */
+
+/**
+ * Returns a callback for Array.prototype.map for mapping AdaptationSet nodes to a list of
+ * Representation information objects
+ *
+ * @param {Object} periodAttributes
+ * Contains attributes inherited by the Period
+ * @param {string[]} periodBaseUrls
+ * Contains list of resolved base urls inherited by the Period
+ * @param {string[]} periodSegmentInfo
+ * Contains Segment Information at the period level
+ * @return {toRepresentationsCallback}
+ * Callback map function
+ */
+
+
+var toRepresentations = function toRepresentations(periodAttributes, periodBaseUrls, periodSegmentInfo) {
+ return function (adaptationSet) {
+ var adaptationSetAttributes = parseAttributes(adaptationSet);
+ var adaptationSetBaseUrls = buildBaseUrls(periodBaseUrls, findChildren(adaptationSet, 'BaseURL'));
+ var role = findChildren(adaptationSet, 'Role')[0];
+ var roleAttributes = {
+ role: parseAttributes(role)
+ };
+ var attrs = merge(periodAttributes, adaptationSetAttributes, roleAttributes);
+ var contentProtection = generateKeySystemInformation(findChildren(adaptationSet, 'ContentProtection'));
+
+ if (Object.keys(contentProtection).length) {
+ attrs = merge(attrs, {
+ contentProtection: contentProtection
+ });
+ }
+
+ var segmentInfo = getSegmentInformation(adaptationSet);
+ var representations = findChildren(adaptationSet, 'Representation');
+ var adaptationSetSegmentInfo = merge(periodSegmentInfo, segmentInfo);
+ return flatten(representations.map(inheritBaseUrls(attrs, adaptationSetBaseUrls, adaptationSetSegmentInfo)));
+ };
+};
+/**
+ * Maps an Period node to a list of Representation inforamtion objects for all
+ * AdaptationSet nodes contained within the Period
+ *
+ * @name toAdaptationSetsCallback
+ * @function
+ * @param {Node} period
+ * Period node from the mpd
+ * @param {number} periodIndex
+ * Index of the Period within the mpd
+ * @return {RepresentationInformation[]}
+ * List of objects containing Representaion information
+ */
+
+/**
+ * Returns a callback for Array.prototype.map for mapping Period nodes to a list of
+ * Representation information objects
+ *
+ * @param {Object} mpdAttributes
+ * Contains attributes inherited by the mpd
+ * @param {string[]} mpdBaseUrls
+ * Contains list of resolved base urls inherited by the mpd
+ * @return {toAdaptationSetsCallback}
+ * Callback map function
+ */
+
+var toAdaptationSets = function toAdaptationSets(mpdAttributes, mpdBaseUrls) {
+ return function (period, index) {
+ var periodBaseUrls = buildBaseUrls(mpdBaseUrls, findChildren(period, 'BaseURL'));
+ var periodAtt = parseAttributes(period);
+ var parsedPeriodId = parseInt(periodAtt.id, 10); // fallback to mapping index if Period@id is not a number
+
+ var periodIndex = global_window__WEBPACK_IMPORTED_MODULE_1___default().isNaN(parsedPeriodId) ? index : parsedPeriodId;
+ var periodAttributes = merge(mpdAttributes, {
+ periodIndex: periodIndex
+ });
+ var adaptationSets = findChildren(period, 'AdaptationSet');
+ var periodSegmentInfo = getSegmentInformation(period);
+ return flatten(adaptationSets.map(toRepresentations(periodAttributes, periodBaseUrls, periodSegmentInfo)));
+ };
+};
+/**
+ * Traverses the mpd xml tree to generate a list of Representation information objects
+ * that have inherited attributes from parent nodes
+ *
+ * @param {Node} mpd
+ * The root node of the mpd
+ * @param {Object} options
+ * Available options for inheritAttributes
+ * @param {string} options.manifestUri
+ * The uri source of the mpd
+ * @param {number} options.NOW
+ * Current time per DASH IOP. Default is current time in ms since epoch
+ * @param {number} options.clientOffset
+ * Client time difference from NOW (in milliseconds)
+ * @return {RepresentationInformation[]}
+ * List of objects containing Representation information
+ */
+
+var inheritAttributes = function inheritAttributes(mpd, options) {
+ if (options === void 0) {
+ options = {};
+ }
+
+ var _options = options,
+ _options$manifestUri = _options.manifestUri,
+ manifestUri = _options$manifestUri === void 0 ? '' : _options$manifestUri,
+ _options$NOW = _options.NOW,
+ NOW = _options$NOW === void 0 ? Date.now() : _options$NOW,
+ _options$clientOffset = _options.clientOffset,
+ clientOffset = _options$clientOffset === void 0 ? 0 : _options$clientOffset;
+ var periods = findChildren(mpd, 'Period');
+
+ if (!periods.length) {
+ throw new Error(errors.INVALID_NUMBER_OF_PERIOD);
+ }
+
+ var locations = findChildren(mpd, 'Location');
+ var mpdAttributes = parseAttributes(mpd);
+ var mpdBaseUrls = buildBaseUrls([manifestUri], findChildren(mpd, 'BaseURL'));
+ mpdAttributes.sourceDuration = mpdAttributes.mediaPresentationDuration || 0;
+ mpdAttributes.NOW = NOW;
+ mpdAttributes.clientOffset = clientOffset;
+
+ if (locations.length) {
+ mpdAttributes.locations = locations.map(getContent);
+ }
+
+ return {
+ locations: mpdAttributes.locations,
+ representationInfo: flatten(periods.map(toAdaptationSets(mpdAttributes, mpdBaseUrls)))
+ };
+};
+
+var stringToMpdXml = function stringToMpdXml(manifestString) {
+ if (manifestString === '') {
+ throw new Error(errors.DASH_EMPTY_MANIFEST);
+ }
+
+ var parser = new xmldom__WEBPACK_IMPORTED_MODULE_3__.DOMParser();
+ var xml = parser.parseFromString(manifestString, 'application/xml');
+ var mpd = xml && xml.documentElement.tagName === 'MPD' ? xml.documentElement : null;
+
+ if (!mpd || mpd && mpd.getElementsByTagName('parsererror').length > 0) {
+ throw new Error(errors.DASH_INVALID_XML);
+ }
+
+ return mpd;
+};
+
+/**
+ * Parses the manifest for a UTCTiming node, returning the nodes attributes if found
+ *
+ * @param {string} mpd
+ * XML string of the MPD manifest
+ * @return {Object|null}
+ * Attributes of UTCTiming node specified in the manifest. Null if none found
+ */
+
+var parseUTCTimingScheme = function parseUTCTimingScheme(mpd) {
+ var UTCTimingNode = findChildren(mpd, 'UTCTiming')[0];
+
+ if (!UTCTimingNode) {
+ return null;
+ }
+
+ var attributes = parseAttributes(UTCTimingNode);
+
+ switch (attributes.schemeIdUri) {
+ case 'urn:mpeg:dash:utc:http-head:2014':
+ case 'urn:mpeg:dash:utc:http-head:2012':
+ attributes.method = 'HEAD';
+ break;
+
+ case 'urn:mpeg:dash:utc:http-xsdate:2014':
+ case 'urn:mpeg:dash:utc:http-iso:2014':
+ case 'urn:mpeg:dash:utc:http-xsdate:2012':
+ case 'urn:mpeg:dash:utc:http-iso:2012':
+ attributes.method = 'GET';
+ break;
+
+ case 'urn:mpeg:dash:utc:direct:2014':
+ case 'urn:mpeg:dash:utc:direct:2012':
+ attributes.method = 'DIRECT';
+ attributes.value = Date.parse(attributes.value);
+ break;
+
+ case 'urn:mpeg:dash:utc:http-ntp:2014':
+ case 'urn:mpeg:dash:utc:ntp:2014':
+ case 'urn:mpeg:dash:utc:sntp:2014':
+ default:
+ throw new Error(errors.UNSUPPORTED_UTC_TIMING_SCHEME);
+ }
+
+ return attributes;
+};
+
+var VERSION = version;
+
+var parse = function parse(manifestString, options) {
+ if (options === void 0) {
+ options = {};
+ }
+
+ var parsedManifestInfo = inheritAttributes(stringToMpdXml(manifestString), options);
+ var playlists = toPlaylists(parsedManifestInfo.representationInfo);
+ return toM3u8(playlists, parsedManifestInfo.locations, options.sidxMapping);
+};
+/**
+ * Parses the manifest for a UTCTiming node, returning the nodes attributes if found
+ *
+ * @param {string} manifestString
+ * XML string of the MPD manifest
+ * @return {Object|null}
+ * Attributes of UTCTiming node specified in the manifest. Null if none found
+ */
+
+
+var parseUTCTiming = function parseUTCTiming(manifestString) {
+ return parseUTCTimingScheme(stringToMpdXml(manifestString));
+};
+
+
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/aac/utils.js":
+/*!**********************************************!*\
+ !*** ./node_modules/mux.js/lib/aac/utils.js ***!
+ \**********************************************/
+/***/ ((module) => {
+
+"use strict";
+/**
+ * mux.js
+ *
+ * Copyright (c) Brightcove
+ * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
+ *
+ * Utilities to detect basic properties and metadata about Aac data.
+ */
+
+
+var ADTS_SAMPLING_FREQUENCIES = [
+ 96000,
+ 88200,
+ 64000,
+ 48000,
+ 44100,
+ 32000,
+ 24000,
+ 22050,
+ 16000,
+ 12000,
+ 11025,
+ 8000,
+ 7350
+];
+
+var parseId3TagSize = function(header, byteIndex) {
+ var
+ returnSize = (header[byteIndex + 6] << 21) |
+ (header[byteIndex + 7] << 14) |
+ (header[byteIndex + 8] << 7) |
+ (header[byteIndex + 9]),
+ flags = header[byteIndex + 5],
+ footerPresent = (flags & 16) >> 4;
+
+ // if we get a negative returnSize clamp it to 0
+ returnSize = returnSize >= 0 ? returnSize : 0;
+
+ if (footerPresent) {
+ return returnSize + 20;
+ }
+ return returnSize + 10;
+};
+
+var getId3Offset = function(data, offset) {
+ if (data.length - offset < 10 ||
+ data[offset] !== 'I'.charCodeAt(0) ||
+ data[offset + 1] !== 'D'.charCodeAt(0) ||
+ data[offset + 2] !== '3'.charCodeAt(0)) {
+ return offset;
+ }
+
+ offset += parseId3TagSize(data, offset);
+
+ return getId3Offset(data, offset);
+};
+
+
+// TODO: use vhs-utils
+var isLikelyAacData = function(data) {
+ var offset = getId3Offset(data, 0);
+
+ return data.length >= offset + 2 &&
+ (data[offset] & 0xFF) === 0xFF &&
+ (data[offset + 1] & 0xF0) === 0xF0 &&
+ // verify that the 2 layer bits are 0, aka this
+ // is not mp3 data but aac data.
+ (data[offset + 1] & 0x16) === 0x10;
+};
+
+var parseSyncSafeInteger = function(data) {
+ return (data[0] << 21) |
+ (data[1] << 14) |
+ (data[2] << 7) |
+ (data[3]);
+};
+
+// return a percent-encoded representation of the specified byte range
+// @see http://en.wikipedia.org/wiki/Percent-encoding
+var percentEncode = function(bytes, start, end) {
+ var i, result = '';
+ for (i = start; i < end; i++) {
+ result += '%' + ('00' + bytes[i].toString(16)).slice(-2);
+ }
+ return result;
+};
+
+// return the string representation of the specified byte range,
+// interpreted as ISO-8859-1.
+var parseIso88591 = function(bytes, start, end) {
+ return unescape(percentEncode(bytes, start, end)); // jshint ignore:line
+};
+
+var parseAdtsSize = function(header, byteIndex) {
+ var
+ lowThree = (header[byteIndex + 5] & 0xE0) >> 5,
+ middle = header[byteIndex + 4] << 3,
+ highTwo = header[byteIndex + 3] & 0x3 << 11;
+
+ return (highTwo | middle) | lowThree;
+};
+
+var parseType = function(header, byteIndex) {
+ if ((header[byteIndex] === 'I'.charCodeAt(0)) &&
+ (header[byteIndex + 1] === 'D'.charCodeAt(0)) &&
+ (header[byteIndex + 2] === '3'.charCodeAt(0))) {
+ return 'timed-metadata';
+ } else if ((header[byteIndex] & 0xff === 0xff) &&
+ ((header[byteIndex + 1] & 0xf0) === 0xf0)) {
+ return 'audio';
+ }
+ return null;
+};
+
+var parseSampleRate = function(packet) {
+ var i = 0;
+
+ while (i + 5 < packet.length) {
+ if (packet[i] !== 0xFF || (packet[i + 1] & 0xF6) !== 0xF0) {
+ // If a valid header was not found, jump one forward and attempt to
+ // find a valid ADTS header starting at the next byte
+ i++;
+ continue;
+ }
+ return ADTS_SAMPLING_FREQUENCIES[(packet[i + 2] & 0x3c) >>> 2];
+ }
+
+ return null;
+};
+
+var parseAacTimestamp = function(packet) {
+ var frameStart, frameSize, frame, frameHeader;
+
+ // find the start of the first frame and the end of the tag
+ frameStart = 10;
+ if (packet[5] & 0x40) {
+ // advance the frame start past the extended header
+ frameStart += 4; // header size field
+ frameStart += parseSyncSafeInteger(packet.subarray(10, 14));
+ }
+
+ // parse one or more ID3 frames
+ // http://id3.org/id3v2.3.0#ID3v2_frame_overview
+ do {
+ // determine the number of bytes in this frame
+ frameSize = parseSyncSafeInteger(packet.subarray(frameStart + 4, frameStart + 8));
+ if (frameSize < 1) {
+ return null;
+ }
+ frameHeader = String.fromCharCode(packet[frameStart],
+ packet[frameStart + 1],
+ packet[frameStart + 2],
+ packet[frameStart + 3]);
+
+ if (frameHeader === 'PRIV') {
+ frame = packet.subarray(frameStart + 10, frameStart + frameSize + 10);
+
+ for (var i = 0; i < frame.byteLength; i++) {
+ if (frame[i] === 0) {
+ var owner = parseIso88591(frame, 0, i);
+ if (owner === 'com.apple.streaming.transportStreamTimestamp') {
+ var d = frame.subarray(i + 1);
+ var size = ((d[3] & 0x01) << 30) |
+ (d[4] << 22) |
+ (d[5] << 14) |
+ (d[6] << 6) |
+ (d[7] >>> 2);
+ size *= 4;
+ size += d[7] & 0x03;
+
+ return size;
+ }
+ break;
+ }
+ }
+ }
+
+ frameStart += 10; // advance past the frame header
+ frameStart += frameSize; // advance past the frame body
+ } while (frameStart < packet.byteLength);
+ return null;
+};
+
+module.exports = {
+ isLikelyAacData: isLikelyAacData,
+ parseId3TagSize: parseId3TagSize,
+ parseAdtsSize: parseAdtsSize,
+ parseType: parseType,
+ parseSampleRate: parseSampleRate,
+ parseAacTimestamp: parseAacTimestamp
+};
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/m2ts/probe.js":
+/*!***********************************************!*\
+ !*** ./node_modules/mux.js/lib/m2ts/probe.js ***!
+ \***********************************************/
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+"use strict";
+/**
+ * mux.js
+ *
+ * Copyright (c) Brightcove
+ * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
+ *
+ * Utilities to detect basic properties and metadata about TS Segments.
+ */
+
+
+var StreamTypes = __webpack_require__(/*! ./stream-types.js */ "./node_modules/mux.js/lib/m2ts/stream-types.js");
+
+var parsePid = function(packet) {
+ var pid = packet[1] & 0x1f;
+ pid <<= 8;
+ pid |= packet[2];
+ return pid;
+};
+
+var parsePayloadUnitStartIndicator = function(packet) {
+ return !!(packet[1] & 0x40);
+};
+
+var parseAdaptionField = function(packet) {
+ var offset = 0;
+ // if an adaption field is present, its length is specified by the
+ // fifth byte of the TS packet header. The adaptation field is
+ // used to add stuffing to PES packets that don't fill a complete
+ // TS packet, and to specify some forms of timing and control data
+ // that we do not currently use.
+ if (((packet[3] & 0x30) >>> 4) > 0x01) {
+ offset += packet[4] + 1;
+ }
+ return offset;
+};
+
+var parseType = function(packet, pmtPid) {
+ var pid = parsePid(packet);
+ if (pid === 0) {
+ return 'pat';
+ } else if (pid === pmtPid) {
+ return 'pmt';
+ } else if (pmtPid) {
+ return 'pes';
+ }
+ return null;
+};
+
+var parsePat = function(packet) {
+ var pusi = parsePayloadUnitStartIndicator(packet);
+ var offset = 4 + parseAdaptionField(packet);
+
+ if (pusi) {
+ offset += packet[offset] + 1;
+ }
+
+ return (packet[offset + 10] & 0x1f) << 8 | packet[offset + 11];
+};
+
+var parsePmt = function(packet) {
+ var programMapTable = {};
+ var pusi = parsePayloadUnitStartIndicator(packet);
+ var payloadOffset = 4 + parseAdaptionField(packet);
+
+ if (pusi) {
+ payloadOffset += packet[payloadOffset] + 1;
+ }
+
+ // PMTs can be sent ahead of the time when they should actually
+ // take effect. We don't believe this should ever be the case
+ // for HLS but we'll ignore "forward" PMT declarations if we see
+ // them. Future PMT declarations have the current_next_indicator
+ // set to zero.
+ if (!(packet[payloadOffset + 5] & 0x01)) {
+ return;
+ }
+
+ var sectionLength, tableEnd, programInfoLength;
+ // the mapping table ends at the end of the current section
+ sectionLength = (packet[payloadOffset + 1] & 0x0f) << 8 | packet[payloadOffset + 2];
+ tableEnd = 3 + sectionLength - 4;
+
+ // to determine where the table is, we have to figure out how
+ // long the program info descriptors are
+ programInfoLength = (packet[payloadOffset + 10] & 0x0f) << 8 | packet[payloadOffset + 11];
+
+ // advance the offset to the first entry in the mapping table
+ var offset = 12 + programInfoLength;
+ while (offset < tableEnd) {
+ var i = payloadOffset + offset;
+ // add an entry that maps the elementary_pid to the stream_type
+ programMapTable[(packet[i + 1] & 0x1F) << 8 | packet[i + 2]] = packet[i];
+
+ // move to the next table entry
+ // skip past the elementary stream descriptors, if present
+ offset += ((packet[i + 3] & 0x0F) << 8 | packet[i + 4]) + 5;
+ }
+ return programMapTable;
+};
+
+var parsePesType = function(packet, programMapTable) {
+ var pid = parsePid(packet);
+ var type = programMapTable[pid];
+ switch (type) {
+ case StreamTypes.H264_STREAM_TYPE:
+ return 'video';
+ case StreamTypes.ADTS_STREAM_TYPE:
+ return 'audio';
+ case StreamTypes.METADATA_STREAM_TYPE:
+ return 'timed-metadata';
+ default:
+ return null;
+ }
+};
+
+var parsePesTime = function(packet) {
+ var pusi = parsePayloadUnitStartIndicator(packet);
+ if (!pusi) {
+ return null;
+ }
+
+ var offset = 4 + parseAdaptionField(packet);
+
+ if (offset >= packet.byteLength) {
+ // From the H 222.0 MPEG-TS spec
+ // "For transport stream packets carrying PES packets, stuffing is needed when there
+ // is insufficient PES packet data to completely fill the transport stream packet
+ // payload bytes. Stuffing is accomplished by defining an adaptation field longer than
+ // the sum of the lengths of the data elements in it, so that the payload bytes
+ // remaining after the adaptation field exactly accommodates the available PES packet
+ // data."
+ //
+ // If the offset is >= the length of the packet, then the packet contains no data
+ // and instead is just adaption field stuffing bytes
+ return null;
+ }
+
+ var pes = null;
+ var ptsDtsFlags;
+
+ // PES packets may be annotated with a PTS value, or a PTS value
+ // and a DTS value. Determine what combination of values is
+ // available to work with.
+ ptsDtsFlags = packet[offset + 7];
+
+ // PTS and DTS are normally stored as a 33-bit number. Javascript
+ // performs all bitwise operations on 32-bit integers but javascript
+ // supports a much greater range (52-bits) of integer using standard
+ // mathematical operations.
+ // We construct a 31-bit value using bitwise operators over the 31
+ // most significant bits and then multiply by 4 (equal to a left-shift
+ // of 2) before we add the final 2 least significant bits of the
+ // timestamp (equal to an OR.)
+ if (ptsDtsFlags & 0xC0) {
+ pes = {};
+ // the PTS and DTS are not written out directly. For information
+ // on how they are encoded, see
+ // http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
+ pes.pts = (packet[offset + 9] & 0x0E) << 27 |
+ (packet[offset + 10] & 0xFF) << 20 |
+ (packet[offset + 11] & 0xFE) << 12 |
+ (packet[offset + 12] & 0xFF) << 5 |
+ (packet[offset + 13] & 0xFE) >>> 3;
+ pes.pts *= 4; // Left shift by 2
+ pes.pts += (packet[offset + 13] & 0x06) >>> 1; // OR by the two LSBs
+ pes.dts = pes.pts;
+ if (ptsDtsFlags & 0x40) {
+ pes.dts = (packet[offset + 14] & 0x0E) << 27 |
+ (packet[offset + 15] & 0xFF) << 20 |
+ (packet[offset + 16] & 0xFE) << 12 |
+ (packet[offset + 17] & 0xFF) << 5 |
+ (packet[offset + 18] & 0xFE) >>> 3;
+ pes.dts *= 4; // Left shift by 2
+ pes.dts += (packet[offset + 18] & 0x06) >>> 1; // OR by the two LSBs
+ }
+ }
+ return pes;
+};
+
+var parseNalUnitType = function(type) {
+ switch (type) {
+ case 0x05:
+ return 'slice_layer_without_partitioning_rbsp_idr';
+ case 0x06:
+ return 'sei_rbsp';
+ case 0x07:
+ return 'seq_parameter_set_rbsp';
+ case 0x08:
+ return 'pic_parameter_set_rbsp';
+ case 0x09:
+ return 'access_unit_delimiter_rbsp';
+ default:
+ return null;
+ }
+};
+
+var videoPacketContainsKeyFrame = function(packet) {
+ var offset = 4 + parseAdaptionField(packet);
+ var frameBuffer = packet.subarray(offset);
+ var frameI = 0;
+ var frameSyncPoint = 0;
+ var foundKeyFrame = false;
+ var nalType;
+
+ // advance the sync point to a NAL start, if necessary
+ for (; frameSyncPoint < frameBuffer.byteLength - 3; frameSyncPoint++) {
+ if (frameBuffer[frameSyncPoint + 2] === 1) {
+ // the sync point is properly aligned
+ frameI = frameSyncPoint + 5;
+ break;
+ }
+ }
+
+ while (frameI < frameBuffer.byteLength) {
+ // look at the current byte to determine if we've hit the end of
+ // a NAL unit boundary
+ switch (frameBuffer[frameI]) {
+ case 0:
+ // skip past non-sync sequences
+ if (frameBuffer[frameI - 1] !== 0) {
+ frameI += 2;
+ break;
+ } else if (frameBuffer[frameI - 2] !== 0) {
+ frameI++;
+ break;
+ }
+
+ if (frameSyncPoint + 3 !== frameI - 2) {
+ nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f);
+ if (nalType === 'slice_layer_without_partitioning_rbsp_idr') {
+ foundKeyFrame = true;
+ }
+ }
+
+ // drop trailing zeroes
+ do {
+ frameI++;
+ } while (frameBuffer[frameI] !== 1 && frameI < frameBuffer.length);
+ frameSyncPoint = frameI - 2;
+ frameI += 3;
+ break;
+ case 1:
+ // skip past non-sync sequences
+ if (frameBuffer[frameI - 1] !== 0 ||
+ frameBuffer[frameI - 2] !== 0) {
+ frameI += 3;
+ break;
+ }
+
+ nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f);
+ if (nalType === 'slice_layer_without_partitioning_rbsp_idr') {
+ foundKeyFrame = true;
+ }
+ frameSyncPoint = frameI - 2;
+ frameI += 3;
+ break;
+ default:
+ // the current byte isn't a one or zero, so it cannot be part
+ // of a sync sequence
+ frameI += 3;
+ break;
+ }
+ }
+ frameBuffer = frameBuffer.subarray(frameSyncPoint);
+ frameI -= frameSyncPoint;
+ frameSyncPoint = 0;
+ // parse the final nal
+ if (frameBuffer && frameBuffer.byteLength > 3) {
+ nalType = parseNalUnitType(frameBuffer[frameSyncPoint + 3] & 0x1f);
+ if (nalType === 'slice_layer_without_partitioning_rbsp_idr') {
+ foundKeyFrame = true;
+ }
+ }
+
+ return foundKeyFrame;
+};
+
+
+module.exports = {
+ parseType: parseType,
+ parsePat: parsePat,
+ parsePmt: parsePmt,
+ parsePayloadUnitStartIndicator: parsePayloadUnitStartIndicator,
+ parsePesType: parsePesType,
+ parsePesTime: parsePesTime,
+ videoPacketContainsKeyFrame: videoPacketContainsKeyFrame
+};
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/m2ts/stream-types.js":
+/*!******************************************************!*\
+ !*** ./node_modules/mux.js/lib/m2ts/stream-types.js ***!
+ \******************************************************/
+/***/ ((module) => {
+
+"use strict";
+/**
+ * mux.js
+ *
+ * Copyright (c) Brightcove
+ * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
+ */
+
+
+module.exports = {
+ H264_STREAM_TYPE: 0x1B,
+ ADTS_STREAM_TYPE: 0x0F,
+ METADATA_STREAM_TYPE: 0x15
+};
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/m2ts/timestamp-rollover-stream.js":
+/*!*******************************************************************!*\
+ !*** ./node_modules/mux.js/lib/m2ts/timestamp-rollover-stream.js ***!
+ \*******************************************************************/
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+"use strict";
+/**
+ * mux.js
+ *
+ * Copyright (c) Brightcove
+ * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
+ *
+ * Accepts program elementary stream (PES) data events and corrects
+ * decode and presentation time stamps to account for a rollover
+ * of the 33 bit value.
+ */
+
+
+
+var Stream = __webpack_require__(/*! ../utils/stream */ "./node_modules/mux.js/lib/utils/stream.js");
+
+var MAX_TS = 8589934592;
+
+var RO_THRESH = 4294967296;
+
+var TYPE_SHARED = 'shared';
+
+var handleRollover = function(value, reference) {
+ var direction = 1;
+
+ if (value > reference) {
+ // If the current timestamp value is greater than our reference timestamp and we detect a
+ // timestamp rollover, this means the roll over is happening in the opposite direction.
+ // Example scenario: Enter a long stream/video just after a rollover occurred. The reference
+ // point will be set to a small number, e.g. 1. The user then seeks backwards over the
+ // rollover point. In loading this segment, the timestamp values will be very large,
+ // e.g. 2^33 - 1. Since this comes before the data we loaded previously, we want to adjust
+ // the time stamp to be `value - 2^33`.
+ direction = -1;
+ }
+
+ // Note: A seek forwards or back that is greater than the RO_THRESH (2^32, ~13 hours) will
+ // cause an incorrect adjustment.
+ while (Math.abs(reference - value) > RO_THRESH) {
+ value += (direction * MAX_TS);
+ }
+
+ return value;
+};
+
+var TimestampRolloverStream = function(type) {
+ var lastDTS, referenceDTS;
+
+ TimestampRolloverStream.prototype.init.call(this);
+
+ // The "shared" type is used in cases where a stream will contain muxed
+ // video and audio. We could use `undefined` here, but having a string
+ // makes debugging a little clearer.
+ this.type_ = type || TYPE_SHARED;
+
+ this.push = function(data) {
+
+ // Any "shared" rollover streams will accept _all_ data. Otherwise,
+ // streams will only accept data that matches their type.
+ if (this.type_ !== TYPE_SHARED && data.type !== this.type_) {
+ return;
+ }
+
+ if (referenceDTS === undefined) {
+ referenceDTS = data.dts;
+ }
+
+ data.dts = handleRollover(data.dts, referenceDTS);
+ data.pts = handleRollover(data.pts, referenceDTS);
+
+ lastDTS = data.dts;
+
+ this.trigger('data', data);
+ };
+
+ this.flush = function() {
+ referenceDTS = lastDTS;
+ this.trigger('done');
+ };
+
+ this.endTimeline = function() {
+ this.flush();
+ this.trigger('endedtimeline');
+ };
+
+ this.discontinuity = function() {
+ referenceDTS = void 0;
+ lastDTS = void 0;
+ };
+
+ this.reset = function() {
+ this.discontinuity();
+ this.trigger('reset');
+ };
+};
+
+TimestampRolloverStream.prototype = new Stream();
+
+module.exports = {
+ TimestampRolloverStream: TimestampRolloverStream,
+ handleRollover: handleRollover
+};
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/mp4/find-box.js":
+/*!*************************************************!*\
+ !*** ./node_modules/mux.js/lib/mp4/find-box.js ***!
+ \*************************************************/
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+var toUnsigned = __webpack_require__(/*! ../utils/bin */ "./node_modules/mux.js/lib/utils/bin.js").toUnsigned;
+var parseType = __webpack_require__(/*! ./parse-type.js */ "./node_modules/mux.js/lib/mp4/parse-type.js");
+
+var findBox = function(data, path) {
+ var results = [],
+ i, size, type, end, subresults;
+
+ if (!path.length) {
+ // short-circuit the search for empty paths
+ return null;
+ }
+
+ for (i = 0; i < data.byteLength;) {
+ size = toUnsigned(data[i] << 24 |
+ data[i + 1] << 16 |
+ data[i + 2] << 8 |
+ data[i + 3]);
+
+ type = parseType(data.subarray(i + 4, i + 8));
+
+ end = size > 1 ? i + size : data.byteLength;
+
+ if (type === path[0]) {
+ if (path.length === 1) {
+ // this is the end of the path and we've found the box we were
+ // looking for
+ results.push(data.subarray(i + 8, end));
+ } else {
+ // recursively search for the next box along the path
+ subresults = findBox(data.subarray(i + 8, end), path.slice(1));
+ if (subresults.length) {
+ results = results.concat(subresults);
+ }
+ }
+ }
+ i = end;
+ }
+
+ // we've finished searching all of data
+ return results;
+};
+
+module.exports = findBox;
+
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/mp4/parse-type.js":
+/*!***************************************************!*\
+ !*** ./node_modules/mux.js/lib/mp4/parse-type.js ***!
+ \***************************************************/
+/***/ ((module) => {
+
+var parseType = function(buffer) {
+ var result = '';
+ result += String.fromCharCode(buffer[0]);
+ result += String.fromCharCode(buffer[1]);
+ result += String.fromCharCode(buffer[2]);
+ result += String.fromCharCode(buffer[3]);
+ return result;
+};
+
+
+module.exports = parseType;
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/mp4/probe.js":
+/*!**********************************************!*\
+ !*** ./node_modules/mux.js/lib/mp4/probe.js ***!
+ \**********************************************/
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+"use strict";
+/**
+ * mux.js
+ *
+ * Copyright (c) Brightcove
+ * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
+ *
+ * Utilities to detect basic properties and metadata about MP4s.
+ */
+
+
+var toUnsigned = __webpack_require__(/*! ../utils/bin */ "./node_modules/mux.js/lib/utils/bin.js").toUnsigned;
+var toHexString = __webpack_require__(/*! ../utils/bin */ "./node_modules/mux.js/lib/utils/bin.js").toHexString;
+var findBox = __webpack_require__(/*! ../mp4/find-box.js */ "./node_modules/mux.js/lib/mp4/find-box.js");
+var parseType = __webpack_require__(/*! ../mp4/parse-type.js */ "./node_modules/mux.js/lib/mp4/parse-type.js");
+var parseTfhd = __webpack_require__(/*! ../tools/parse-tfhd.js */ "./node_modules/mux.js/lib/tools/parse-tfhd.js");
+var parseTrun = __webpack_require__(/*! ../tools/parse-trun.js */ "./node_modules/mux.js/lib/tools/parse-trun.js");
+var parseTfdt = __webpack_require__(/*! ../tools/parse-tfdt.js */ "./node_modules/mux.js/lib/tools/parse-tfdt.js");
+var timescale, startTime, compositionStartTime, getVideoTrackIds, getTracks,
+ getTimescaleFromMediaHeader;
+
+/**
+ * Parses an MP4 initialization segment and extracts the timescale
+ * values for any declared tracks. Timescale values indicate the
+ * number of clock ticks per second to assume for time-based values
+ * elsewhere in the MP4.
+ *
+ * To determine the start time of an MP4, you need two pieces of
+ * information: the timescale unit and the earliest base media decode
+ * time. Multiple timescales can be specified within an MP4 but the
+ * base media decode time is always expressed in the timescale from
+ * the media header box for the track:
+ * ```
+ * moov > trak > mdia > mdhd.timescale
+ * ```
+ * @param init {Uint8Array} the bytes of the init segment
+ * @return {object} a hash of track ids to timescale values or null if
+ * the init segment is malformed.
+ */
+timescale = function(init) {
+ var
+ result = {},
+ traks = findBox(init, ['moov', 'trak']);
+
+ // mdhd timescale
+ return traks.reduce(function(result, trak) {
+ var tkhd, version, index, id, mdhd;
+
+ tkhd = findBox(trak, ['tkhd'])[0];
+ if (!tkhd) {
+ return null;
+ }
+ version = tkhd[0];
+ index = version === 0 ? 12 : 20;
+ id = toUnsigned(tkhd[index] << 24 |
+ tkhd[index + 1] << 16 |
+ tkhd[index + 2] << 8 |
+ tkhd[index + 3]);
+
+ mdhd = findBox(trak, ['mdia', 'mdhd'])[0];
+ if (!mdhd) {
+ return null;
+ }
+ version = mdhd[0];
+ index = version === 0 ? 12 : 20;
+ result[id] = toUnsigned(mdhd[index] << 24 |
+ mdhd[index + 1] << 16 |
+ mdhd[index + 2] << 8 |
+ mdhd[index + 3]);
+ return result;
+ }, result);
+};
+
+/**
+ * Determine the base media decode start time, in seconds, for an MP4
+ * fragment. If multiple fragments are specified, the earliest time is
+ * returned.
+ *
+ * The base media decode time can be parsed from track fragment
+ * metadata:
+ * ```
+ * moof > traf > tfdt.baseMediaDecodeTime
+ * ```
+ * It requires the timescale value from the mdhd to interpret.
+ *
+ * @param timescale {object} a hash of track ids to timescale values.
+ * @return {number} the earliest base media decode start time for the
+ * fragment, in seconds
+ */
+startTime = function(timescale, fragment) {
+ var trafs, baseTimes, result;
+
+ // we need info from two childrend of each track fragment box
+ trafs = findBox(fragment, ['moof', 'traf']);
+
+ // determine the start times for each track
+ baseTimes = [].concat.apply([], trafs.map(function(traf) {
+ return findBox(traf, ['tfhd']).map(function(tfhd) {
+ var id, scale, baseTime;
+
+ // get the track id from the tfhd
+ id = toUnsigned(tfhd[4] << 24 |
+ tfhd[5] << 16 |
+ tfhd[6] << 8 |
+ tfhd[7]);
+ // assume a 90kHz clock if no timescale was specified
+ scale = timescale[id] || 90e3;
+
+ // get the base media decode time from the tfdt
+ baseTime = findBox(traf, ['tfdt']).map(function(tfdt) {
+ var version, result;
+
+ version = tfdt[0];
+ result = toUnsigned(tfdt[4] << 24 |
+ tfdt[5] << 16 |
+ tfdt[6] << 8 |
+ tfdt[7]);
+ if (version === 1) {
+ result *= Math.pow(2, 32);
+ result += toUnsigned(tfdt[8] << 24 |
+ tfdt[9] << 16 |
+ tfdt[10] << 8 |
+ tfdt[11]);
+ }
+ return result;
+ })[0];
+ baseTime = baseTime || Infinity;
+
+ // convert base time to seconds
+ return baseTime / scale;
+ });
+ }));
+
+ // return the minimum
+ result = Math.min.apply(null, baseTimes);
+ return isFinite(result) ? result : 0;
+};
+
+/**
+ * Determine the composition start, in seconds, for an MP4
+ * fragment.
+ *
+ * The composition start time of a fragment can be calculated using the base
+ * media decode time, composition time offset, and timescale, as follows:
+ *
+ * compositionStartTime = (baseMediaDecodeTime + compositionTimeOffset) / timescale
+ *
+ * All of the aforementioned information is contained within a media fragment's
+ * `traf` box, except for timescale info, which comes from the initialization
+ * segment, so a track id (also contained within a `traf`) is also necessary to
+ * associate it with a timescale
+ *
+ *
+ * @param timescales {object} - a hash of track ids to timescale values.
+ * @param fragment {Unit8Array} - the bytes of a media segment
+ * @return {number} the composition start time for the fragment, in seconds
+ **/
+compositionStartTime = function(timescales, fragment) {
+ var trafBoxes = findBox(fragment, ['moof', 'traf']);
+ var baseMediaDecodeTime = 0;
+ var compositionTimeOffset = 0;
+ var trackId;
+
+ if (trafBoxes && trafBoxes.length) {
+ // The spec states that track run samples contained within a `traf` box are contiguous, but
+ // it does not explicitly state whether the `traf` boxes themselves are contiguous.
+ // We will assume that they are, so we only need the first to calculate start time.
+ var tfhd = findBox(trafBoxes[0], ['tfhd'])[0];
+ var trun = findBox(trafBoxes[0], ['trun'])[0];
+ var tfdt = findBox(trafBoxes[0], ['tfdt'])[0];
+
+ if (tfhd) {
+ var parsedTfhd = parseTfhd(tfhd);
+
+ trackId = parsedTfhd.trackId;
+ }
+
+ if (tfdt) {
+ var parsedTfdt = parseTfdt(tfdt);
+
+ baseMediaDecodeTime = parsedTfdt.baseMediaDecodeTime;
+ }
+
+ if (trun) {
+ var parsedTrun = parseTrun(trun);
+
+ if (parsedTrun.samples && parsedTrun.samples.length) {
+ compositionTimeOffset = parsedTrun.samples[0].compositionTimeOffset || 0;
+ }
+ }
+ }
+
+ // Get timescale for this specific track. Assume a 90kHz clock if no timescale was
+ // specified.
+ var timescale = timescales[trackId] || 90e3;
+
+ // return the composition start time, in seconds
+ return (baseMediaDecodeTime + compositionTimeOffset) / timescale;
+};
+
+/**
+ * Find the trackIds of the video tracks in this source.
+ * Found by parsing the Handler Reference and Track Header Boxes:
+ * moov > trak > mdia > hdlr
+ * moov > trak > tkhd
+ *
+ * @param {Uint8Array} init - The bytes of the init segment for this source
+ * @return {Number[]} A list of trackIds
+ *
+ * @see ISO-BMFF-12/2015, Section 8.4.3
+ **/
+getVideoTrackIds = function(init) {
+ var traks = findBox(init, ['moov', 'trak']);
+ var videoTrackIds = [];
+
+ traks.forEach(function(trak) {
+ var hdlrs = findBox(trak, ['mdia', 'hdlr']);
+ var tkhds = findBox(trak, ['tkhd']);
+
+ hdlrs.forEach(function(hdlr, index) {
+ var handlerType = parseType(hdlr.subarray(8, 12));
+ var tkhd = tkhds[index];
+ var view;
+ var version;
+ var trackId;
+
+ if (handlerType === 'vide') {
+ view = new DataView(tkhd.buffer, tkhd.byteOffset, tkhd.byteLength);
+ version = view.getUint8(0);
+ trackId = (version === 0) ? view.getUint32(12) : view.getUint32(20);
+
+ videoTrackIds.push(trackId);
+ }
+ });
+ });
+
+ return videoTrackIds;
+};
+
+getTimescaleFromMediaHeader = function(mdhd) {
+ // mdhd is a FullBox, meaning it will have its own version as the first byte
+ var version = mdhd[0];
+ var index = version === 0 ? 12 : 20;
+
+ return toUnsigned(
+ mdhd[index] << 24 |
+ mdhd[index + 1] << 16 |
+ mdhd[index + 2] << 8 |
+ mdhd[index + 3]
+ );
+};
+
+/**
+ * Get all the video, audio, and hint tracks from a non fragmented
+ * mp4 segment
+ */
+getTracks = function(init) {
+ var traks = findBox(init, ['moov', 'trak']);
+ var tracks = [];
+
+ traks.forEach(function(trak) {
+ var track = {};
+ var tkhd = findBox(trak, ['tkhd'])[0];
+ var view, tkhdVersion;
+
+ // id
+ if (tkhd) {
+ view = new DataView(tkhd.buffer, tkhd.byteOffset, tkhd.byteLength);
+ tkhdVersion = view.getUint8(0);
+
+ track.id = (tkhdVersion === 0) ? view.getUint32(12) : view.getUint32(20);
+ }
+
+ var hdlr = findBox(trak, ['mdia', 'hdlr'])[0];
+
+ // type
+ if (hdlr) {
+ var type = parseType(hdlr.subarray(8, 12));
+
+ if (type === 'vide') {
+ track.type = 'video';
+ } else if (type === 'soun') {
+ track.type = 'audio';
+ } else {
+ track.type = type;
+ }
+ }
+
+
+ // codec
+ var stsd = findBox(trak, ['mdia', 'minf', 'stbl', 'stsd'])[0];
+
+ if (stsd) {
+ var sampleDescriptions = stsd.subarray(8);
+ // gives the codec type string
+ track.codec = parseType(sampleDescriptions.subarray(4, 8));
+
+ var codecBox = findBox(sampleDescriptions, [track.codec])[0];
+ var codecConfig, codecConfigType;
+
+ if (codecBox) {
+ // https://tools.ietf.org/html/rfc6381#section-3.3
+ if ((/^[a-z]vc[1-9]$/i).test(track.codec)) {
+ // we don't need anything but the "config" parameter of the
+ // avc1 codecBox
+ codecConfig = codecBox.subarray(78);
+ codecConfigType = parseType(codecConfig.subarray(4, 8));
+
+ if (codecConfigType === 'avcC' && codecConfig.length > 11) {
+ track.codec += '.';
+
+ // left padded with zeroes for single digit hex
+ // profile idc
+ track.codec += toHexString(codecConfig[9]);
+ // the byte containing the constraint_set flags
+ track.codec += toHexString(codecConfig[10]);
+ // level idc
+ track.codec += toHexString(codecConfig[11]);
+ } else {
+ // TODO: show a warning that we couldn't parse the codec
+ // and are using the default
+ track.codec = 'avc1.4d400d';
+ }
+ } else if ((/^mp4[a,v]$/i).test(track.codec)) {
+ // we do not need anything but the streamDescriptor of the mp4a codecBox
+ codecConfig = codecBox.subarray(28);
+ codecConfigType = parseType(codecConfig.subarray(4, 8));
+
+ if (codecConfigType === 'esds' && codecConfig.length > 20 && codecConfig[19] !== 0) {
+ track.codec += '.' + toHexString(codecConfig[19]);
+ // this value is only a single digit
+ track.codec += '.' + toHexString((codecConfig[20] >>> 2) & 0x3f).replace(/^0/, '');
+ } else {
+ // TODO: show a warning that we couldn't parse the codec
+ // and are using the default
+ track.codec = 'mp4a.40.2';
+ }
+ } else {
+ // TODO: show a warning? for unknown codec type
+ }
+ }
+ }
+
+ var mdhd = findBox(trak, ['mdia', 'mdhd'])[0];
+
+ if (mdhd) {
+ track.timescale = getTimescaleFromMediaHeader(mdhd);
+ }
+
+ tracks.push(track);
+ });
+
+ return tracks;
+};
+
+module.exports = {
+ // export mp4 inspector's findBox and parseType for backwards compatibility
+ findBox: findBox,
+ parseType: parseType,
+ timescale: timescale,
+ startTime: startTime,
+ compositionStartTime: compositionStartTime,
+ videoTrackIds: getVideoTrackIds,
+ tracks: getTracks,
+ getTimescaleFromMediaHeader: getTimescaleFromMediaHeader
+};
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/tools/parse-sample-flags.js":
+/*!*************************************************************!*\
+ !*** ./node_modules/mux.js/lib/tools/parse-sample-flags.js ***!
+ \*************************************************************/
+/***/ ((module) => {
+
+var parseSampleFlags = function(flags) {
+ return {
+ isLeading: (flags[0] & 0x0c) >>> 2,
+ dependsOn: flags[0] & 0x03,
+ isDependedOn: (flags[1] & 0xc0) >>> 6,
+ hasRedundancy: (flags[1] & 0x30) >>> 4,
+ paddingValue: (flags[1] & 0x0e) >>> 1,
+ isNonSyncSample: flags[1] & 0x01,
+ degradationPriority: (flags[2] << 8) | flags[3]
+ };
+};
+
+module.exports = parseSampleFlags;
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/tools/parse-sidx.js":
+/*!*****************************************************!*\
+ !*** ./node_modules/mux.js/lib/tools/parse-sidx.js ***!
+ \*****************************************************/
+/***/ ((module) => {
+
+var parseSidx = function(data) {
+ var view = new DataView(data.buffer, data.byteOffset, data.byteLength),
+ result = {
+ version: data[0],
+ flags: new Uint8Array(data.subarray(1, 4)),
+ references: [],
+ referenceId: view.getUint32(4),
+ timescale: view.getUint32(8),
+ earliestPresentationTime: view.getUint32(12),
+ firstOffset: view.getUint32(16)
+ },
+ referenceCount = view.getUint16(22),
+ i;
+
+ for (i = 24; referenceCount; i += 12, referenceCount--) {
+ result.references.push({
+ referenceType: (data[i] & 0x80) >>> 7,
+ referencedSize: view.getUint32(i) & 0x7FFFFFFF,
+ subsegmentDuration: view.getUint32(i + 4),
+ startsWithSap: !!(data[i + 8] & 0x80),
+ sapType: (data[i + 8] & 0x70) >>> 4,
+ sapDeltaTime: view.getUint32(i + 8) & 0x0FFFFFFF
+ });
+ }
+
+ return result;
+};
+
+module.exports = parseSidx;
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/tools/parse-tfdt.js":
+/*!*****************************************************!*\
+ !*** ./node_modules/mux.js/lib/tools/parse-tfdt.js ***!
+ \*****************************************************/
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+var toUnsigned = __webpack_require__(/*! ../utils/bin */ "./node_modules/mux.js/lib/utils/bin.js").toUnsigned;
+
+var tfdt = function(data) {
+ var result = {
+ version: data[0],
+ flags: new Uint8Array(data.subarray(1, 4)),
+ baseMediaDecodeTime: toUnsigned(data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7])
+ };
+ if (result.version === 1) {
+ result.baseMediaDecodeTime *= Math.pow(2, 32);
+ result.baseMediaDecodeTime += toUnsigned(data[8] << 24 | data[9] << 16 | data[10] << 8 | data[11]);
+ }
+ return result;
+};
+
+module.exports = tfdt;
+
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/tools/parse-tfhd.js":
+/*!*****************************************************!*\
+ !*** ./node_modules/mux.js/lib/tools/parse-tfhd.js ***!
+ \*****************************************************/
+/***/ ((module) => {
+
+var tfhd = function(data) {
+ var
+ view = new DataView(data.buffer, data.byteOffset, data.byteLength),
+ result = {
+ version: data[0],
+ flags: new Uint8Array(data.subarray(1, 4)),
+ trackId: view.getUint32(4)
+ },
+ baseDataOffsetPresent = result.flags[2] & 0x01,
+ sampleDescriptionIndexPresent = result.flags[2] & 0x02,
+ defaultSampleDurationPresent = result.flags[2] & 0x08,
+ defaultSampleSizePresent = result.flags[2] & 0x10,
+ defaultSampleFlagsPresent = result.flags[2] & 0x20,
+ durationIsEmpty = result.flags[0] & 0x010000,
+ defaultBaseIsMoof = result.flags[0] & 0x020000,
+ i;
+
+ i = 8;
+ if (baseDataOffsetPresent) {
+ i += 4; // truncate top 4 bytes
+ // FIXME: should we read the full 64 bits?
+ result.baseDataOffset = view.getUint32(12);
+ i += 4;
+ }
+ if (sampleDescriptionIndexPresent) {
+ result.sampleDescriptionIndex = view.getUint32(i);
+ i += 4;
+ }
+ if (defaultSampleDurationPresent) {
+ result.defaultSampleDuration = view.getUint32(i);
+ i += 4;
+ }
+ if (defaultSampleSizePresent) {
+ result.defaultSampleSize = view.getUint32(i);
+ i += 4;
+ }
+ if (defaultSampleFlagsPresent) {
+ result.defaultSampleFlags = view.getUint32(i);
+ }
+ if (durationIsEmpty) {
+ result.durationIsEmpty = true;
+ }
+ if (!baseDataOffsetPresent && defaultBaseIsMoof) {
+ result.baseDataOffsetIsMoof = true;
+ }
+ return result;
+};
+
+module.exports = tfhd;
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/tools/parse-trun.js":
+/*!*****************************************************!*\
+ !*** ./node_modules/mux.js/lib/tools/parse-trun.js ***!
+ \*****************************************************/
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+var parseSampleFlags = __webpack_require__(/*! ./parse-sample-flags.js */ "./node_modules/mux.js/lib/tools/parse-sample-flags.js");
+
+var trun = function(data) {
+ var
+ result = {
+ version: data[0],
+ flags: new Uint8Array(data.subarray(1, 4)),
+ samples: []
+ },
+ view = new DataView(data.buffer, data.byteOffset, data.byteLength),
+ // Flag interpretation
+ dataOffsetPresent = result.flags[2] & 0x01, // compare with 2nd byte of 0x1
+ firstSampleFlagsPresent = result.flags[2] & 0x04, // compare with 2nd byte of 0x4
+ sampleDurationPresent = result.flags[1] & 0x01, // compare with 2nd byte of 0x100
+ sampleSizePresent = result.flags[1] & 0x02, // compare with 2nd byte of 0x200
+ sampleFlagsPresent = result.flags[1] & 0x04, // compare with 2nd byte of 0x400
+ sampleCompositionTimeOffsetPresent = result.flags[1] & 0x08, // compare with 2nd byte of 0x800
+ sampleCount = view.getUint32(4),
+ offset = 8,
+ sample;
+
+ if (dataOffsetPresent) {
+ // 32 bit signed integer
+ result.dataOffset = view.getInt32(offset);
+ offset += 4;
+ }
+
+ // Overrides the flags for the first sample only. The order of
+ // optional values will be: duration, size, compositionTimeOffset
+ if (firstSampleFlagsPresent && sampleCount) {
+ sample = {
+ flags: parseSampleFlags(data.subarray(offset, offset + 4))
+ };
+ offset += 4;
+ if (sampleDurationPresent) {
+ sample.duration = view.getUint32(offset);
+ offset += 4;
+ }
+ if (sampleSizePresent) {
+ sample.size = view.getUint32(offset);
+ offset += 4;
+ }
+ if (sampleCompositionTimeOffsetPresent) {
+ if (result.version === 1) {
+ sample.compositionTimeOffset = view.getInt32(offset);
+ } else {
+ sample.compositionTimeOffset = view.getUint32(offset);
+ }
+ offset += 4;
+ }
+ result.samples.push(sample);
+ sampleCount--;
+ }
+
+ while (sampleCount--) {
+ sample = {};
+ if (sampleDurationPresent) {
+ sample.duration = view.getUint32(offset);
+ offset += 4;
+ }
+ if (sampleSizePresent) {
+ sample.size = view.getUint32(offset);
+ offset += 4;
+ }
+ if (sampleFlagsPresent) {
+ sample.flags = parseSampleFlags(data.subarray(offset, offset + 4));
+ offset += 4;
+ }
+ if (sampleCompositionTimeOffsetPresent) {
+ if (result.version === 1) {
+ sample.compositionTimeOffset = view.getInt32(offset);
+ } else {
+ sample.compositionTimeOffset = view.getUint32(offset);
+ }
+ offset += 4;
+ }
+ result.samples.push(sample);
+ }
+ return result;
+};
+
+module.exports = trun;
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/tools/ts-inspector.js":
+/*!*******************************************************!*\
+ !*** ./node_modules/mux.js/lib/tools/ts-inspector.js ***!
+ \*******************************************************/
+/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
+
+"use strict";
+/**
+ * mux.js
+ *
+ * Copyright (c) Brightcove
+ * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
+ *
+ * Parse mpeg2 transport stream packets to extract basic timing information
+ */
+
+
+var StreamTypes = __webpack_require__(/*! ../m2ts/stream-types.js */ "./node_modules/mux.js/lib/m2ts/stream-types.js");
+var handleRollover = __webpack_require__(/*! ../m2ts/timestamp-rollover-stream.js */ "./node_modules/mux.js/lib/m2ts/timestamp-rollover-stream.js").handleRollover;
+var probe = {};
+probe.ts = __webpack_require__(/*! ../m2ts/probe.js */ "./node_modules/mux.js/lib/m2ts/probe.js");
+probe.aac = __webpack_require__(/*! ../aac/utils.js */ "./node_modules/mux.js/lib/aac/utils.js");
+var ONE_SECOND_IN_TS = __webpack_require__(/*! ../utils/clock */ "./node_modules/mux.js/lib/utils/clock.js").ONE_SECOND_IN_TS;
+
+var
+ MP2T_PACKET_LENGTH = 188, // bytes
+ SYNC_BYTE = 0x47;
+
+/**
+ * walks through segment data looking for pat and pmt packets to parse out
+ * program map table information
+ */
+var parsePsi_ = function(bytes, pmt) {
+ var
+ startIndex = 0,
+ endIndex = MP2T_PACKET_LENGTH,
+ packet, type;
+
+ while (endIndex < bytes.byteLength) {
+ // Look for a pair of start and end sync bytes in the data..
+ if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) {
+ // We found a packet
+ packet = bytes.subarray(startIndex, endIndex);
+ type = probe.ts.parseType(packet, pmt.pid);
+
+ switch (type) {
+ case 'pat':
+ if (!pmt.pid) {
+ pmt.pid = probe.ts.parsePat(packet);
+ }
+ break;
+ case 'pmt':
+ if (!pmt.table) {
+ pmt.table = probe.ts.parsePmt(packet);
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Found the pat and pmt, we can stop walking the segment
+ if (pmt.pid && pmt.table) {
+ return;
+ }
+
+ startIndex += MP2T_PACKET_LENGTH;
+ endIndex += MP2T_PACKET_LENGTH;
+ continue;
+ }
+
+ // If we get here, we have somehow become de-synchronized and we need to step
+ // forward one byte at a time until we find a pair of sync bytes that denote
+ // a packet
+ startIndex++;
+ endIndex++;
+ }
+};
+
+/**
+ * walks through the segment data from the start and end to get timing information
+ * for the first and last audio pes packets
+ */
+var parseAudioPes_ = function(bytes, pmt, result) {
+ var
+ startIndex = 0,
+ endIndex = MP2T_PACKET_LENGTH,
+ packet, type, pesType, pusi, parsed;
+
+ var endLoop = false;
+
+ // Start walking from start of segment to get first audio packet
+ while (endIndex <= bytes.byteLength) {
+ // Look for a pair of start and end sync bytes in the data..
+ if (bytes[startIndex] === SYNC_BYTE &&
+ (bytes[endIndex] === SYNC_BYTE || endIndex === bytes.byteLength)) {
+ // We found a packet
+ packet = bytes.subarray(startIndex, endIndex);
+ type = probe.ts.parseType(packet, pmt.pid);
+
+ switch (type) {
+ case 'pes':
+ pesType = probe.ts.parsePesType(packet, pmt.table);
+ pusi = probe.ts.parsePayloadUnitStartIndicator(packet);
+ if (pesType === 'audio' && pusi) {
+ parsed = probe.ts.parsePesTime(packet);
+ if (parsed) {
+ parsed.type = 'audio';
+ result.audio.push(parsed);
+ endLoop = true;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (endLoop) {
+ break;
+ }
+
+ startIndex += MP2T_PACKET_LENGTH;
+ endIndex += MP2T_PACKET_LENGTH;
+ continue;
+ }
+
+ // If we get here, we have somehow become de-synchronized and we need to step
+ // forward one byte at a time until we find a pair of sync bytes that denote
+ // a packet
+ startIndex++;
+ endIndex++;
+ }
+
+ // Start walking from end of segment to get last audio packet
+ endIndex = bytes.byteLength;
+ startIndex = endIndex - MP2T_PACKET_LENGTH;
+ endLoop = false;
+ while (startIndex >= 0) {
+ // Look for a pair of start and end sync bytes in the data..
+ if (bytes[startIndex] === SYNC_BYTE &&
+ (bytes[endIndex] === SYNC_BYTE || endIndex === bytes.byteLength)) {
+ // We found a packet
+ packet = bytes.subarray(startIndex, endIndex);
+ type = probe.ts.parseType(packet, pmt.pid);
+
+ switch (type) {
+ case 'pes':
+ pesType = probe.ts.parsePesType(packet, pmt.table);
+ pusi = probe.ts.parsePayloadUnitStartIndicator(packet);
+ if (pesType === 'audio' && pusi) {
+ parsed = probe.ts.parsePesTime(packet);
+ if (parsed) {
+ parsed.type = 'audio';
+ result.audio.push(parsed);
+ endLoop = true;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (endLoop) {
+ break;
+ }
+
+ startIndex -= MP2T_PACKET_LENGTH;
+ endIndex -= MP2T_PACKET_LENGTH;
+ continue;
+ }
+
+ // If we get here, we have somehow become de-synchronized and we need to step
+ // forward one byte at a time until we find a pair of sync bytes that denote
+ // a packet
+ startIndex--;
+ endIndex--;
+ }
+};
+
+/**
+ * walks through the segment data from the start and end to get timing information
+ * for the first and last video pes packets as well as timing information for the first
+ * key frame.
+ */
+var parseVideoPes_ = function(bytes, pmt, result) {
+ var
+ startIndex = 0,
+ endIndex = MP2T_PACKET_LENGTH,
+ packet, type, pesType, pusi, parsed, frame, i, pes;
+
+ var endLoop = false;
+
+ var currentFrame = {
+ data: [],
+ size: 0
+ };
+
+ // Start walking from start of segment to get first video packet
+ while (endIndex < bytes.byteLength) {
+ // Look for a pair of start and end sync bytes in the data..
+ if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) {
+ // We found a packet
+ packet = bytes.subarray(startIndex, endIndex);
+ type = probe.ts.parseType(packet, pmt.pid);
+
+ switch (type) {
+ case 'pes':
+ pesType = probe.ts.parsePesType(packet, pmt.table);
+ pusi = probe.ts.parsePayloadUnitStartIndicator(packet);
+ if (pesType === 'video') {
+ if (pusi && !endLoop) {
+ parsed = probe.ts.parsePesTime(packet);
+ if (parsed) {
+ parsed.type = 'video';
+ result.video.push(parsed);
+ endLoop = true;
+ }
+ }
+ if (!result.firstKeyFrame) {
+ if (pusi) {
+ if (currentFrame.size !== 0) {
+ frame = new Uint8Array(currentFrame.size);
+ i = 0;
+ while (currentFrame.data.length) {
+ pes = currentFrame.data.shift();
+ frame.set(pes, i);
+ i += pes.byteLength;
+ }
+ if (probe.ts.videoPacketContainsKeyFrame(frame)) {
+ var firstKeyFrame = probe.ts.parsePesTime(frame);
+
+ // PTS/DTS may not be available. Simply *not* setting
+ // the keyframe seems to work fine with HLS playback
+ // and definitely preferable to a crash with TypeError...
+ if (firstKeyFrame) {
+ result.firstKeyFrame = firstKeyFrame;
+ result.firstKeyFrame.type = 'video';
+ } else {
+ // eslint-disable-next-line
+ console.warn(
+ 'Failed to extract PTS/DTS from PES at first keyframe. ' +
+ 'This could be an unusual TS segment, or else mux.js did not ' +
+ 'parse your TS segment correctly. If you know your TS ' +
+ 'segments do contain PTS/DTS on keyframes please file a bug ' +
+ 'report! You can try ffprobe to double check for yourself.'
+ );
+ }
+ }
+ currentFrame.size = 0;
+ }
+ }
+ currentFrame.data.push(packet);
+ currentFrame.size += packet.byteLength;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (endLoop && result.firstKeyFrame) {
+ break;
+ }
+
+ startIndex += MP2T_PACKET_LENGTH;
+ endIndex += MP2T_PACKET_LENGTH;
+ continue;
+ }
+
+ // If we get here, we have somehow become de-synchronized and we need to step
+ // forward one byte at a time until we find a pair of sync bytes that denote
+ // a packet
+ startIndex++;
+ endIndex++;
+ }
+
+ // Start walking from end of segment to get last video packet
+ endIndex = bytes.byteLength;
+ startIndex = endIndex - MP2T_PACKET_LENGTH;
+ endLoop = false;
+ while (startIndex >= 0) {
+ // Look for a pair of start and end sync bytes in the data..
+ if (bytes[startIndex] === SYNC_BYTE && bytes[endIndex] === SYNC_BYTE) {
+ // We found a packet
+ packet = bytes.subarray(startIndex, endIndex);
+ type = probe.ts.parseType(packet, pmt.pid);
+
+ switch (type) {
+ case 'pes':
+ pesType = probe.ts.parsePesType(packet, pmt.table);
+ pusi = probe.ts.parsePayloadUnitStartIndicator(packet);
+ if (pesType === 'video' && pusi) {
+ parsed = probe.ts.parsePesTime(packet);
+ if (parsed) {
+ parsed.type = 'video';
+ result.video.push(parsed);
+ endLoop = true;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (endLoop) {
+ break;
+ }
+
+ startIndex -= MP2T_PACKET_LENGTH;
+ endIndex -= MP2T_PACKET_LENGTH;
+ continue;
+ }
+
+ // If we get here, we have somehow become de-synchronized and we need to step
+ // forward one byte at a time until we find a pair of sync bytes that denote
+ // a packet
+ startIndex--;
+ endIndex--;
+ }
+};
+
+/**
+ * Adjusts the timestamp information for the segment to account for
+ * rollover and convert to seconds based on pes packet timescale (90khz clock)
+ */
+var adjustTimestamp_ = function(segmentInfo, baseTimestamp) {
+ if (segmentInfo.audio && segmentInfo.audio.length) {
+ var audioBaseTimestamp = baseTimestamp;
+ if (typeof audioBaseTimestamp === 'undefined') {
+ audioBaseTimestamp = segmentInfo.audio[0].dts;
+ }
+ segmentInfo.audio.forEach(function(info) {
+ info.dts = handleRollover(info.dts, audioBaseTimestamp);
+ info.pts = handleRollover(info.pts, audioBaseTimestamp);
+ // time in seconds
+ info.dtsTime = info.dts / ONE_SECOND_IN_TS;
+ info.ptsTime = info.pts / ONE_SECOND_IN_TS;
+ });
+ }
+
+ if (segmentInfo.video && segmentInfo.video.length) {
+ var videoBaseTimestamp = baseTimestamp;
+ if (typeof videoBaseTimestamp === 'undefined') {
+ videoBaseTimestamp = segmentInfo.video[0].dts;
+ }
+ segmentInfo.video.forEach(function(info) {
+ info.dts = handleRollover(info.dts, videoBaseTimestamp);
+ info.pts = handleRollover(info.pts, videoBaseTimestamp);
+ // time in seconds
+ info.dtsTime = info.dts / ONE_SECOND_IN_TS;
+ info.ptsTime = info.pts / ONE_SECOND_IN_TS;
+ });
+ if (segmentInfo.firstKeyFrame) {
+ var frame = segmentInfo.firstKeyFrame;
+ frame.dts = handleRollover(frame.dts, videoBaseTimestamp);
+ frame.pts = handleRollover(frame.pts, videoBaseTimestamp);
+ // time in seconds
+ frame.dtsTime = frame.dts / ONE_SECOND_IN_TS;
+ frame.ptsTime = frame.dts / ONE_SECOND_IN_TS;
+ }
+ }
+};
+
+/**
+ * inspects the aac data stream for start and end time information
+ */
+var inspectAac_ = function(bytes) {
+ var
+ endLoop = false,
+ audioCount = 0,
+ sampleRate = null,
+ timestamp = null,
+ frameSize = 0,
+ byteIndex = 0,
+ packet;
+
+ while (bytes.length - byteIndex >= 3) {
+ var type = probe.aac.parseType(bytes, byteIndex);
+ switch (type) {
+ case 'timed-metadata':
+ // Exit early because we don't have enough to parse
+ // the ID3 tag header
+ if (bytes.length - byteIndex < 10) {
+ endLoop = true;
+ break;
+ }
+
+ frameSize = probe.aac.parseId3TagSize(bytes, byteIndex);
+
+ // Exit early if we don't have enough in the buffer
+ // to emit a full packet
+ if (frameSize > bytes.length) {
+ endLoop = true;
+ break;
+ }
+ if (timestamp === null) {
+ packet = bytes.subarray(byteIndex, byteIndex + frameSize);
+ timestamp = probe.aac.parseAacTimestamp(packet);
+ }
+ byteIndex += frameSize;
+ break;
+ case 'audio':
+ // Exit early because we don't have enough to parse
+ // the ADTS frame header
+ if (bytes.length - byteIndex < 7) {
+ endLoop = true;
+ break;
+ }
+
+ frameSize = probe.aac.parseAdtsSize(bytes, byteIndex);
+
+ // Exit early if we don't have enough in the buffer
+ // to emit a full packet
+ if (frameSize > bytes.length) {
+ endLoop = true;
+ break;
+ }
+ if (sampleRate === null) {
+ packet = bytes.subarray(byteIndex, byteIndex + frameSize);
+ sampleRate = probe.aac.parseSampleRate(packet);
+ }
+ audioCount++;
+ byteIndex += frameSize;
+ break;
+ default:
+ byteIndex++;
+ break;
+ }
+ if (endLoop) {
+ return null;
+ }
+ }
+ if (sampleRate === null || timestamp === null) {
+ return null;
+ }
+
+ var audioTimescale = ONE_SECOND_IN_TS / sampleRate;
+
+ var result = {
+ audio: [
+ {
+ type: 'audio',
+ dts: timestamp,
+ pts: timestamp
+ },
+ {
+ type: 'audio',
+ dts: timestamp + (audioCount * 1024 * audioTimescale),
+ pts: timestamp + (audioCount * 1024 * audioTimescale)
+ }
+ ]
+ };
+
+ return result;
+};
+
+/**
+ * inspects the transport stream segment data for start and end time information
+ * of the audio and video tracks (when present) as well as the first key frame's
+ * start time.
+ */
+var inspectTs_ = function(bytes) {
+ var pmt = {
+ pid: null,
+ table: null
+ };
+
+ var result = {};
+
+ parsePsi_(bytes, pmt);
+
+ for (var pid in pmt.table) {
+ if (pmt.table.hasOwnProperty(pid)) {
+ var type = pmt.table[pid];
+ switch (type) {
+ case StreamTypes.H264_STREAM_TYPE:
+ result.video = [];
+ parseVideoPes_(bytes, pmt, result);
+ if (result.video.length === 0) {
+ delete result.video;
+ }
+ break;
+ case StreamTypes.ADTS_STREAM_TYPE:
+ result.audio = [];
+ parseAudioPes_(bytes, pmt, result);
+ if (result.audio.length === 0) {
+ delete result.audio;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return result;
+};
+
+/**
+ * Inspects segment byte data and returns an object with start and end timing information
+ *
+ * @param {Uint8Array} bytes The segment byte data
+ * @param {Number} baseTimestamp Relative reference timestamp used when adjusting frame
+ * timestamps for rollover. This value must be in 90khz clock.
+ * @return {Object} Object containing start and end frame timing info of segment.
+ */
+var inspect = function(bytes, baseTimestamp) {
+ var isAacData = probe.aac.isLikelyAacData(bytes);
+
+ var result;
+
+ if (isAacData) {
+ result = inspectAac_(bytes);
+ } else {
+ result = inspectTs_(bytes);
+ }
+
+ if (!result || (!result.audio && !result.video)) {
+ return null;
+ }
+
+ adjustTimestamp_(result, baseTimestamp);
+
+ return result;
+};
+
+module.exports = {
+ inspect: inspect,
+ parseAudioPes_: parseAudioPes_
+};
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/utils/bin.js":
+/*!**********************************************!*\
+ !*** ./node_modules/mux.js/lib/utils/bin.js ***!
+ \**********************************************/
+/***/ ((module) => {
+
+/**
+ * mux.js
+ *
+ * Copyright (c) Brightcove
+ * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
+ */
+var toUnsigned = function(value) {
+ return value >>> 0;
+};
+
+var toHexString = function(value) {
+ return ('00' + value.toString(16)).slice(-2);
+};
+
+module.exports = {
+ toUnsigned: toUnsigned,
+ toHexString: toHexString
+};
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/utils/clock.js":
+/*!************************************************!*\
+ !*** ./node_modules/mux.js/lib/utils/clock.js ***!
+ \************************************************/
+/***/ ((module) => {
+
+/**
+ * mux.js
+ *
+ * Copyright (c) Brightcove
+ * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
+ */
+var
+ ONE_SECOND_IN_TS = 90000, // 90kHz clock
+ secondsToVideoTs,
+ secondsToAudioTs,
+ videoTsToSeconds,
+ audioTsToSeconds,
+ audioTsToVideoTs,
+ videoTsToAudioTs,
+ metadataTsToSeconds;
+
+secondsToVideoTs = function(seconds) {
+ return seconds * ONE_SECOND_IN_TS;
+};
+
+secondsToAudioTs = function(seconds, sampleRate) {
+ return seconds * sampleRate;
+};
+
+videoTsToSeconds = function(timestamp) {
+ return timestamp / ONE_SECOND_IN_TS;
+};
+
+audioTsToSeconds = function(timestamp, sampleRate) {
+ return timestamp / sampleRate;
+};
+
+audioTsToVideoTs = function(timestamp, sampleRate) {
+ return secondsToVideoTs(audioTsToSeconds(timestamp, sampleRate));
+};
+
+videoTsToAudioTs = function(timestamp, sampleRate) {
+ return secondsToAudioTs(videoTsToSeconds(timestamp), sampleRate);
+};
+
+/**
+ * Adjust ID3 tag or caption timing information by the timeline pts values
+ * (if keepOriginalTimestamps is false) and convert to seconds
+ */
+metadataTsToSeconds = function(timestamp, timelineStartPts, keepOriginalTimestamps) {
+ return videoTsToSeconds(keepOriginalTimestamps ? timestamp : timestamp - timelineStartPts);
+};
+
+module.exports = {
+ ONE_SECOND_IN_TS: ONE_SECOND_IN_TS,
+ secondsToVideoTs: secondsToVideoTs,
+ secondsToAudioTs: secondsToAudioTs,
+ videoTsToSeconds: videoTsToSeconds,
+ audioTsToSeconds: audioTsToSeconds,
+ audioTsToVideoTs: audioTsToVideoTs,
+ videoTsToAudioTs: videoTsToAudioTs,
+ metadataTsToSeconds: metadataTsToSeconds
+};
+
+
+/***/ }),
+
+/***/ "./node_modules/mux.js/lib/utils/stream.js":
+/*!*************************************************!*\
+ !*** ./node_modules/mux.js/lib/utils/stream.js ***!
+ \*************************************************/
+/***/ ((module) => {
+
+"use strict";
+/**
+ * mux.js
+ *
+ * Copyright (c) Brightcove
+ * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
+ *
+ * A lightweight readable stream implemention that handles event dispatching.
+ * Objects that inherit from streams should call init in their constructors.
+ */
+
+
+var Stream = function() {
+ this.init = function() {
+ var listeners = {};
+ /**
+ * Add a listener for a specified event type.
+ * @param type {string} the event name
+ * @param listener {function} the callback to be invoked when an event of
+ * the specified type occurs
+ */
+ this.on = function(type, listener) {
+ if (!listeners[type]) {
+ listeners[type] = [];
+ }
+ listeners[type] = listeners[type].concat(listener);
+ };
+ /**
+ * Remove a listener for a specified event type.
+ * @param type {string} the event name
+ * @param listener {function} a function previously registered for this
+ * type of event through `on`
+ */
+ this.off = function(type, listener) {
+ var index;
+ if (!listeners[type]) {
+ return false;
+ }
+ index = listeners[type].indexOf(listener);
+ listeners[type] = listeners[type].slice();
+ listeners[type].splice(index, 1);
+ return index > -1;
+ };
+ /**
+ * Trigger an event of the specified type on this stream. Any additional
+ * arguments to this function are passed as parameters to event listeners.
+ * @param type {string} the event name
+ */
+ this.trigger = function(type) {
+ var callbacks, i, length, args;
+ callbacks = listeners[type];
+ if (!callbacks) {
+ return;
+ }
+ // Slicing the arguments on every invocation of this method
+ // can add a significant amount of overhead. Avoid the
+ // intermediate object creation for the common case of a
+ // single callback argument
+ if (arguments.length === 2) {
+ length = callbacks.length;
+ for (i = 0; i < length; ++i) {
+ callbacks[i].call(this, arguments[1]);
+ }
+ } else {
+ args = [];
+ i = arguments.length;
+ for (i = 1; i < arguments.length; ++i) {
+ args.push(arguments[i]);
+ }
+ length = callbacks.length;
+ for (i = 0; i < length; ++i) {
+ callbacks[i].apply(this, args);
+ }
+ }
+ };
+ /**
+ * Destroys the stream and cleans up.
+ */
+ this.dispose = function() {
+ listeners = {};
+ };
+ };
+};
+
+/**
+ * Forwards all `data` events on this stream to the destination stream. The
+ * destination stream should provide a method `push` to receive the data
+ * events as they arrive.
+ * @param destination {stream} the stream that will receive all `data` events
+ * @param autoFlush {boolean} if false, we will not call `flush` on the destination
+ * when the current stream emits a 'done' event
+ * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
+ */
+Stream.prototype.pipe = function(destination) {
+ this.on('data', function(data) {
+ destination.push(data);
+ });
+
+ this.on('done', function(flushSource) {
+ destination.flush(flushSource);
+ });
+
+ this.on('partialdone', function(flushSource) {
+ destination.partialFlush(flushSource);
+ });
+
+ this.on('endedtimeline', function(flushSource) {
+ destination.endTimeline(flushSource);
+ });
+
+ this.on('reset', function(flushSource) {
+ destination.reset(flushSource);
+ });
+
+ return destination;
+};
+
+// Default stream functions that are expected to be overridden to perform
+// actual work. These are provided by the prototype as a sort of no-op
+// implementation so that we don't have to check for their existence in the
+// `pipe` function above.
+Stream.prototype.push = function(data) {
+ this.trigger('data', data);
+};
+
+Stream.prototype.flush = function(flushSource) {
+ this.trigger('done', flushSource);
+};
+
+Stream.prototype.partialFlush = function(flushSource) {
+ this.trigger('partialdone', flushSource);
+};
+
+Stream.prototype.endTimeline = function(flushSource) {
+ this.trigger('endedtimeline', flushSource);
+};
+
+Stream.prototype.reset = function(flushSource) {
+ this.trigger('reset', flushSource);
+};
+
+module.exports = Stream;
+
+
+/***/ }),
+
+/***/ "./node_modules/safe-json-parse/tuple.js":
+/*!***********************************************!*\
+ !*** ./node_modules/safe-json-parse/tuple.js ***!
+ \***********************************************/
+/***/ ((module) => {
+
+module.exports = SafeParseTuple
+
+function SafeParseTuple(obj, reviver) {
+ var json
+ var error = null
+
+ try {
+ json = JSON.parse(obj, reviver)
+ } catch (err) {
+ error = err
+ }
+
+ return [error, json]
+}
+
+
+/***/ }),
+
+/***/ "./node_modules/url-toolkit/src/url-toolkit.js":
+/*!*****************************************************!*\
+ !*** ./node_modules/url-toolkit/src/url-toolkit.js ***!
+ \*****************************************************/
+/***/ (function(module) {
+
+// see https://tools.ietf.org/html/rfc1808
+
+(function (root) {
+ var URL_REGEX = /^((?:[a-zA-Z0-9+\-.]+:)?)(\/\/[^\/?#]*)?((?:[^\/?#]*\/)*[^;?#]*)?(;[^?#]*)?(\?[^#]*)?(#.*)?$/;
+ var FIRST_SEGMENT_REGEX = /^([^\/?#]*)(.*)$/;
+ var SLASH_DOT_REGEX = /(?:\/|^)\.(?=\/)/g;
+ var SLASH_DOT_DOT_REGEX = /(?:\/|^)\.\.\/(?!\.\.\/)[^\/]*(?=\/)/g;
+
+ var URLToolkit = {
+ // If opts.alwaysNormalize is true then the path will always be normalized even when it starts with / or //
+ // E.g
+ // With opts.alwaysNormalize = false (default, spec compliant)
+ // http://a.com/b/cd + /e/f/../g => http://a.com/e/f/../g
+ // With opts.alwaysNormalize = true (not spec compliant)
+ // http://a.com/b/cd + /e/f/../g => http://a.com/e/g
+ buildAbsoluteURL: function (baseURL, relativeURL, opts) {
+ opts = opts || {};
+ // remove any remaining space and CRLF
+ baseURL = baseURL.trim();
+ relativeURL = relativeURL.trim();
+ if (!relativeURL) {
+ // 2a) If the embedded URL is entirely empty, it inherits the
+ // entire base URL (i.e., is set equal to the base URL)
+ // and we are done.
+ if (!opts.alwaysNormalize) {
+ return baseURL;
+ }
+ var basePartsForNormalise = URLToolkit.parseURL(baseURL);
+ if (!basePartsForNormalise) {
+ throw new Error('Error trying to parse base URL.');
+ }
+ basePartsForNormalise.path = URLToolkit.normalizePath(
+ basePartsForNormalise.path
+ );
+ return URLToolkit.buildURLFromParts(basePartsForNormalise);
+ }
+ var relativeParts = URLToolkit.parseURL(relativeURL);
+ if (!relativeParts) {
+ throw new Error('Error trying to parse relative URL.');
+ }
+ if (relativeParts.scheme) {
+ // 2b) If the embedded URL starts with a scheme name, it is
+ // interpreted as an absolute URL and we are done.
+ if (!opts.alwaysNormalize) {
+ return relativeURL;
+ }
+ relativeParts.path = URLToolkit.normalizePath(relativeParts.path);
+ return URLToolkit.buildURLFromParts(relativeParts);
+ }
+ var baseParts = URLToolkit.parseURL(baseURL);
+ if (!baseParts) {
+ throw new Error('Error trying to parse base URL.');
+ }
+ if (!baseParts.netLoc && baseParts.path && baseParts.path[0] !== '/') {
+ // If netLoc missing and path doesn't start with '/', assume everthing before the first '/' is the netLoc
+ // This causes 'example.com/a' to be handled as '//example.com/a' instead of '/example.com/a'
+ var pathParts = FIRST_SEGMENT_REGEX.exec(baseParts.path);
+ baseParts.netLoc = pathParts[1];
+ baseParts.path = pathParts[2];
+ }
+ if (baseParts.netLoc && !baseParts.path) {
+ baseParts.path = '/';
+ }
+ var builtParts = {
+ // 2c) Otherwise, the embedded URL inherits the scheme of
+ // the base URL.
+ scheme: baseParts.scheme,
+ netLoc: relativeParts.netLoc,
+ path: null,
+ params: relativeParts.params,
+ query: relativeParts.query,
+ fragment: relativeParts.fragment,
+ };
+ if (!relativeParts.netLoc) {
+ // 3) If the embedded URL's is non-empty, we skip to
+ // Step 7. Otherwise, the embedded URL inherits the
+ // (if any) of the base URL.
+ builtParts.netLoc = baseParts.netLoc;
+ // 4) If the embedded URL path is preceded by a slash "/", the
+ // path is not relative and we skip to Step 7.
+ if (relativeParts.path[0] !== '/') {
+ if (!relativeParts.path) {
+ // 5) If the embedded URL path is empty (and not preceded by a
+ // slash), then the embedded URL inherits the base URL path
+ builtParts.path = baseParts.path;
+ // 5a) if the embedded URL's is non-empty, we skip to
+ // step 7; otherwise, it inherits the of the base
+ // URL (if any) and
+ if (!relativeParts.params) {
+ builtParts.params = baseParts.params;
+ // 5b) if the embedded URL's is non-empty, we skip to
+ // step 7; otherwise, it inherits the of the base
+ // URL (if any) and we skip to step 7.
+ if (!relativeParts.query) {
+ builtParts.query = baseParts.query;
+ }
+ }
+ } else {
+ // 6) The last segment of the base URL's path (anything
+ // following the rightmost slash "/", or the entire path if no
+ // slash is present) is removed and the embedded URL's path is
+ // appended in its place.
+ var baseURLPath = baseParts.path;
+ var newPath =
+ baseURLPath.substring(0, baseURLPath.lastIndexOf('/') + 1) +
+ relativeParts.path;
+ builtParts.path = URLToolkit.normalizePath(newPath);
+ }
+ }
+ }
+ if (builtParts.path === null) {
+ builtParts.path = opts.alwaysNormalize
+ ? URLToolkit.normalizePath(relativeParts.path)
+ : relativeParts.path;
+ }
+ return URLToolkit.buildURLFromParts(builtParts);
+ },
+ parseURL: function (url) {
+ var parts = URL_REGEX.exec(url);
+ if (!parts) {
+ return null;
+ }
+ return {
+ scheme: parts[1] || '',
+ netLoc: parts[2] || '',
+ path: parts[3] || '',
+ params: parts[4] || '',
+ query: parts[5] || '',
+ fragment: parts[6] || '',
+ };
+ },
+ normalizePath: function (path) {
+ // The following operations are
+ // then applied, in order, to the new path:
+ // 6a) All occurrences of "./", where "." is a complete path
+ // segment, are removed.
+ // 6b) If the path ends with "." as a complete path segment,
+ // that "." is removed.
+ path = path.split('').reverse().join('').replace(SLASH_DOT_REGEX, '');
+ // 6c) All occurrences of "/../", where is a
+ // complete path segment not equal to "..", are removed.
+ // Removal of these path segments is performed iteratively,
+ // removing the leftmost matching pattern on each iteration,
+ // until no matching pattern remains.
+ // 6d) If the path ends with "/..", where is a
+ // complete path segment not equal to "..", that
+ // "/.." is removed.
+ while (
+ path.length !== (path = path.replace(SLASH_DOT_DOT_REGEX, '')).length
+ ) {}
+ return path.split('').reverse().join('');
+ },
+ buildURLFromParts: function (parts) {
+ return (
+ parts.scheme +
+ parts.netLoc +
+ parts.path +
+ parts.params +
+ parts.query +
+ parts.fragment
+ );
+ },
+ };
+
+ if (true)
+ module.exports = URLToolkit;
+ else {}
+})(this);
+
+
+/***/ }),
+
+/***/ "./node_modules/video.js/dist/video.es.js":
+/*!************************************************!*\
+ !*** ./node_modules/video.js/dist/video.es.js ***!
+ \************************************************/
+/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export */ __webpack_require__.d(__webpack_exports__, {
+/* harmony export */ "default": () => __WEBPACK_DEFAULT_EXPORT__
+/* harmony export */ });
+/* harmony import */ var global_window__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! global/window */ "./node_modules/video.js/node_modules/global/window.js");
+/* harmony import */ var global_window__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(global_window__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var global_document__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! global/document */ "./node_modules/video.js/node_modules/global/document.js");
+/* harmony import */ var global_document__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(global_document__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @babel/runtime/helpers/extends */ "./node_modules/@babel/runtime/helpers/extends.js");
+/* harmony import */ var _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_2__);
+/* harmony import */ var _babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @babel/runtime/helpers/assertThisInitialized */ "./node_modules/@babel/runtime/helpers/assertThisInitialized.js");
+/* harmony import */ var _babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3__);
+/* harmony import */ var _babel_runtime_helpers_possibleConstructorReturn__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @babel/runtime/helpers/possibleConstructorReturn */ "./node_modules/@babel/runtime/helpers/possibleConstructorReturn.js");
+/* harmony import */ var _babel_runtime_helpers_possibleConstructorReturn__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_possibleConstructorReturn__WEBPACK_IMPORTED_MODULE_4__);
+/* harmony import */ var _babel_runtime_helpers_getPrototypeOf__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @babel/runtime/helpers/getPrototypeOf */ "./node_modules/@babel/runtime/helpers/getPrototypeOf.js");
+/* harmony import */ var _babel_runtime_helpers_getPrototypeOf__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_getPrototypeOf__WEBPACK_IMPORTED_MODULE_5__);
+/* harmony import */ var _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @babel/runtime/helpers/inheritsLoose */ "./node_modules/@babel/runtime/helpers/inheritsLoose.js");
+/* harmony import */ var _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6__);
+/* harmony import */ var safe_json_parse_tuple__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! safe-json-parse/tuple */ "./node_modules/safe-json-parse/tuple.js");
+/* harmony import */ var safe_json_parse_tuple__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(safe_json_parse_tuple__WEBPACK_IMPORTED_MODULE_7__);
+/* harmony import */ var keycode__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! keycode */ "./node_modules/keycode/index.js");
+/* harmony import */ var keycode__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(keycode__WEBPACK_IMPORTED_MODULE_8__);
+/* harmony import */ var _videojs_xhr__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @videojs/xhr */ "./node_modules/@videojs/xhr/index.js");
+/* harmony import */ var _videojs_xhr__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(_videojs_xhr__WEBPACK_IMPORTED_MODULE_9__);
+/* harmony import */ var videojs_vtt_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! videojs-vtt.js */ "./node_modules/videojs-vtt.js/lib/browser-index.js");
+/* harmony import */ var videojs_vtt_js__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(videojs_vtt_js__WEBPACK_IMPORTED_MODULE_10__);
+/* harmony import */ var _babel_runtime_helpers_construct__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @babel/runtime/helpers/construct */ "./node_modules/@babel/runtime/helpers/construct.js");
+/* harmony import */ var _babel_runtime_helpers_construct__WEBPACK_IMPORTED_MODULE_11___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_construct__WEBPACK_IMPORTED_MODULE_11__);
+/* harmony import */ var _babel_runtime_helpers_inherits__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @babel/runtime/helpers/inherits */ "./node_modules/@babel/runtime/helpers/inherits.js");
+/* harmony import */ var _babel_runtime_helpers_inherits__WEBPACK_IMPORTED_MODULE_12___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_inherits__WEBPACK_IMPORTED_MODULE_12__);
+/* harmony import */ var _videojs_vhs_utils_dist_resolve_url_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @videojs/vhs-utils/dist/resolve-url.js */ "./node_modules/@videojs/vhs-utils/dist/resolve-url.js");
+/* harmony import */ var _videojs_vhs_utils_dist_resolve_url_js__WEBPACK_IMPORTED_MODULE_13___default = /*#__PURE__*/__webpack_require__.n(_videojs_vhs_utils_dist_resolve_url_js__WEBPACK_IMPORTED_MODULE_13__);
+/* harmony import */ var m3u8_parser__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! m3u8-parser */ "./node_modules/m3u8-parser/dist/m3u8-parser.es.js");
+/* harmony import */ var _videojs_vhs_utils_dist_media_types_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @videojs/vhs-utils/dist/media-types.js */ "./node_modules/@videojs/vhs-utils/dist/media-types.js");
+/* harmony import */ var mpd_parser__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! mpd-parser */ "./node_modules/mpd-parser/dist/mpd-parser.es.js");
+/* harmony import */ var mux_js_lib_tools_parse_sidx__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! mux.js/lib/tools/parse-sidx */ "./node_modules/mux.js/lib/tools/parse-sidx.js");
+/* harmony import */ var mux_js_lib_tools_parse_sidx__WEBPACK_IMPORTED_MODULE_17___default = /*#__PURE__*/__webpack_require__.n(mux_js_lib_tools_parse_sidx__WEBPACK_IMPORTED_MODULE_17__);
+/* harmony import */ var _videojs_vhs_utils_dist_containers__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @videojs/vhs-utils/dist/containers */ "./node_modules/@videojs/vhs-utils/dist/containers.js");
+/* harmony import */ var _videojs_vhs_utils_dist_byte_helpers__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @videojs/vhs-utils/dist/byte-helpers */ "./node_modules/@videojs/vhs-utils/dist/byte-helpers.js");
+/* harmony import */ var mux_js_lib_tools_ts_inspector_js__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! mux.js/lib/tools/ts-inspector.js */ "./node_modules/mux.js/lib/tools/ts-inspector.js");
+/* harmony import */ var mux_js_lib_tools_ts_inspector_js__WEBPACK_IMPORTED_MODULE_20___default = /*#__PURE__*/__webpack_require__.n(mux_js_lib_tools_ts_inspector_js__WEBPACK_IMPORTED_MODULE_20__);
+/* harmony import */ var mux_js_lib_utils_clock__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! mux.js/lib/utils/clock */ "./node_modules/mux.js/lib/utils/clock.js");
+/* harmony import */ var mux_js_lib_utils_clock__WEBPACK_IMPORTED_MODULE_21___default = /*#__PURE__*/__webpack_require__.n(mux_js_lib_utils_clock__WEBPACK_IMPORTED_MODULE_21__);
+/* harmony import */ var mux_js_lib_mp4_probe__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! mux.js/lib/mp4/probe */ "./node_modules/mux.js/lib/mp4/probe.js");
+/* harmony import */ var mux_js_lib_mp4_probe__WEBPACK_IMPORTED_MODULE_22___default = /*#__PURE__*/__webpack_require__.n(mux_js_lib_mp4_probe__WEBPACK_IMPORTED_MODULE_22__);
+/* harmony import */ var _videojs_vhs_utils_dist_codecs_js__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @videojs/vhs-utils/dist/codecs.js */ "./node_modules/@videojs/vhs-utils/dist/codecs.js");
+/**
+ * @license
+ * Video.js 7.10.2
+ * Copyright Brightcove, Inc.
+ * Available under Apache License Version 2.0
+ *
+ *
+ * Includes vtt.js
+ * Available under Apache License Version 2.0
+ *
+ */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+var version = "7.10.2";
+
+/**
+ * @file create-logger.js
+ * @module create-logger
+ */
+
+var history = [];
+/**
+ * Log messages to the console and history based on the type of message
+ *
+ * @private
+ * @param {string} type
+ * The name of the console method to use.
+ *
+ * @param {Array} args
+ * The arguments to be passed to the matching console method.
+ */
+
+var LogByTypeFactory = function LogByTypeFactory(name, log) {
+ return function (type, level, args) {
+ var lvl = log.levels[level];
+ var lvlRegExp = new RegExp("^(" + lvl + ")$");
+
+ if (type !== 'log') {
+ // Add the type to the front of the message when it's not "log".
+ args.unshift(type.toUpperCase() + ':');
+ } // Add console prefix after adding to history.
+
+
+ args.unshift(name + ':'); // Add a clone of the args at this point to history.
+
+ if (history) {
+ history.push([].concat(args)); // only store 1000 history entries
+
+ var splice = history.length - 1000;
+ history.splice(0, splice > 0 ? splice : 0);
+ } // If there's no console then don't try to output messages, but they will
+ // still be stored in history.
+
+
+ if (!(global_window__WEBPACK_IMPORTED_MODULE_0___default().console)) {
+ return;
+ } // Was setting these once outside of this function, but containing them
+ // in the function makes it easier to test cases where console doesn't exist
+ // when the module is executed.
+
+
+ var fn = (global_window__WEBPACK_IMPORTED_MODULE_0___default().console)[type];
+
+ if (!fn && type === 'debug') {
+ // Certain browsers don't have support for console.debug. For those, we
+ // should default to the closest comparable log.
+ fn = (global_window__WEBPACK_IMPORTED_MODULE_0___default().console.info) || (global_window__WEBPACK_IMPORTED_MODULE_0___default().console.log);
+ } // Bail out if there's no console or if this type is not allowed by the
+ // current logging level.
+
+
+ if (!fn || !lvl || !lvlRegExp.test(type)) {
+ return;
+ }
+
+ fn[Array.isArray(args) ? 'apply' : 'call']((global_window__WEBPACK_IMPORTED_MODULE_0___default().console), args);
+ };
+};
+
+function createLogger(name) {
+ // This is the private tracking variable for logging level.
+ var level = 'info'; // the curried logByType bound to the specific log and history
+
+ var logByType;
+ /**
+ * Logs plain debug messages. Similar to `console.log`.
+ *
+ * Due to [limitations](https://github.com/jsdoc3/jsdoc/issues/955#issuecomment-313829149)
+ * of our JSDoc template, we cannot properly document this as both a function
+ * and a namespace, so its function signature is documented here.
+ *
+ * #### Arguments
+ * ##### *args
+ * Mixed[]
+ *
+ * Any combination of values that could be passed to `console.log()`.
+ *
+ * #### Return Value
+ *
+ * `undefined`
+ *
+ * @namespace
+ * @param {Mixed[]} args
+ * One or more messages or objects that should be logged.
+ */
+
+ var log = function log() {
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ logByType('log', level, args);
+ }; // This is the logByType helper that the logging methods below use
+
+
+ logByType = LogByTypeFactory(name, log);
+ /**
+ * Create a new sublogger which chains the old name to the new name.
+ *
+ * For example, doing `videojs.log.createLogger('player')` and then using that logger will log the following:
+ * ```js
+ * mylogger('foo');
+ * // > VIDEOJS: player: foo
+ * ```
+ *
+ * @param {string} name
+ * The name to add call the new logger
+ * @return {Object}
+ */
+
+ log.createLogger = function (subname) {
+ return createLogger(name + ': ' + subname);
+ };
+ /**
+ * Enumeration of available logging levels, where the keys are the level names
+ * and the values are `|`-separated strings containing logging methods allowed
+ * in that logging level. These strings are used to create a regular expression
+ * matching the function name being called.
+ *
+ * Levels provided by Video.js are:
+ *
+ * - `off`: Matches no calls. Any value that can be cast to `false` will have
+ * this effect. The most restrictive.
+ * - `all`: Matches only Video.js-provided functions (`debug`, `log`,
+ * `log.warn`, and `log.error`).
+ * - `debug`: Matches `log.debug`, `log`, `log.warn`, and `log.error` calls.
+ * - `info` (default): Matches `log`, `log.warn`, and `log.error` calls.
+ * - `warn`: Matches `log.warn` and `log.error` calls.
+ * - `error`: Matches only `log.error` calls.
+ *
+ * @type {Object}
+ */
+
+
+ log.levels = {
+ all: 'debug|log|warn|error',
+ off: '',
+ debug: 'debug|log|warn|error',
+ info: 'log|warn|error',
+ warn: 'warn|error',
+ error: 'error',
+ DEFAULT: level
+ };
+ /**
+ * Get or set the current logging level.
+ *
+ * If a string matching a key from {@link module:log.levels} is provided, acts
+ * as a setter.
+ *
+ * @param {string} [lvl]
+ * Pass a valid level to set a new logging level.
+ *
+ * @return {string}
+ * The current logging level.
+ */
+
+ log.level = function (lvl) {
+ if (typeof lvl === 'string') {
+ if (!log.levels.hasOwnProperty(lvl)) {
+ throw new Error("\"" + lvl + "\" in not a valid log level");
+ }
+
+ level = lvl;
+ }
+
+ return level;
+ };
+ /**
+ * Returns an array containing everything that has been logged to the history.
+ *
+ * This array is a shallow clone of the internal history record. However, its
+ * contents are _not_ cloned; so, mutating objects inside this array will
+ * mutate them in history.
+ *
+ * @return {Array}
+ */
+
+
+ log.history = function () {
+ return history ? [].concat(history) : [];
+ };
+ /**
+ * Allows you to filter the history by the given logger name
+ *
+ * @param {string} fname
+ * The name to filter by
+ *
+ * @return {Array}
+ * The filtered list to return
+ */
+
+
+ log.history.filter = function (fname) {
+ return (history || []).filter(function (historyItem) {
+ // if the first item in each historyItem includes `fname`, then it's a match
+ return new RegExp(".*" + fname + ".*").test(historyItem[0]);
+ });
+ };
+ /**
+ * Clears the internal history tracking, but does not prevent further history
+ * tracking.
+ */
+
+
+ log.history.clear = function () {
+ if (history) {
+ history.length = 0;
+ }
+ };
+ /**
+ * Disable history tracking if it is currently enabled.
+ */
+
+
+ log.history.disable = function () {
+ if (history !== null) {
+ history.length = 0;
+ history = null;
+ }
+ };
+ /**
+ * Enable history tracking if it is currently disabled.
+ */
+
+
+ log.history.enable = function () {
+ if (history === null) {
+ history = [];
+ }
+ };
+ /**
+ * Logs error messages. Similar to `console.error`.
+ *
+ * @param {Mixed[]} args
+ * One or more messages or objects that should be logged as an error
+ */
+
+
+ log.error = function () {
+ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+ args[_key2] = arguments[_key2];
+ }
+
+ return logByType('error', level, args);
+ };
+ /**
+ * Logs warning messages. Similar to `console.warn`.
+ *
+ * @param {Mixed[]} args
+ * One or more messages or objects that should be logged as a warning.
+ */
+
+
+ log.warn = function () {
+ for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
+ args[_key3] = arguments[_key3];
+ }
+
+ return logByType('warn', level, args);
+ };
+ /**
+ * Logs debug messages. Similar to `console.debug`, but may also act as a comparable
+ * log if `console.debug` is not available
+ *
+ * @param {Mixed[]} args
+ * One or more messages or objects that should be logged as debug.
+ */
+
+
+ log.debug = function () {
+ for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
+ args[_key4] = arguments[_key4];
+ }
+
+ return logByType('debug', level, args);
+ };
+
+ return log;
+}
+
+/**
+ * @file log.js
+ * @module log
+ */
+var log = createLogger('VIDEOJS');
+var createLogger$1 = log.createLogger;
+
+/**
+ * @file obj.js
+ * @module obj
+ */
+
+/**
+ * @callback obj:EachCallback
+ *
+ * @param {Mixed} value
+ * The current key for the object that is being iterated over.
+ *
+ * @param {string} key
+ * The current key-value for object that is being iterated over
+ */
+
+/**
+ * @callback obj:ReduceCallback
+ *
+ * @param {Mixed} accum
+ * The value that is accumulating over the reduce loop.
+ *
+ * @param {Mixed} value
+ * The current key for the object that is being iterated over.
+ *
+ * @param {string} key
+ * The current key-value for object that is being iterated over
+ *
+ * @return {Mixed}
+ * The new accumulated value.
+ */
+var toString = Object.prototype.toString;
+/**
+ * Get the keys of an Object
+ *
+ * @param {Object}
+ * The Object to get the keys from
+ *
+ * @return {string[]}
+ * An array of the keys from the object. Returns an empty array if the
+ * object passed in was invalid or had no keys.
+ *
+ * @private
+ */
+
+var keys = function keys(object) {
+ return isObject(object) ? Object.keys(object) : [];
+};
+/**
+ * Array-like iteration for objects.
+ *
+ * @param {Object} object
+ * The object to iterate over
+ *
+ * @param {obj:EachCallback} fn
+ * The callback function which is called for each key in the object.
+ */
+
+
+function each(object, fn) {
+ keys(object).forEach(function (key) {
+ return fn(object[key], key);
+ });
+}
+/**
+ * Array-like reduce for objects.
+ *
+ * @param {Object} object
+ * The Object that you want to reduce.
+ *
+ * @param {Function} fn
+ * A callback function which is called for each key in the object. It
+ * receives the accumulated value and the per-iteration value and key
+ * as arguments.
+ *
+ * @param {Mixed} [initial = 0]
+ * Starting value
+ *
+ * @return {Mixed}
+ * The final accumulated value.
+ */
+
+function reduce(object, fn, initial) {
+ if (initial === void 0) {
+ initial = 0;
+ }
+
+ return keys(object).reduce(function (accum, key) {
+ return fn(accum, object[key], key);
+ }, initial);
+}
+/**
+ * Object.assign-style object shallow merge/extend.
+ *
+ * @param {Object} target
+ * @param {Object} ...sources
+ * @return {Object}
+ */
+
+function assign(target) {
+ for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ sources[_key - 1] = arguments[_key];
+ }
+
+ if (Object.assign) {
+ return _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_2___default().apply(void 0, [target].concat(sources));
+ }
+
+ sources.forEach(function (source) {
+ if (!source) {
+ return;
+ }
+
+ each(source, function (value, key) {
+ target[key] = value;
+ });
+ });
+ return target;
+}
+/**
+ * Returns whether a value is an object of any kind - including DOM nodes,
+ * arrays, regular expressions, etc. Not functions, though.
+ *
+ * This avoids the gotcha where using `typeof` on a `null` value
+ * results in `'object'`.
+ *
+ * @param {Object} value
+ * @return {boolean}
+ */
+
+function isObject(value) {
+ return !!value && typeof value === 'object';
+}
+/**
+ * Returns whether an object appears to be a "plain" object - that is, a
+ * direct instance of `Object`.
+ *
+ * @param {Object} value
+ * @return {boolean}
+ */
+
+function isPlain(value) {
+ return isObject(value) && toString.call(value) === '[object Object]' && value.constructor === Object;
+}
+
+/**
+ * @file computed-style.js
+ * @module computed-style
+ */
+/**
+ * A safe getComputedStyle.
+ *
+ * This is needed because in Firefox, if the player is loaded in an iframe with
+ * `display:none`, then `getComputedStyle` returns `null`, so, we do a
+ * null-check to make sure that the player doesn't break in these cases.
+ *
+ * @function
+ * @param {Element} el
+ * The element you want the computed style of
+ *
+ * @param {string} prop
+ * The property name you want
+ *
+ * @see https://bugzilla.mozilla.org/show_bug.cgi?id=548397
+ */
+
+function computedStyle(el, prop) {
+ if (!el || !prop) {
+ return '';
+ }
+
+ if (typeof (global_window__WEBPACK_IMPORTED_MODULE_0___default().getComputedStyle) === 'function') {
+ var computedStyleValue = global_window__WEBPACK_IMPORTED_MODULE_0___default().getComputedStyle(el);
+ return computedStyleValue ? computedStyleValue.getPropertyValue(prop) || computedStyleValue[prop] : '';
+ }
+
+ return '';
+}
+
+/**
+ * @file dom.js
+ * @module dom
+ */
+/**
+ * Detect if a value is a string with any non-whitespace characters.
+ *
+ * @private
+ * @param {string} str
+ * The string to check
+ *
+ * @return {boolean}
+ * Will be `true` if the string is non-blank, `false` otherwise.
+ *
+ */
+
+function isNonBlankString(str) {
+ // we use str.trim as it will trim any whitespace characters
+ // from the front or back of non-whitespace characters. aka
+ // Any string that contains non-whitespace characters will
+ // still contain them after `trim` but whitespace only strings
+ // will have a length of 0, failing this check.
+ return typeof str === 'string' && Boolean(str.trim());
+}
+/**
+ * Throws an error if the passed string has whitespace. This is used by
+ * class methods to be relatively consistent with the classList API.
+ *
+ * @private
+ * @param {string} str
+ * The string to check for whitespace.
+ *
+ * @throws {Error}
+ * Throws an error if there is whitespace in the string.
+ */
+
+
+function throwIfWhitespace(str) {
+ // str.indexOf instead of regex because str.indexOf is faster performance wise.
+ if (str.indexOf(' ') >= 0) {
+ throw new Error('class has illegal whitespace characters');
+ }
+}
+/**
+ * Produce a regular expression for matching a className within an elements className.
+ *
+ * @private
+ * @param {string} className
+ * The className to generate the RegExp for.
+ *
+ * @return {RegExp}
+ * The RegExp that will check for a specific `className` in an elements
+ * className.
+ */
+
+
+function classRegExp(className) {
+ return new RegExp('(^|\\s)' + className + '($|\\s)');
+}
+/**
+ * Whether the current DOM interface appears to be real (i.e. not simulated).
+ *
+ * @return {boolean}
+ * Will be `true` if the DOM appears to be real, `false` otherwise.
+ */
+
+
+function isReal() {
+ // Both document and window will never be undefined thanks to `global`.
+ return (global_document__WEBPACK_IMPORTED_MODULE_1___default()) === (global_window__WEBPACK_IMPORTED_MODULE_0___default().document);
+}
+/**
+ * Determines, via duck typing, whether or not a value is a DOM element.
+ *
+ * @param {Mixed} value
+ * The value to check.
+ *
+ * @return {boolean}
+ * Will be `true` if the value is a DOM element, `false` otherwise.
+ */
+
+function isEl(value) {
+ return isObject(value) && value.nodeType === 1;
+}
+/**
+ * Determines if the current DOM is embedded in an iframe.
+ *
+ * @return {boolean}
+ * Will be `true` if the DOM is embedded in an iframe, `false`
+ * otherwise.
+ */
+
+function isInFrame() {
+ // We need a try/catch here because Safari will throw errors when attempting
+ // to get either `parent` or `self`
+ try {
+ return (global_window__WEBPACK_IMPORTED_MODULE_0___default().parent) !== (global_window__WEBPACK_IMPORTED_MODULE_0___default().self);
+ } catch (x) {
+ return true;
+ }
+}
+/**
+ * Creates functions to query the DOM using a given method.
+ *
+ * @private
+ * @param {string} method
+ * The method to create the query with.
+ *
+ * @return {Function}
+ * The query method
+ */
+
+function createQuerier(method) {
+ return function (selector, context) {
+ if (!isNonBlankString(selector)) {
+ return (global_document__WEBPACK_IMPORTED_MODULE_1___default())[method](null);
+ }
+
+ if (isNonBlankString(context)) {
+ context = global_document__WEBPACK_IMPORTED_MODULE_1___default().querySelector(context);
+ }
+
+ var ctx = isEl(context) ? context : (global_document__WEBPACK_IMPORTED_MODULE_1___default());
+ return ctx[method] && ctx[method](selector);
+ };
+}
+/**
+ * Creates an element and applies properties, attributes, and inserts content.
+ *
+ * @param {string} [tagName='div']
+ * Name of tag to be created.
+ *
+ * @param {Object} [properties={}]
+ * Element properties to be applied.
+ *
+ * @param {Object} [attributes={}]
+ * Element attributes to be applied.
+ *
+ * @param {module:dom~ContentDescriptor} content
+ * A content descriptor object.
+ *
+ * @return {Element}
+ * The element that was created.
+ */
+
+
+function createEl(tagName, properties, attributes, content) {
+ if (tagName === void 0) {
+ tagName = 'div';
+ }
+
+ if (properties === void 0) {
+ properties = {};
+ }
+
+ if (attributes === void 0) {
+ attributes = {};
+ }
+
+ var el = global_document__WEBPACK_IMPORTED_MODULE_1___default().createElement(tagName);
+ Object.getOwnPropertyNames(properties).forEach(function (propName) {
+ var val = properties[propName]; // See #2176
+ // We originally were accepting both properties and attributes in the
+ // same object, but that doesn't work so well.
+
+ if (propName.indexOf('aria-') !== -1 || propName === 'role' || propName === 'type') {
+ log.warn('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 " + propName + " to " + val + "."));
+ el.setAttribute(propName, val); // Handle textContent since it's not supported everywhere and we have a
+ // method for it.
+ } else if (propName === 'textContent') {
+ textContent(el, val);
+ } else if (el[propName] !== val) {
+ el[propName] = val;
+ }
+ });
+ Object.getOwnPropertyNames(attributes).forEach(function (attrName) {
+ el.setAttribute(attrName, attributes[attrName]);
+ });
+
+ if (content) {
+ appendContent(el, content);
+ }
+
+ return el;
+}
+/**
+ * Injects text into an element, replacing any existing contents entirely.
+ *
+ * @param {Element} el
+ * The element to add text content into
+ *
+ * @param {string} text
+ * The text content to add.
+ *
+ * @return {Element}
+ * The element with added text content.
+ */
+
+function textContent(el, text) {
+ if (typeof el.textContent === 'undefined') {
+ el.innerText = text;
+ } else {
+ el.textContent = text;
+ }
+
+ return el;
+}
+/**
+ * Insert an element as the first child node of another
+ *
+ * @param {Element} child
+ * Element to insert
+ *
+ * @param {Element} parent
+ * Element to insert child into
+ */
+
+function prependTo(child, parent) {
+ if (parent.firstChild) {
+ parent.insertBefore(child, parent.firstChild);
+ } else {
+ parent.appendChild(child);
+ }
+}
+/**
+ * Check if an element has a class name.
+ *
+ * @param {Element} element
+ * Element to check
+ *
+ * @param {string} classToCheck
+ * Class name to check for
+ *
+ * @return {boolean}
+ * Will be `true` if the element has a class, `false` otherwise.
+ *
+ * @throws {Error}
+ * Throws an error if `classToCheck` has white space.
+ */
+
+function hasClass(element, classToCheck) {
+ throwIfWhitespace(classToCheck);
+
+ if (element.classList) {
+ return element.classList.contains(classToCheck);
+ }
+
+ return classRegExp(classToCheck).test(element.className);
+}
+/**
+ * Add a class name to an element.
+ *
+ * @param {Element} element
+ * Element to add class name to.
+ *
+ * @param {string} classToAdd
+ * Class name to add.
+ *
+ * @return {Element}
+ * The DOM element with the added class name.
+ */
+
+function addClass(element, classToAdd) {
+ if (element.classList) {
+ element.classList.add(classToAdd); // Don't need to `throwIfWhitespace` here because `hasElClass` will do it
+ // in the case of classList not being supported.
+ } else if (!hasClass(element, classToAdd)) {
+ element.className = (element.className + ' ' + classToAdd).trim();
+ }
+
+ return element;
+}
+/**
+ * Remove a class name from an element.
+ *
+ * @param {Element} element
+ * Element to remove a class name from.
+ *
+ * @param {string} classToRemove
+ * Class name to remove
+ *
+ * @return {Element}
+ * The DOM element with class name removed.
+ */
+
+function removeClass(element, classToRemove) {
+ if (element.classList) {
+ element.classList.remove(classToRemove);
+ } else {
+ throwIfWhitespace(classToRemove);
+ element.className = element.className.split(/\s+/).filter(function (c) {
+ return c !== classToRemove;
+ }).join(' ');
+ }
+
+ return element;
+}
+/**
+ * The callback definition for toggleClass.
+ *
+ * @callback module:dom~PredicateCallback
+ * @param {Element} element
+ * The DOM element of the Component.
+ *
+ * @param {string} classToToggle
+ * The `className` that wants to be toggled
+ *
+ * @return {boolean|undefined}
+ * If `true` is returned, the `classToToggle` will be added to the
+ * `element`. If `false`, the `classToToggle` will be removed from
+ * the `element`. If `undefined`, the callback will be ignored.
+ */
+
+/**
+ * Adds or removes a class name to/from an element depending on an optional
+ * condition or the presence/absence of the class name.
+ *
+ * @param {Element} element
+ * The element to toggle a class name on.
+ *
+ * @param {string} classToToggle
+ * The class that should be toggled.
+ *
+ * @param {boolean|module:dom~PredicateCallback} [predicate]
+ * See the return value for {@link module:dom~PredicateCallback}
+ *
+ * @return {Element}
+ * The element with a class that has been toggled.
+ */
+
+function toggleClass(element, classToToggle, predicate) {
+ // This CANNOT use `classList` internally because IE11 does not support the
+ // second parameter to the `classList.toggle()` method! Which is fine because
+ // `classList` will be used by the add/remove functions.
+ var has = hasClass(element, classToToggle);
+
+ if (typeof predicate === 'function') {
+ predicate = predicate(element, classToToggle);
+ }
+
+ if (typeof predicate !== 'boolean') {
+ predicate = !has;
+ } // If the necessary class operation matches the current state of the
+ // element, no action is required.
+
+
+ if (predicate === has) {
+ return;
+ }
+
+ if (predicate) {
+ addClass(element, classToToggle);
+ } else {
+ removeClass(element, classToToggle);
+ }
+
+ return element;
+}
+/**
+ * Apply attributes to an HTML element.
+ *
+ * @param {Element} el
+ * Element to add attributes to.
+ *
+ * @param {Object} [attributes]
+ * Attributes to be applied.
+ */
+
+function setAttributes(el, attributes) {
+ Object.getOwnPropertyNames(attributes).forEach(function (attrName) {
+ var attrValue = attributes[attrName];
+
+ if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) {
+ el.removeAttribute(attrName);
+ } else {
+ el.setAttribute(attrName, attrValue === true ? '' : attrValue);
+ }
+ });
+}
+/**
+ * Get an element's attribute values, as defined on the HTML tag.
+ *
+ * Attributes are not the same as properties. They're defined on the tag
+ * or with setAttribute.
+ *
+ * @param {Element} tag
+ * Element from which to get tag attributes.
+ *
+ * @return {Object}
+ * All attributes of the element. Boolean attributes will be `true` or
+ * `false`, others will be strings.
+ */
+
+function getAttributes(tag) {
+ var obj = {}; // known boolean attributes
+ // we can check for matching boolean properties, but not all browsers
+ // and not all tags know about these attributes, so, we still want to check them manually
+
+ var knownBooleans = ',' + 'autoplay,controls,playsinline,loop,muted,default,defaultMuted' + ',';
+
+ if (tag && tag.attributes && tag.attributes.length > 0) {
+ var attrs = tag.attributes;
+
+ for (var i = attrs.length - 1; i >= 0; i--) {
+ var attrName = attrs[i].name;
+ var attrVal = attrs[i].value; // check for known booleans
+ // the matching element property will return a value for typeof
+
+ if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(',' + attrName + ',') !== -1) {
+ // the value of an included boolean attribute is typically an empty
+ // string ('') which would equal false if we just check for a false value.
+ // we also don't want support bad code like autoplay='false'
+ attrVal = attrVal !== null ? true : false;
+ }
+
+ obj[attrName] = attrVal;
+ }
+ }
+
+ return obj;
+}
+/**
+ * Get the value of an element's attribute.
+ *
+ * @param {Element} el
+ * A DOM element.
+ *
+ * @param {string} attribute
+ * Attribute to get the value of.
+ *
+ * @return {string}
+ * The value of the attribute.
+ */
+
+function getAttribute(el, attribute) {
+ return el.getAttribute(attribute);
+}
+/**
+ * Set the value of an element's attribute.
+ *
+ * @param {Element} el
+ * A DOM element.
+ *
+ * @param {string} attribute
+ * Attribute to set.
+ *
+ * @param {string} value
+ * Value to set the attribute to.
+ */
+
+function setAttribute(el, attribute, value) {
+ el.setAttribute(attribute, value);
+}
+/**
+ * Remove an element's attribute.
+ *
+ * @param {Element} el
+ * A DOM element.
+ *
+ * @param {string} attribute
+ * Attribute to remove.
+ */
+
+function removeAttribute(el, attribute) {
+ el.removeAttribute(attribute);
+}
+/**
+ * Attempt to block the ability to select text.
+ */
+
+function blockTextSelection() {
+ global_document__WEBPACK_IMPORTED_MODULE_1___default().body.focus();
+
+ (global_document__WEBPACK_IMPORTED_MODULE_1___default().onselectstart) = function () {
+ return false;
+ };
+}
+/**
+ * Turn off text selection blocking.
+ */
+
+function unblockTextSelection() {
+ (global_document__WEBPACK_IMPORTED_MODULE_1___default().onselectstart) = function () {
+ return true;
+ };
+}
+/**
+ * Identical to the native `getBoundingClientRect` function, but ensures that
+ * the method is supported at all (it is in all browsers we claim to support)
+ * and that the element is in the DOM before continuing.
+ *
+ * This wrapper function also shims properties which are not provided by some
+ * older browsers (namely, IE8).
+ *
+ * Additionally, some browsers do not support adding properties to a
+ * `ClientRect`/`DOMRect` object; so, we shallow-copy it with the standard
+ * properties (except `x` and `y` which are not widely supported). This helps
+ * avoid implementations where keys are non-enumerable.
+ *
+ * @param {Element} el
+ * Element whose `ClientRect` we want to calculate.
+ *
+ * @return {Object|undefined}
+ * Always returns a plain object - or `undefined` if it cannot.
+ */
+
+function getBoundingClientRect(el) {
+ if (el && el.getBoundingClientRect && el.parentNode) {
+ var rect = el.getBoundingClientRect();
+ var result = {};
+ ['bottom', 'height', 'left', 'right', 'top', 'width'].forEach(function (k) {
+ if (rect[k] !== undefined) {
+ result[k] = rect[k];
+ }
+ });
+
+ if (!result.height) {
+ result.height = parseFloat(computedStyle(el, 'height'));
+ }
+
+ if (!result.width) {
+ result.width = parseFloat(computedStyle(el, 'width'));
+ }
+
+ return result;
+ }
+}
+/**
+ * Represents the position of a DOM element on the page.
+ *
+ * @typedef {Object} module:dom~Position
+ *
+ * @property {number} left
+ * Pixels to the left.
+ *
+ * @property {number} top
+ * Pixels from the top.
+ */
+
+/**
+ * Get the position of an element in the DOM.
+ *
+ * Uses `getBoundingClientRect` technique from John Resig.
+ *
+ * @see http://ejohn.org/blog/getboundingclientrect-is-awesome/
+ *
+ * @param {Element} el
+ * Element from which to get offset.
+ *
+ * @return {module:dom~Position}
+ * The position of the element that was passed in.
+ */
+
+function findPosition(el) {
+ if (!el || el && !el.offsetParent) {
+ return {
+ left: 0,
+ top: 0,
+ width: 0,
+ height: 0
+ };
+ }
+
+ var width = el.offsetWidth;
+ var height = el.offsetHeight;
+ var left = 0;
+ var top = 0;
+
+ do {
+ left += el.offsetLeft;
+ top += el.offsetTop;
+ el = el.offsetParent;
+ } while (el);
+
+ return {
+ left: left,
+ top: top,
+ width: width,
+ height: height
+ };
+}
+/**
+ * Represents x and y coordinates for a DOM element or mouse pointer.
+ *
+ * @typedef {Object} module:dom~Coordinates
+ *
+ * @property {number} x
+ * x coordinate in pixels
+ *
+ * @property {number} y
+ * y coordinate in pixels
+ */
+
+/**
+ * Get the pointer position within an element.
+ *
+ * The base on the coordinates are the bottom left of the element.
+ *
+ * @param {Element} el
+ * Element on which to get the pointer position on.
+ *
+ * @param {EventTarget~Event} event
+ * Event object.
+ *
+ * @return {module:dom~Coordinates}
+ * A coordinates object corresponding to the mouse position.
+ *
+ */
+
+function getPointerPosition(el, event) {
+ var position = {};
+ var boxTarget = findPosition(event.target);
+ var box = findPosition(el);
+ var boxW = box.width;
+ var boxH = box.height;
+ var offsetY = event.offsetY - (box.top - boxTarget.top);
+ var offsetX = event.offsetX - (box.left - boxTarget.left);
+
+ if (event.changedTouches) {
+ offsetX = event.changedTouches[0].pageX - box.left;
+ offsetY = event.changedTouches[0].pageY + box.top;
+ }
+
+ position.y = 1 - Math.max(0, Math.min(1, offsetY / boxH));
+ position.x = Math.max(0, Math.min(1, offsetX / boxW));
+ return position;
+}
+/**
+ * Determines, via duck typing, whether or not a value is a text node.
+ *
+ * @param {Mixed} value
+ * Check if this value is a text node.
+ *
+ * @return {boolean}
+ * Will be `true` if the value is a text node, `false` otherwise.
+ */
+
+function isTextNode(value) {
+ return isObject(value) && value.nodeType === 3;
+}
+/**
+ * Empties the contents of an element.
+ *
+ * @param {Element} el
+ * The element to empty children from
+ *
+ * @return {Element}
+ * The element with no children
+ */
+
+function emptyEl(el) {
+ while (el.firstChild) {
+ el.removeChild(el.firstChild);
+ }
+
+ return el;
+}
+/**
+ * This is a mixed value that describes content to be injected into the DOM
+ * via some method. It can be of the following types:
+ *
+ * Type | Description
+ * -----------|-------------
+ * `string` | The value will be normalized into a text node.
+ * `Element` | The value will be accepted as-is.
+ * `TextNode` | The value will be accepted as-is.
+ * `Array` | A one-dimensional array of strings, elements, text nodes, or functions. These functions should return a string, element, or text node (any other return value, like an array, will be ignored).
+ * `Function` | A function, which is expected to return a string, element, text node, or array - any of the other possible values described above. This means that a content descriptor could be a function that returns an array of functions, but those second-level functions must return strings, elements, or text nodes.
+ *
+ * @typedef {string|Element|TextNode|Array|Function} module:dom~ContentDescriptor
+ */
+
+/**
+ * Normalizes content for eventual insertion into the DOM.
+ *
+ * This allows a wide range of content definition methods, but helps protect
+ * from falling into the trap of simply writing to `innerHTML`, which could
+ * be an XSS concern.
+ *
+ * The content for an element can be passed in multiple types and
+ * combinations, whose behavior is as follows:
+ *
+ * @param {module:dom~ContentDescriptor} content
+ * A content descriptor value.
+ *
+ * @return {Array}
+ * All of the content that was passed in, normalized to an array of
+ * elements or text nodes.
+ */
+
+function normalizeContent(content) {
+ // First, invoke content if it is a function. If it produces an array,
+ // that needs to happen before normalization.
+ if (typeof content === 'function') {
+ content = content();
+ } // Next up, normalize to an array, so one or many items can be normalized,
+ // filtered, and returned.
+
+
+ return (Array.isArray(content) ? content : [content]).map(function (value) {
+ // First, invoke value if it is a function to produce a new value,
+ // which will be subsequently normalized to a Node of some kind.
+ if (typeof value === 'function') {
+ value = value();
+ }
+
+ if (isEl(value) || isTextNode(value)) {
+ return value;
+ }
+
+ if (typeof value === 'string' && /\S/.test(value)) {
+ return global_document__WEBPACK_IMPORTED_MODULE_1___default().createTextNode(value);
+ }
+ }).filter(function (value) {
+ return value;
+ });
+}
+/**
+ * Normalizes and appends content to an element.
+ *
+ * @param {Element} el
+ * Element to append normalized content to.
+ *
+ * @param {module:dom~ContentDescriptor} content
+ * A content descriptor value.
+ *
+ * @return {Element}
+ * The element with appended normalized content.
+ */
+
+function appendContent(el, content) {
+ normalizeContent(content).forEach(function (node) {
+ return el.appendChild(node);
+ });
+ return el;
+}
+/**
+ * Normalizes and inserts content into an element; this is identical to
+ * `appendContent()`, except it empties the element first.
+ *
+ * @param {Element} el
+ * Element to insert normalized content into.
+ *
+ * @param {module:dom~ContentDescriptor} content
+ * A content descriptor value.
+ *
+ * @return {Element}
+ * The element with inserted normalized content.
+ */
+
+function insertContent(el, content) {
+ return appendContent(emptyEl(el), content);
+}
+/**
+ * Check if an event was a single left click.
+ *
+ * @param {EventTarget~Event} event
+ * Event object.
+ *
+ * @return {boolean}
+ * Will be `true` if a single left click, `false` otherwise.
+ */
+
+function isSingleLeftClick(event) {
+ // Note: if you create something draggable, be sure to
+ // call it on both `mousedown` and `mousemove` event,
+ // otherwise `mousedown` should be enough for a button
+ if (event.button === undefined && event.buttons === undefined) {
+ // Why do we need `buttons` ?
+ // Because, middle mouse sometimes have this:
+ // e.button === 0 and e.buttons === 4
+ // Furthermore, we want to prevent combination click, something like
+ // HOLD middlemouse then left click, that would be
+ // e.button === 0, e.buttons === 5
+ // just `button` is not gonna work
+ // Alright, then what this block does ?
+ // this is for chrome `simulate mobile devices`
+ // I want to support this as well
+ return true;
+ }
+
+ if (event.button === 0 && event.buttons === undefined) {
+ // Touch screen, sometimes on some specific device, `buttons`
+ // doesn't have anything (safari on ios, blackberry...)
+ return true;
+ } // `mouseup` event on a single left click has
+ // `button` and `buttons` equal to 0
+
+
+ if (event.type === 'mouseup' && event.button === 0 && event.buttons === 0) {
+ return true;
+ }
+
+ if (event.button !== 0 || event.buttons !== 1) {
+ // This is the reason we have those if else block above
+ // if any special case we can catch and let it slide
+ // we do it above, when get to here, this definitely
+ // is-not-left-click
+ return false;
+ }
+
+ return true;
+}
+/**
+ * Finds a single DOM element matching `selector` within the optional
+ * `context` of another DOM element (defaulting to `document`).
+ *
+ * @param {string} selector
+ * A valid CSS selector, which will be passed to `querySelector`.
+ *
+ * @param {Element|String} [context=document]
+ * A DOM element within which to query. Can also be a selector
+ * string in which case the first matching element will be used
+ * as context. If missing (or no element matches selector), falls
+ * back to `document`.
+ *
+ * @return {Element|null}
+ * The element that was found or null.
+ */
+
+var $ = createQuerier('querySelector');
+/**
+ * Finds a all DOM elements matching `selector` within the optional
+ * `context` of another DOM element (defaulting to `document`).
+ *
+ * @param {string} selector
+ * A valid CSS selector, which will be passed to `querySelectorAll`.
+ *
+ * @param {Element|String} [context=document]
+ * A DOM element within which to query. Can also be a selector
+ * string in which case the first matching element will be used
+ * as context. If missing (or no element matches selector), falls
+ * back to `document`.
+ *
+ * @return {NodeList}
+ * A element list of elements that were found. Will be empty if none
+ * were found.
+ *
+ */
+
+var $$ = createQuerier('querySelectorAll');
+
+var Dom = /*#__PURE__*/Object.freeze({
+ __proto__: null,
+ isReal: isReal,
+ isEl: isEl,
+ isInFrame: isInFrame,
+ createEl: createEl,
+ textContent: textContent,
+ prependTo: prependTo,
+ hasClass: hasClass,
+ addClass: addClass,
+ removeClass: removeClass,
+ toggleClass: toggleClass,
+ setAttributes: setAttributes,
+ getAttributes: getAttributes,
+ getAttribute: getAttribute,
+ setAttribute: setAttribute,
+ removeAttribute: removeAttribute,
+ blockTextSelection: blockTextSelection,
+ unblockTextSelection: unblockTextSelection,
+ getBoundingClientRect: getBoundingClientRect,
+ findPosition: findPosition,
+ getPointerPosition: getPointerPosition,
+ isTextNode: isTextNode,
+ emptyEl: emptyEl,
+ normalizeContent: normalizeContent,
+ appendContent: appendContent,
+ insertContent: insertContent,
+ isSingleLeftClick: isSingleLeftClick,
+ $: $,
+ $$: $$
+});
+
+/**
+ * @file setup.js - Functions for setting up a player without
+ * user interaction based on the data-setup `attribute` of the video tag.
+ *
+ * @module setup
+ */
+var _windowLoaded = false;
+var videojs;
+/**
+ * Set up any tags that have a data-setup `attribute` when the player is started.
+ */
+
+var autoSetup = function autoSetup() {
+ // Protect against breakage in non-browser environments and check global autoSetup option.
+ if (!isReal() || videojs.options.autoSetup === false) {
+ return;
+ }
+
+ var vids = Array.prototype.slice.call(global_document__WEBPACK_IMPORTED_MODULE_1___default().getElementsByTagName('video'));
+ var audios = Array.prototype.slice.call(global_document__WEBPACK_IMPORTED_MODULE_1___default().getElementsByTagName('audio'));
+ var divs = Array.prototype.slice.call(global_document__WEBPACK_IMPORTED_MODULE_1___default().getElementsByTagName('video-js'));
+ var mediaEls = vids.concat(audios, divs); // Check if any media elements exist
+
+ if (mediaEls && mediaEls.length > 0) {
+ for (var i = 0, e = mediaEls.length; i < e; i++) {
+ var mediaEl = mediaEls[i]; // Check if element exists, has getAttribute func.
+
+ if (mediaEl && mediaEl.getAttribute) {
+ // Make sure this player hasn't already been set up.
+ if (mediaEl.player === undefined) {
+ var options = mediaEl.getAttribute('data-setup'); // Check if data-setup attr exists.
+ // We only auto-setup if they've added the data-setup attr.
+
+ if (options !== null) {
+ // Create new video.js instance.
+ videojs(mediaEl);
+ }
+ } // If getAttribute isn't defined, we need to wait for the DOM.
+
+ } else {
+ autoSetupTimeout(1);
+ break;
+ }
+ } // No videos were found, so keep looping unless page is finished loading.
+
+ } else if (!_windowLoaded) {
+ autoSetupTimeout(1);
+ }
+};
+/**
+ * Wait until the page is loaded before running autoSetup. This will be called in
+ * autoSetup if `hasLoaded` returns false.
+ *
+ * @param {number} wait
+ * How long to wait in ms
+ *
+ * @param {module:videojs} [vjs]
+ * The videojs library function
+ */
+
+
+function autoSetupTimeout(wait, vjs) {
+ if (vjs) {
+ videojs = vjs;
+ }
+
+ global_window__WEBPACK_IMPORTED_MODULE_0___default().setTimeout(autoSetup, wait);
+}
+/**
+ * Used to set the internal tracking of window loaded state to true.
+ *
+ * @private
+ */
+
+
+function setWindowLoaded() {
+ _windowLoaded = true;
+ global_window__WEBPACK_IMPORTED_MODULE_0___default().removeEventListener('load', setWindowLoaded);
+}
+
+if (isReal()) {
+ if ((global_document__WEBPACK_IMPORTED_MODULE_1___default().readyState) === 'complete') {
+ setWindowLoaded();
+ } else {
+ /**
+ * Listen for the load event on window, and set _windowLoaded to true.
+ *
+ * We use a standard event listener here to avoid incrementing the GUID
+ * before any players are created.
+ *
+ * @listens load
+ */
+ global_window__WEBPACK_IMPORTED_MODULE_0___default().addEventListener('load', setWindowLoaded);
+ }
+}
+
+/**
+ * @file stylesheet.js
+ * @module stylesheet
+ */
+/**
+ * Create a DOM syle element given a className for it.
+ *
+ * @param {string} className
+ * The className to add to the created style element.
+ *
+ * @return {Element}
+ * The element that was created.
+ */
+
+var createStyleElement = function createStyleElement(className) {
+ var style = global_document__WEBPACK_IMPORTED_MODULE_1___default().createElement('style');
+ style.className = className;
+ return style;
+};
+/**
+ * Add text to a DOM element.
+ *
+ * @param {Element} el
+ * The Element to add text content to.
+ *
+ * @param {string} content
+ * The text to add to the element.
+ */
+
+var setTextContent = function setTextContent(el, content) {
+ if (el.styleSheet) {
+ el.styleSheet.cssText = content;
+ } else {
+ el.textContent = content;
+ }
+};
+
+/**
+ * @file guid.js
+ * @module guid
+ */
+// Default value for GUIDs. This allows us to reset the GUID counter in tests.
+//
+// The initial GUID is 3 because some users have come to rely on the first
+// default player ID ending up as `vjs_video_3`.
+//
+// See: https://github.com/videojs/video.js/pull/6216
+var _initialGuid = 3;
+/**
+ * Unique ID for an element or function
+ *
+ * @type {Number}
+ */
+
+var _guid = _initialGuid;
+/**
+ * Get a unique auto-incrementing ID by number that has not been returned before.
+ *
+ * @return {number}
+ * A new unique ID.
+ */
+
+function newGUID() {
+ return _guid++;
+}
+
+/**
+ * @file dom-data.js
+ * @module dom-data
+ */
+var FakeWeakMap;
+
+if (!(global_window__WEBPACK_IMPORTED_MODULE_0___default().WeakMap)) {
+ FakeWeakMap = /*#__PURE__*/function () {
+ function FakeWeakMap() {
+ this.vdata = 'vdata' + Math.floor((global_window__WEBPACK_IMPORTED_MODULE_0___default().performance) && global_window__WEBPACK_IMPORTED_MODULE_0___default().performance.now() || Date.now());
+ this.data = {};
+ }
+
+ var _proto = FakeWeakMap.prototype;
+
+ _proto.set = function set(key, value) {
+ var access = key[this.vdata] || newGUID();
+
+ if (!key[this.vdata]) {
+ key[this.vdata] = access;
+ }
+
+ this.data[access] = value;
+ return this;
+ };
+
+ _proto.get = function get(key) {
+ var access = key[this.vdata]; // we have data, return it
+
+ if (access) {
+ return this.data[access];
+ } // we don't have data, return nothing.
+ // return undefined explicitly as that's the contract for this method
+
+
+ log('We have no data for this element', key);
+ return undefined;
+ };
+
+ _proto.has = function has(key) {
+ var access = key[this.vdata];
+ return access in this.data;
+ };
+
+ _proto["delete"] = function _delete(key) {
+ var access = key[this.vdata];
+
+ if (access) {
+ delete this.data[access];
+ delete key[this.vdata];
+ }
+ };
+
+ return FakeWeakMap;
+ }();
+}
+/**
+ * Element Data Store.
+ *
+ * Allows for binding data to an element without putting it directly on the
+ * element. Ex. Event listeners are stored here.
+ * (also from jsninja.com, slightly modified and updated for closure compiler)
+ *
+ * @type {Object}
+ * @private
+ */
+
+
+var DomData = (global_window__WEBPACK_IMPORTED_MODULE_0___default().WeakMap) ? new WeakMap() : new FakeWeakMap();
+
+/**
+ * @file events.js. An Event System (John Resig - Secrets of a JS Ninja http://jsninja.com/)
+ * (Original book version wasn't completely usable, so fixed some things and made Closure Compiler compatible)
+ * This should work very similarly to jQuery's events, however it's based off the book version which isn't as
+ * robust as jquery's, so there's probably some differences.
+ *
+ * @file events.js
+ * @module events
+ */
+/**
+ * Clean up the listener cache and dispatchers
+ *
+ * @param {Element|Object} elem
+ * Element to clean up
+ *
+ * @param {string} type
+ * Type of event to clean up
+ */
+
+function _cleanUpEvents(elem, type) {
+ if (!DomData.has(elem)) {
+ return;
+ }
+
+ var data = DomData.get(elem); // Remove the events of a particular type if there are none left
+
+ if (data.handlers[type].length === 0) {
+ delete data.handlers[type]; // data.handlers[type] = null;
+ // Setting to null was causing an error with data.handlers
+ // Remove the meta-handler from the element
+
+ if (elem.removeEventListener) {
+ elem.removeEventListener(type, data.dispatcher, false);
+ } else if (elem.detachEvent) {
+ elem.detachEvent('on' + type, data.dispatcher);
+ }
+ } // Remove the events object if there are no types left
+
+
+ if (Object.getOwnPropertyNames(data.handlers).length <= 0) {
+ delete data.handlers;
+ delete data.dispatcher;
+ delete data.disabled;
+ } // Finally remove the element data if there is no data left
+
+
+ if (Object.getOwnPropertyNames(data).length === 0) {
+ DomData["delete"](elem);
+ }
+}
+/**
+ * Loops through an array of event types and calls the requested method for each type.
+ *
+ * @param {Function} fn
+ * The event method we want to use.
+ *
+ * @param {Element|Object} elem
+ * Element or object to bind listeners to
+ *
+ * @param {string} type
+ * Type of event to bind to.
+ *
+ * @param {EventTarget~EventListener} callback
+ * Event listener.
+ */
+
+
+function _handleMultipleEvents(fn, elem, types, callback) {
+ types.forEach(function (type) {
+ // Call the event method for each one of the types
+ fn(elem, type, callback);
+ });
+}
+/**
+ * Fix a native event to have standard property values
+ *
+ * @param {Object} event
+ * Event object to fix.
+ *
+ * @return {Object}
+ * Fixed event object.
+ */
+
+
+function fixEvent(event) {
+ if (event.fixed_) {
+ return event;
+ }
+
+ function returnTrue() {
+ return true;
+ }
+
+ function returnFalse() {
+ return false;
+ } // Test if fixing up is needed
+ // Used to check if !event.stopPropagation instead of isPropagationStopped
+ // But native events return true for stopPropagation, but don't have
+ // other expected methods like isPropagationStopped. Seems to be a problem
+ // with the Javascript Ninja code. So we're just overriding all events now.
+
+
+ if (!event || !event.isPropagationStopped) {
+ var old = event || (global_window__WEBPACK_IMPORTED_MODULE_0___default().event);
+ event = {}; // Clone the old object so that we can modify the values event = {};
+ // IE8 Doesn't like when you mess with native event properties
+ // Firefox returns false for event.hasOwnProperty('type') and other props
+ // which makes copying more difficult.
+ // TODO: Probably best to create a whitelist of event props
+
+ for (var key in old) {
+ // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y
+ // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation
+ // and webkitMovementX/Y
+ if (key !== 'layerX' && key !== 'layerY' && key !== 'keyLocation' && key !== 'webkitMovementX' && key !== 'webkitMovementY') {
+ // Chrome 32+ warns if you try to copy deprecated returnValue, but
+ // we still want to if preventDefault isn't supported (IE8).
+ if (!(key === 'returnValue' && old.preventDefault)) {
+ event[key] = old[key];
+ }
+ }
+ } // The event occurred on this element
+
+
+ if (!event.target) {
+ event.target = event.srcElement || (global_document__WEBPACK_IMPORTED_MODULE_1___default());
+ } // Handle which other element the event is related to
+
+
+ if (!event.relatedTarget) {
+ event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
+ } // Stop the default browser action
+
+
+ event.preventDefault = function () {
+ if (old.preventDefault) {
+ old.preventDefault();
+ }
+
+ event.returnValue = false;
+ old.returnValue = false;
+ event.defaultPrevented = true;
+ };
+
+ event.defaultPrevented = false; // Stop the event from bubbling
+
+ event.stopPropagation = function () {
+ if (old.stopPropagation) {
+ old.stopPropagation();
+ }
+
+ event.cancelBubble = true;
+ old.cancelBubble = true;
+ event.isPropagationStopped = returnTrue;
+ };
+
+ event.isPropagationStopped = returnFalse; // Stop the event from bubbling and executing other handlers
+
+ event.stopImmediatePropagation = function () {
+ if (old.stopImmediatePropagation) {
+ old.stopImmediatePropagation();
+ }
+
+ event.isImmediatePropagationStopped = returnTrue;
+ event.stopPropagation();
+ };
+
+ event.isImmediatePropagationStopped = returnFalse; // Handle mouse position
+
+ if (event.clientX !== null && event.clientX !== undefined) {
+ var doc = (global_document__WEBPACK_IMPORTED_MODULE_1___default().documentElement);
+ var body = (global_document__WEBPACK_IMPORTED_MODULE_1___default().body);
+ event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
+ event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
+ } // Handle key presses
+
+
+ event.which = event.charCode || event.keyCode; // Fix button for mouse clicks:
+ // 0 == left; 1 == middle; 2 == right
+
+ if (event.button !== null && event.button !== undefined) {
+ // The following is disabled because it does not pass videojs-standard
+ // and... yikes.
+
+ /* eslint-disable */
+ event.button = event.button & 1 ? 0 : event.button & 4 ? 1 : event.button & 2 ? 2 : 0;
+ /* eslint-enable */
+ }
+ }
+
+ event.fixed_ = true; // Returns fixed-up instance
+
+ return event;
+}
+/**
+ * Whether passive event listeners are supported
+ */
+
+var _supportsPassive;
+
+var supportsPassive = function supportsPassive() {
+ if (typeof _supportsPassive !== 'boolean') {
+ _supportsPassive = false;
+
+ try {
+ var opts = Object.defineProperty({}, 'passive', {
+ get: function get() {
+ _supportsPassive = true;
+ }
+ });
+ global_window__WEBPACK_IMPORTED_MODULE_0___default().addEventListener('test', null, opts);
+ global_window__WEBPACK_IMPORTED_MODULE_0___default().removeEventListener('test', null, opts);
+ } catch (e) {// disregard
+ }
+ }
+
+ return _supportsPassive;
+};
+/**
+ * Touch events Chrome expects to be passive
+ */
+
+
+var passiveEvents = ['touchstart', 'touchmove'];
+/**
+ * Add an event listener to element
+ * It stores the handler function in a separate cache object
+ * and adds a generic handler to the element's event,
+ * along with a unique id (guid) to the element.
+ *
+ * @param {Element|Object} elem
+ * Element or object to bind listeners to
+ *
+ * @param {string|string[]} type
+ * Type of event to bind to.
+ *
+ * @param {EventTarget~EventListener} fn
+ * Event listener.
+ */
+
+function on(elem, type, fn) {
+ if (Array.isArray(type)) {
+ return _handleMultipleEvents(on, elem, type, fn);
+ }
+
+ if (!DomData.has(elem)) {
+ DomData.set(elem, {});
+ }
+
+ var data = DomData.get(elem); // We need a place to store all our handler data
+
+ if (!data.handlers) {
+ data.handlers = {};
+ }
+
+ if (!data.handlers[type]) {
+ data.handlers[type] = [];
+ }
+
+ if (!fn.guid) {
+ fn.guid = newGUID();
+ }
+
+ data.handlers[type].push(fn);
+
+ if (!data.dispatcher) {
+ data.disabled = false;
+
+ data.dispatcher = function (event, hash) {
+ if (data.disabled) {
+ return;
+ }
+
+ event = fixEvent(event);
+ var handlers = data.handlers[event.type];
+
+ if (handlers) {
+ // Copy handlers so if handlers are added/removed during the process it doesn't throw everything off.
+ var handlersCopy = handlers.slice(0);
+
+ for (var m = 0, n = handlersCopy.length; m < n; m++) {
+ if (event.isImmediatePropagationStopped()) {
+ break;
+ } else {
+ try {
+ handlersCopy[m].call(elem, event, hash);
+ } catch (e) {
+ log.error(e);
+ }
+ }
+ }
+ }
+ };
+ }
+
+ if (data.handlers[type].length === 1) {
+ if (elem.addEventListener) {
+ var options = false;
+
+ if (supportsPassive() && passiveEvents.indexOf(type) > -1) {
+ options = {
+ passive: true
+ };
+ }
+
+ elem.addEventListener(type, data.dispatcher, options);
+ } else if (elem.attachEvent) {
+ elem.attachEvent('on' + type, data.dispatcher);
+ }
+ }
+}
+/**
+ * Removes event listeners from an element
+ *
+ * @param {Element|Object} elem
+ * Object to remove listeners from.
+ *
+ * @param {string|string[]} [type]
+ * Type of listener to remove. Don't include to remove all events from element.
+ *
+ * @param {EventTarget~EventListener} [fn]
+ * Specific listener to remove. Don't include to remove listeners for an event
+ * type.
+ */
+
+function off(elem, type, fn) {
+ // Don't want to add a cache object through getElData if not needed
+ if (!DomData.has(elem)) {
+ return;
+ }
+
+ var data = DomData.get(elem); // If no events exist, nothing to unbind
+
+ if (!data.handlers) {
+ return;
+ }
+
+ if (Array.isArray(type)) {
+ return _handleMultipleEvents(off, elem, type, fn);
+ } // Utility function
+
+
+ var removeType = function removeType(el, t) {
+ data.handlers[t] = [];
+
+ _cleanUpEvents(el, t);
+ }; // Are we removing all bound events?
+
+
+ if (type === undefined) {
+ for (var t in data.handlers) {
+ if (Object.prototype.hasOwnProperty.call(data.handlers || {}, t)) {
+ removeType(elem, t);
+ }
+ }
+
+ return;
+ }
+
+ var handlers = data.handlers[type]; // If no handlers exist, nothing to unbind
+
+ if (!handlers) {
+ return;
+ } // If no listener was provided, remove all listeners for type
+
+
+ if (!fn) {
+ removeType(elem, type);
+ return;
+ } // We're only removing a single handler
+
+
+ if (fn.guid) {
+ for (var n = 0; n < handlers.length; n++) {
+ if (handlers[n].guid === fn.guid) {
+ handlers.splice(n--, 1);
+ }
+ }
+ }
+
+ _cleanUpEvents(elem, type);
+}
+/**
+ * Trigger an event for an element
+ *
+ * @param {Element|Object} elem
+ * Element to trigger an event on
+ *
+ * @param {EventTarget~Event|string} event
+ * A string (the type) or an event object with a type attribute
+ *
+ * @param {Object} [hash]
+ * data hash to pass along with the event
+ *
+ * @return {boolean|undefined}
+ * Returns the opposite of `defaultPrevented` if default was
+ * prevented. Otherwise, returns `undefined`
+ */
+
+function trigger(elem, event, hash) {
+ // Fetches element data and a reference to the parent (for bubbling).
+ // Don't want to add a data object to cache for every parent,
+ // so checking hasElData first.
+ var elemData = DomData.has(elem) ? DomData.get(elem) : {};
+ var parent = elem.parentNode || elem.ownerDocument; // type = event.type || event,
+ // handler;
+ // If an event name was passed as a string, creates an event out of it
+
+ if (typeof event === 'string') {
+ event = {
+ type: event,
+ target: elem
+ };
+ } else if (!event.target) {
+ event.target = elem;
+ } // Normalizes the event properties.
+
+
+ event = fixEvent(event); // If the passed element has a dispatcher, executes the established handlers.
+
+ if (elemData.dispatcher) {
+ elemData.dispatcher.call(elem, event, hash);
+ } // Unless explicitly stopped or the event does not bubble (e.g. media events)
+ // recursively calls this function to bubble the event up the DOM.
+
+
+ if (parent && !event.isPropagationStopped() && event.bubbles === true) {
+ trigger.call(null, parent, event, hash); // If at the top of the DOM, triggers the default action unless disabled.
+ } else if (!parent && !event.defaultPrevented && event.target && event.target[event.type]) {
+ if (!DomData.has(event.target)) {
+ DomData.set(event.target, {});
+ }
+
+ var targetData = DomData.get(event.target); // Checks if the target has a default action for this event.
+
+ if (event.target[event.type]) {
+ // Temporarily disables event dispatching on the target as we have already executed the handler.
+ targetData.disabled = true; // Executes the default action.
+
+ if (typeof event.target[event.type] === 'function') {
+ event.target[event.type]();
+ } // Re-enables event dispatching.
+
+
+ targetData.disabled = false;
+ }
+ } // Inform the triggerer if the default was prevented by returning false
+
+
+ return !event.defaultPrevented;
+}
+/**
+ * Trigger a listener only once for an event.
+ *
+ * @param {Element|Object} elem
+ * Element or object to bind to.
+ *
+ * @param {string|string[]} type
+ * Name/type of event
+ *
+ * @param {Event~EventListener} fn
+ * Event listener function
+ */
+
+function one(elem, type, fn) {
+ if (Array.isArray(type)) {
+ return _handleMultipleEvents(one, elem, type, fn);
+ }
+
+ var func = function func() {
+ off(elem, type, func);
+ fn.apply(this, arguments);
+ }; // copy the guid to the new function so it can removed using the original function's ID
+
+
+ func.guid = fn.guid = fn.guid || newGUID();
+ on(elem, type, func);
+}
+/**
+ * Trigger a listener only once and then turn if off for all
+ * configured events
+ *
+ * @param {Element|Object} elem
+ * Element or object to bind to.
+ *
+ * @param {string|string[]} type
+ * Name/type of event
+ *
+ * @param {Event~EventListener} fn
+ * Event listener function
+ */
+
+function any(elem, type, fn) {
+ var func = function func() {
+ off(elem, type, func);
+ fn.apply(this, arguments);
+ }; // copy the guid to the new function so it can removed using the original function's ID
+
+
+ func.guid = fn.guid = fn.guid || newGUID(); // multiple ons, but one off for everything
+
+ on(elem, type, func);
+}
+
+var Events = /*#__PURE__*/Object.freeze({
+ __proto__: null,
+ fixEvent: fixEvent,
+ on: on,
+ off: off,
+ trigger: trigger,
+ one: one,
+ any: any
+});
+
+/**
+ * @file fn.js
+ * @module fn
+ */
+var UPDATE_REFRESH_INTERVAL = 30;
+/**
+ * Bind (a.k.a proxy or context). A simple method for changing the context of
+ * a function.
+ *
+ * It also stores a unique id on the function so it can be easily removed from
+ * events.
+ *
+ * @function
+ * @param {Mixed} context
+ * The object to bind as scope.
+ *
+ * @param {Function} fn
+ * The function to be bound to a scope.
+ *
+ * @param {number} [uid]
+ * An optional unique ID for the function to be set
+ *
+ * @return {Function}
+ * The new function that will be bound into the context given
+ */
+
+var bind = function bind(context, fn, uid) {
+ // Make sure the function has a unique ID
+ if (!fn.guid) {
+ fn.guid = newGUID();
+ } // Create the new function that changes the context
+
+
+ var bound = fn.bind(context); // Allow for the ability to individualize this function
+ // Needed in the case where multiple objects might share the same prototype
+ // IF both items add an event listener with the same function, then you try to remove just one
+ // it will remove both because they both have the same guid.
+ // when using this, you need to use the bind method when you remove the listener as well.
+ // currently used in text tracks
+
+ bound.guid = uid ? uid + '_' + fn.guid : fn.guid;
+ return bound;
+};
+/**
+ * Wraps the given function, `fn`, with a new function that only invokes `fn`
+ * at most once per every `wait` milliseconds.
+ *
+ * @function
+ * @param {Function} fn
+ * The function to be throttled.
+ *
+ * @param {number} wait
+ * The number of milliseconds by which to throttle.
+ *
+ * @return {Function}
+ */
+
+var throttle = function throttle(fn, wait) {
+ var last = global_window__WEBPACK_IMPORTED_MODULE_0___default().performance.now();
+
+ var throttled = function throttled() {
+ var now = global_window__WEBPACK_IMPORTED_MODULE_0___default().performance.now();
+
+ if (now - last >= wait) {
+ fn.apply(void 0, arguments);
+ last = now;
+ }
+ };
+
+ return throttled;
+};
+/**
+ * Creates a debounced function that delays invoking `func` until after `wait`
+ * milliseconds have elapsed since the last time the debounced function was
+ * invoked.
+ *
+ * Inspired by lodash and underscore implementations.
+ *
+ * @function
+ * @param {Function} func
+ * The function to wrap with debounce behavior.
+ *
+ * @param {number} wait
+ * The number of milliseconds to wait after the last invocation.
+ *
+ * @param {boolean} [immediate]
+ * Whether or not to invoke the function immediately upon creation.
+ *
+ * @param {Object} [context=window]
+ * The "context" in which the debounced function should debounce. For
+ * example, if this function should be tied to a Video.js player,
+ * the player can be passed here. Alternatively, defaults to the
+ * global `window` object.
+ *
+ * @return {Function}
+ * A debounced function.
+ */
+
+var debounce = function debounce(func, wait, immediate, context) {
+ if (context === void 0) {
+ context = (global_window__WEBPACK_IMPORTED_MODULE_0___default());
+ }
+
+ var timeout;
+
+ var cancel = function cancel() {
+ context.clearTimeout(timeout);
+ timeout = null;
+ };
+ /* eslint-disable consistent-this */
+
+
+ var debounced = function debounced() {
+ var self = this;
+ var args = arguments;
+
+ var _later = function later() {
+ timeout = null;
+ _later = null;
+
+ if (!immediate) {
+ func.apply(self, args);
+ }
+ };
+
+ if (!timeout && immediate) {
+ func.apply(self, args);
+ }
+
+ context.clearTimeout(timeout);
+ timeout = context.setTimeout(_later, wait);
+ };
+ /* eslint-enable consistent-this */
+
+
+ debounced.cancel = cancel;
+ return debounced;
+};
+
+/**
+ * @file src/js/event-target.js
+ */
+/**
+ * `EventTarget` is a class that can have the same API as the DOM `EventTarget`. It
+ * adds shorthand functions that wrap around lengthy functions. For example:
+ * the `on` function is a wrapper around `addEventListener`.
+ *
+ * @see [EventTarget Spec]{@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget}
+ * @class EventTarget
+ */
+
+var EventTarget = function EventTarget() {};
+/**
+ * A Custom DOM event.
+ *
+ * @typedef {Object} EventTarget~Event
+ * @see [Properties]{@link https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent}
+ */
+
+/**
+ * All event listeners should follow the following format.
+ *
+ * @callback EventTarget~EventListener
+ * @this {EventTarget}
+ *
+ * @param {EventTarget~Event} event
+ * the event that triggered this function
+ *
+ * @param {Object} [hash]
+ * hash of data sent during the event
+ */
+
+/**
+ * An object containing event names as keys and booleans as values.
+ *
+ * > NOTE: If an event name is set to a true value here {@link EventTarget#trigger}
+ * will have extra functionality. See that function for more information.
+ *
+ * @property EventTarget.prototype.allowedEvents_
+ * @private
+ */
+
+
+EventTarget.prototype.allowedEvents_ = {};
+/**
+ * Adds an `event listener` to an instance of an `EventTarget`. An `event listener` is a
+ * function that will get called when an event with a certain name gets triggered.
+ *
+ * @param {string|string[]} type
+ * An event name or an array of event names.
+ *
+ * @param {EventTarget~EventListener} fn
+ * The function to call with `EventTarget`s
+ */
+
+EventTarget.prototype.on = function (type, fn) {
+ // Remove the addEventListener alias before calling Events.on
+ // so we don't get into an infinite type loop
+ var ael = this.addEventListener;
+
+ this.addEventListener = function () {};
+
+ on(this, type, fn);
+ this.addEventListener = ael;
+};
+/**
+ * An alias of {@link EventTarget#on}. Allows `EventTarget` to mimic
+ * the standard DOM API.
+ *
+ * @function
+ * @see {@link EventTarget#on}
+ */
+
+
+EventTarget.prototype.addEventListener = EventTarget.prototype.on;
+/**
+ * Removes an `event listener` for a specific event from an instance of `EventTarget`.
+ * This makes it so that the `event listener` will no longer get called when the
+ * named event happens.
+ *
+ * @param {string|string[]} type
+ * An event name or an array of event names.
+ *
+ * @param {EventTarget~EventListener} fn
+ * The function to remove.
+ */
+
+EventTarget.prototype.off = function (type, fn) {
+ off(this, type, fn);
+};
+/**
+ * An alias of {@link EventTarget#off}. Allows `EventTarget` to mimic
+ * the standard DOM API.
+ *
+ * @function
+ * @see {@link EventTarget#off}
+ */
+
+
+EventTarget.prototype.removeEventListener = EventTarget.prototype.off;
+/**
+ * This function will add an `event listener` that gets triggered only once. After the
+ * first trigger it will get removed. This is like adding an `event listener`
+ * with {@link EventTarget#on} that calls {@link EventTarget#off} on itself.
+ *
+ * @param {string|string[]} type
+ * An event name or an array of event names.
+ *
+ * @param {EventTarget~EventListener} fn
+ * The function to be called once for each event name.
+ */
+
+EventTarget.prototype.one = function (type, fn) {
+ // Remove the addEventListener aliasing Events.on
+ // so we don't get into an infinite type loop
+ var ael = this.addEventListener;
+
+ this.addEventListener = function () {};
+
+ one(this, type, fn);
+ this.addEventListener = ael;
+};
+
+EventTarget.prototype.any = function (type, fn) {
+ // Remove the addEventListener aliasing Events.on
+ // so we don't get into an infinite type loop
+ var ael = this.addEventListener;
+
+ this.addEventListener = function () {};
+
+ any(this, type, fn);
+ this.addEventListener = ael;
+};
+/**
+ * This function causes an event to happen. This will then cause any `event listeners`
+ * that are waiting for that event, to get called. If there are no `event listeners`
+ * for an event then nothing will happen.
+ *
+ * If the name of the `Event` that is being triggered is in `EventTarget.allowedEvents_`.
+ * Trigger will also call the `on` + `uppercaseEventName` function.
+ *
+ * Example:
+ * 'click' is in `EventTarget.allowedEvents_`, so, trigger will attempt to call
+ * `onClick` if it exists.
+ *
+ * @param {string|EventTarget~Event|Object} event
+ * The name of the event, an `Event`, or an object with a key of type set to
+ * an event name.
+ */
+
+
+EventTarget.prototype.trigger = function (event) {
+ var type = event.type || event; // deprecation
+ // In a future version we should default target to `this`
+ // similar to how we default the target to `elem` in
+ // `Events.trigger`. Right now the default `target` will be
+ // `document` due to the `Event.fixEvent` call.
+
+ if (typeof event === 'string') {
+ event = {
+ type: type
+ };
+ }
+
+ event = fixEvent(event);
+
+ if (this.allowedEvents_[type] && this['on' + type]) {
+ this['on' + type](event);
+ }
+
+ trigger(this, event);
+};
+/**
+ * An alias of {@link EventTarget#trigger}. Allows `EventTarget` to mimic
+ * the standard DOM API.
+ *
+ * @function
+ * @see {@link EventTarget#trigger}
+ */
+
+
+EventTarget.prototype.dispatchEvent = EventTarget.prototype.trigger;
+var EVENT_MAP;
+
+EventTarget.prototype.queueTrigger = function (event) {
+ var _this = this;
+
+ // only set up EVENT_MAP if it'll be used
+ if (!EVENT_MAP) {
+ EVENT_MAP = new Map();
+ }
+
+ var type = event.type || event;
+ var map = EVENT_MAP.get(this);
+
+ if (!map) {
+ map = new Map();
+ EVENT_MAP.set(this, map);
+ }
+
+ var oldTimeout = map.get(type);
+ map["delete"](type);
+ global_window__WEBPACK_IMPORTED_MODULE_0___default().clearTimeout(oldTimeout);
+ var timeout = global_window__WEBPACK_IMPORTED_MODULE_0___default().setTimeout(function () {
+ // if we cleared out all timeouts for the current target, delete its map
+ if (map.size === 0) {
+ map = null;
+ EVENT_MAP["delete"](_this);
+ }
+
+ _this.trigger(event);
+ }, 0);
+ map.set(type, timeout);
+};
+
+/**
+ * @file mixins/evented.js
+ * @module evented
+ */
+/**
+ * Returns whether or not an object has had the evented mixin applied.
+ *
+ * @param {Object} object
+ * An object to test.
+ *
+ * @return {boolean}
+ * Whether or not the object appears to be evented.
+ */
+
+var isEvented = function isEvented(object) {
+ return object instanceof EventTarget || !!object.eventBusEl_ && ['on', 'one', 'off', 'trigger'].every(function (k) {
+ return typeof object[k] === 'function';
+ });
+};
+/**
+ * Adds a callback to run after the evented mixin applied.
+ *
+ * @param {Object} object
+ * An object to Add
+ * @param {Function} callback
+ * The callback to run.
+ */
+
+
+var addEventedCallback = function addEventedCallback(target, callback) {
+ if (isEvented(target)) {
+ callback();
+ } else {
+ if (!target.eventedCallbacks) {
+ target.eventedCallbacks = [];
+ }
+
+ target.eventedCallbacks.push(callback);
+ }
+};
+/**
+ * Whether a value is a valid event type - non-empty string or array.
+ *
+ * @private
+ * @param {string|Array} type
+ * The type value to test.
+ *
+ * @return {boolean}
+ * Whether or not the type is a valid event type.
+ */
+
+
+var isValidEventType = function isValidEventType(type) {
+ return (// The regex here verifies that the `type` contains at least one non-
+ // whitespace character.
+ typeof type === 'string' && /\S/.test(type) || Array.isArray(type) && !!type.length
+ );
+};
+/**
+ * Validates a value to determine if it is a valid event target. Throws if not.
+ *
+ * @private
+ * @throws {Error}
+ * If the target does not appear to be a valid event target.
+ *
+ * @param {Object} target
+ * The object to test.
+ */
+
+
+var validateTarget = function validateTarget(target) {
+ if (!target.nodeName && !isEvented(target)) {
+ throw new Error('Invalid target; must be a DOM node or evented object.');
+ }
+};
+/**
+ * Validates a value to determine if it is a valid event target. Throws if not.
+ *
+ * @private
+ * @throws {Error}
+ * If the type does not appear to be a valid event type.
+ *
+ * @param {string|Array} type
+ * The type to test.
+ */
+
+
+var validateEventType = function validateEventType(type) {
+ if (!isValidEventType(type)) {
+ throw new Error('Invalid event type; must be a non-empty string or array.');
+ }
+};
+/**
+ * Validates a value to determine if it is a valid listener. Throws if not.
+ *
+ * @private
+ * @throws {Error}
+ * If the listener is not a function.
+ *
+ * @param {Function} listener
+ * The listener to test.
+ */
+
+
+var validateListener = function validateListener(listener) {
+ if (typeof listener !== 'function') {
+ throw new Error('Invalid listener; must be a function.');
+ }
+};
+/**
+ * Takes an array of arguments given to `on()` or `one()`, validates them, and
+ * normalizes them into an object.
+ *
+ * @private
+ * @param {Object} self
+ * The evented object on which `on()` or `one()` was called. This
+ * object will be bound as the `this` value for the listener.
+ *
+ * @param {Array} args
+ * An array of arguments passed to `on()` or `one()`.
+ *
+ * @return {Object}
+ * An object containing useful values for `on()` or `one()` calls.
+ */
+
+
+var normalizeListenArgs = function normalizeListenArgs(self, args) {
+ // If the number of arguments is less than 3, the target is always the
+ // evented object itself.
+ var isTargetingSelf = args.length < 3 || args[0] === self || args[0] === self.eventBusEl_;
+ var target;
+ var type;
+ var listener;
+
+ if (isTargetingSelf) {
+ target = self.eventBusEl_; // Deal with cases where we got 3 arguments, but we are still listening to
+ // the evented object itself.
+
+ if (args.length >= 3) {
+ args.shift();
+ }
+
+ type = args[0];
+ listener = args[1];
+ } else {
+ target = args[0];
+ type = args[1];
+ listener = args[2];
+ }
+
+ validateTarget(target);
+ validateEventType(type);
+ validateListener(listener);
+ listener = bind(self, listener);
+ return {
+ isTargetingSelf: isTargetingSelf,
+ target: target,
+ type: type,
+ listener: listener
+ };
+};
+/**
+ * Adds the listener to the event type(s) on the target, normalizing for
+ * the type of target.
+ *
+ * @private
+ * @param {Element|Object} target
+ * A DOM node or evented object.
+ *
+ * @param {string} method
+ * The event binding method to use ("on" or "one").
+ *
+ * @param {string|Array} type
+ * One or more event type(s).
+ *
+ * @param {Function} listener
+ * A listener function.
+ */
+
+
+var listen = function listen(target, method, type, listener) {
+ validateTarget(target);
+
+ if (target.nodeName) {
+ Events[method](target, type, listener);
+ } else {
+ target[method](type, listener);
+ }
+};
+/**
+ * Contains methods that provide event capabilities to an object which is passed
+ * to {@link module:evented|evented}.
+ *
+ * @mixin EventedMixin
+ */
+
+
+var EventedMixin = {
+ /**
+ * Add a listener to an event (or events) on this object or another evented
+ * object.
+ *
+ * @param {string|Array|Element|Object} targetOrType
+ * If this is a string or array, it represents the event type(s)
+ * that will trigger the listener.
+ *
+ * Another evented object can be passed here instead, which will
+ * cause the listener to listen for events on _that_ object.
+ *
+ * In either case, the listener's `this` value will be bound to
+ * this object.
+ *
+ * @param {string|Array|Function} typeOrListener
+ * If the first argument was a string or array, this should be the
+ * listener function. Otherwise, this is a string or array of event
+ * type(s).
+ *
+ * @param {Function} [listener]
+ * If the first argument was another evented object, this will be
+ * the listener function.
+ */
+ on: function on() {
+ var _this = this;
+
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ var _normalizeListenArgs = normalizeListenArgs(this, args),
+ isTargetingSelf = _normalizeListenArgs.isTargetingSelf,
+ target = _normalizeListenArgs.target,
+ type = _normalizeListenArgs.type,
+ listener = _normalizeListenArgs.listener;
+
+ listen(target, 'on', type, listener); // If this object is listening to another evented object.
+
+ if (!isTargetingSelf) {
+ // If this object is disposed, remove the listener.
+ var removeListenerOnDispose = function removeListenerOnDispose() {
+ return _this.off(target, type, listener);
+ }; // Use the same function ID as the listener so we can remove it later it
+ // using the ID of the original listener.
+
+
+ removeListenerOnDispose.guid = listener.guid; // Add a listener to the target's dispose event as well. This ensures
+ // that if the target is disposed BEFORE this object, we remove the
+ // removal listener that was just added. Otherwise, we create a memory leak.
+
+ var removeRemoverOnTargetDispose = function removeRemoverOnTargetDispose() {
+ return _this.off('dispose', removeListenerOnDispose);
+ }; // Use the same function ID as the listener so we can remove it later
+ // it using the ID of the original listener.
+
+
+ removeRemoverOnTargetDispose.guid = listener.guid;
+ listen(this, 'on', 'dispose', removeListenerOnDispose);
+ listen(target, 'on', 'dispose', removeRemoverOnTargetDispose);
+ }
+ },
+
+ /**
+ * Add a listener to an event (or events) on this object or another evented
+ * object. The listener will be called once per event and then removed.
+ *
+ * @param {string|Array|Element|Object} targetOrType
+ * If this is a string or array, it represents the event type(s)
+ * that will trigger the listener.
+ *
+ * Another evented object can be passed here instead, which will
+ * cause the listener to listen for events on _that_ object.
+ *
+ * In either case, the listener's `this` value will be bound to
+ * this object.
+ *
+ * @param {string|Array|Function} typeOrListener
+ * If the first argument was a string or array, this should be the
+ * listener function. Otherwise, this is a string or array of event
+ * type(s).
+ *
+ * @param {Function} [listener]
+ * If the first argument was another evented object, this will be
+ * the listener function.
+ */
+ one: function one() {
+ var _this2 = this;
+
+ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+ args[_key2] = arguments[_key2];
+ }
+
+ var _normalizeListenArgs2 = normalizeListenArgs(this, args),
+ isTargetingSelf = _normalizeListenArgs2.isTargetingSelf,
+ target = _normalizeListenArgs2.target,
+ type = _normalizeListenArgs2.type,
+ listener = _normalizeListenArgs2.listener; // Targeting this evented object.
+
+
+ if (isTargetingSelf) {
+ listen(target, 'one', type, listener); // Targeting another evented object.
+ } else {
+ // TODO: This wrapper is incorrect! It should only
+ // remove the wrapper for the event type that called it.
+ // Instead all listners are removed on the first trigger!
+ // see https://github.com/videojs/video.js/issues/5962
+ var wrapper = function wrapper() {
+ _this2.off(target, type, wrapper);
+
+ for (var _len3 = arguments.length, largs = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
+ largs[_key3] = arguments[_key3];
+ }
+
+ listener.apply(null, largs);
+ }; // Use the same function ID as the listener so we can remove it later
+ // it using the ID of the original listener.
+
+
+ wrapper.guid = listener.guid;
+ listen(target, 'one', type, wrapper);
+ }
+ },
+
+ /**
+ * Add a listener to an event (or events) on this object or another evented
+ * object. The listener will only be called once for the first event that is triggered
+ * then removed.
+ *
+ * @param {string|Array|Element|Object} targetOrType
+ * If this is a string or array, it represents the event type(s)
+ * that will trigger the listener.
+ *
+ * Another evented object can be passed here instead, which will
+ * cause the listener to listen for events on _that_ object.
+ *
+ * In either case, the listener's `this` value will be bound to
+ * this object.
+ *
+ * @param {string|Array|Function} typeOrListener
+ * If the first argument was a string or array, this should be the
+ * listener function. Otherwise, this is a string or array of event
+ * type(s).
+ *
+ * @param {Function} [listener]
+ * If the first argument was another evented object, this will be
+ * the listener function.
+ */
+ any: function any() {
+ var _this3 = this;
+
+ for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
+ args[_key4] = arguments[_key4];
+ }
+
+ var _normalizeListenArgs3 = normalizeListenArgs(this, args),
+ isTargetingSelf = _normalizeListenArgs3.isTargetingSelf,
+ target = _normalizeListenArgs3.target,
+ type = _normalizeListenArgs3.type,
+ listener = _normalizeListenArgs3.listener; // Targeting this evented object.
+
+
+ if (isTargetingSelf) {
+ listen(target, 'any', type, listener); // Targeting another evented object.
+ } else {
+ var wrapper = function wrapper() {
+ _this3.off(target, type, wrapper);
+
+ for (var _len5 = arguments.length, largs = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
+ largs[_key5] = arguments[_key5];
+ }
+
+ listener.apply(null, largs);
+ }; // Use the same function ID as the listener so we can remove it later
+ // it using the ID of the original listener.
+
+
+ wrapper.guid = listener.guid;
+ listen(target, 'any', type, wrapper);
+ }
+ },
+
+ /**
+ * Removes listener(s) from event(s) on an evented object.
+ *
+ * @param {string|Array|Element|Object} [targetOrType]
+ * If this is a string or array, it represents the event type(s).
+ *
+ * Another evented object can be passed here instead, in which case
+ * ALL 3 arguments are _required_.
+ *
+ * @param {string|Array|Function} [typeOrListener]
+ * If the first argument was a string or array, this may be the
+ * listener function. Otherwise, this is a string or array of event
+ * type(s).
+ *
+ * @param {Function} [listener]
+ * If the first argument was another evented object, this will be
+ * the listener function; otherwise, _all_ listeners bound to the
+ * event type(s) will be removed.
+ */
+ off: function off$1(targetOrType, typeOrListener, listener) {
+ // Targeting this evented object.
+ if (!targetOrType || isValidEventType(targetOrType)) {
+ off(this.eventBusEl_, targetOrType, typeOrListener); // Targeting another evented object.
+ } else {
+ var target = targetOrType;
+ var type = typeOrListener; // Fail fast and in a meaningful way!
+
+ validateTarget(target);
+ validateEventType(type);
+ validateListener(listener); // Ensure there's at least a guid, even if the function hasn't been used
+
+ listener = bind(this, listener); // Remove the dispose listener on this evented object, which was given
+ // the same guid as the event listener in on().
+
+ this.off('dispose', listener);
+
+ if (target.nodeName) {
+ off(target, type, listener);
+ off(target, 'dispose', listener);
+ } else if (isEvented(target)) {
+ target.off(type, listener);
+ target.off('dispose', listener);
+ }
+ }
+ },
+
+ /**
+ * Fire an event on this evented object, causing its listeners to be called.
+ *
+ * @param {string|Object} event
+ * An event type or an object with a type property.
+ *
+ * @param {Object} [hash]
+ * An additional object to pass along to listeners.
+ *
+ * @return {boolean}
+ * Whether or not the default behavior was prevented.
+ */
+ trigger: function trigger$1(event, hash) {
+ return trigger(this.eventBusEl_, event, hash);
+ }
+};
+/**
+ * Applies {@link module:evented~EventedMixin|EventedMixin} to a target object.
+ *
+ * @param {Object} target
+ * The object to which to add event methods.
+ *
+ * @param {Object} [options={}]
+ * Options for customizing the mixin behavior.
+ *
+ * @param {string} [options.eventBusKey]
+ * By default, adds a `eventBusEl_` DOM element to the target object,
+ * which is used as an event bus. If the target object already has a
+ * DOM element that should be used, pass its key here.
+ *
+ * @return {Object}
+ * The target object.
+ */
+
+function evented(target, options) {
+ if (options === void 0) {
+ options = {};
+ }
+
+ var _options = options,
+ eventBusKey = _options.eventBusKey; // Set or create the eventBusEl_.
+
+ if (eventBusKey) {
+ if (!target[eventBusKey].nodeName) {
+ throw new Error("The eventBusKey \"" + eventBusKey + "\" does not refer to an element.");
+ }
+
+ target.eventBusEl_ = target[eventBusKey];
+ } else {
+ target.eventBusEl_ = createEl('span', {
+ className: 'vjs-event-bus'
+ });
+ }
+
+ assign(target, EventedMixin);
+
+ if (target.eventedCallbacks) {
+ target.eventedCallbacks.forEach(function (callback) {
+ callback();
+ });
+ } // When any evented object is disposed, it removes all its listeners.
+
+
+ target.on('dispose', function () {
+ target.off();
+ global_window__WEBPACK_IMPORTED_MODULE_0___default().setTimeout(function () {
+ target.eventBusEl_ = null;
+ }, 0);
+ });
+ return target;
+}
+
+/**
+ * @file mixins/stateful.js
+ * @module stateful
+ */
+/**
+ * Contains methods that provide statefulness to an object which is passed
+ * to {@link module:stateful}.
+ *
+ * @mixin StatefulMixin
+ */
+
+var StatefulMixin = {
+ /**
+ * A hash containing arbitrary keys and values representing the state of
+ * the object.
+ *
+ * @type {Object}
+ */
+ state: {},
+
+ /**
+ * Set the state of an object by mutating its
+ * {@link module:stateful~StatefulMixin.state|state} object in place.
+ *
+ * @fires module:stateful~StatefulMixin#statechanged
+ * @param {Object|Function} stateUpdates
+ * A new set of properties to shallow-merge into the plugin state.
+ * Can be a plain object or a function returning a plain object.
+ *
+ * @return {Object|undefined}
+ * An object containing changes that occurred. If no changes
+ * occurred, returns `undefined`.
+ */
+ setState: function setState(stateUpdates) {
+ var _this = this;
+
+ // Support providing the `stateUpdates` state as a function.
+ if (typeof stateUpdates === 'function') {
+ stateUpdates = stateUpdates();
+ }
+
+ var changes;
+ each(stateUpdates, function (value, key) {
+ // Record the change if the value is different from what's in the
+ // current state.
+ if (_this.state[key] !== value) {
+ changes = changes || {};
+ changes[key] = {
+ from: _this.state[key],
+ to: value
+ };
+ }
+
+ _this.state[key] = value;
+ }); // Only trigger "statechange" if there were changes AND we have a trigger
+ // function. This allows us to not require that the target object be an
+ // evented object.
+
+ if (changes && isEvented(this)) {
+ /**
+ * An event triggered on an object that is both
+ * {@link module:stateful|stateful} and {@link module:evented|evented}
+ * indicating that its state has changed.
+ *
+ * @event module:stateful~StatefulMixin#statechanged
+ * @type {Object}
+ * @property {Object} changes
+ * A hash containing the properties that were changed and
+ * the values they were changed `from` and `to`.
+ */
+ this.trigger({
+ changes: changes,
+ type: 'statechanged'
+ });
+ }
+
+ return changes;
+ }
+};
+/**
+ * Applies {@link module:stateful~StatefulMixin|StatefulMixin} to a target
+ * object.
+ *
+ * If the target object is {@link module:evented|evented} and has a
+ * `handleStateChanged` method, that method will be automatically bound to the
+ * `statechanged` event on itself.
+ *
+ * @param {Object} target
+ * The object to be made stateful.
+ *
+ * @param {Object} [defaultState]
+ * A default set of properties to populate the newly-stateful object's
+ * `state` property.
+ *
+ * @return {Object}
+ * Returns the `target`.
+ */
+
+function stateful(target, defaultState) {
+ assign(target, StatefulMixin); // This happens after the mixing-in because we need to replace the `state`
+ // added in that step.
+
+ target.state = assign({}, target.state, defaultState); // Auto-bind the `handleStateChanged` method of the target object if it exists.
+
+ if (typeof target.handleStateChanged === 'function' && isEvented(target)) {
+ target.on('statechanged', target.handleStateChanged);
+ }
+
+ return target;
+}
+
+/**
+ * @file string-cases.js
+ * @module to-lower-case
+ */
+
+/**
+ * Lowercase the first letter of a string.
+ *
+ * @param {string} string
+ * String to be lowercased
+ *
+ * @return {string}
+ * The string with a lowercased first letter
+ */
+var toLowerCase = function toLowerCase(string) {
+ if (typeof string !== 'string') {
+ return string;
+ }
+
+ return string.replace(/./, function (w) {
+ return w.toLowerCase();
+ });
+};
+/**
+ * Uppercase the first letter of a string.
+ *
+ * @param {string} string
+ * String to be uppercased
+ *
+ * @return {string}
+ * The string with an uppercased first letter
+ */
+
+var toTitleCase = function toTitleCase(string) {
+ if (typeof string !== 'string') {
+ return string;
+ }
+
+ return string.replace(/./, function (w) {
+ return w.toUpperCase();
+ });
+};
+/**
+ * Compares the TitleCase versions of the two strings for equality.
+ *
+ * @param {string} str1
+ * The first string to compare
+ *
+ * @param {string} str2
+ * The second string to compare
+ *
+ * @return {boolean}
+ * Whether the TitleCase versions of the strings are equal
+ */
+
+var titleCaseEquals = function titleCaseEquals(str1, str2) {
+ return toTitleCase(str1) === toTitleCase(str2);
+};
+
+/**
+ * @file merge-options.js
+ * @module merge-options
+ */
+/**
+ * Merge two objects recursively.
+ *
+ * Performs a deep merge like
+ * {@link https://lodash.com/docs/4.17.10#merge|lodash.merge}, but only merges
+ * plain objects (not arrays, elements, or anything else).
+ *
+ * Non-plain object values will be copied directly from the right-most
+ * argument.
+ *
+ * @static
+ * @param {Object[]} sources
+ * One or more objects to merge into a new object.
+ *
+ * @return {Object}
+ * A new object that is the merged result of all sources.
+ */
+
+function mergeOptions() {
+ var result = {};
+
+ for (var _len = arguments.length, sources = new Array(_len), _key = 0; _key < _len; _key++) {
+ sources[_key] = arguments[_key];
+ }
+
+ sources.forEach(function (source) {
+ if (!source) {
+ return;
+ }
+
+ each(source, function (value, key) {
+ if (!isPlain(value)) {
+ result[key] = value;
+ return;
+ }
+
+ if (!isPlain(result[key])) {
+ result[key] = {};
+ }
+
+ result[key] = mergeOptions(result[key], value);
+ });
+ });
+ return result;
+}
+
+var MapSham = /*#__PURE__*/function () {
+ function MapSham() {
+ this.map_ = {};
+ }
+
+ var _proto = MapSham.prototype;
+
+ _proto.has = function has(key) {
+ return key in this.map_;
+ };
+
+ _proto["delete"] = function _delete(key) {
+ var has = this.has(key);
+ delete this.map_[key];
+ return has;
+ };
+
+ _proto.set = function set(key, value) {
+ this.set_[key] = value;
+ return this;
+ };
+
+ _proto.forEach = function forEach(callback, thisArg) {
+ for (var key in this.map_) {
+ callback.call(thisArg, this.map_[key], key, this);
+ }
+ };
+
+ return MapSham;
+}();
+
+var Map$1 = (global_window__WEBPACK_IMPORTED_MODULE_0___default().Map) ? (global_window__WEBPACK_IMPORTED_MODULE_0___default().Map) : MapSham;
+
+var SetSham = /*#__PURE__*/function () {
+ function SetSham() {
+ this.set_ = {};
+ }
+
+ var _proto = SetSham.prototype;
+
+ _proto.has = function has(key) {
+ return key in this.set_;
+ };
+
+ _proto["delete"] = function _delete(key) {
+ var has = this.has(key);
+ delete this.set_[key];
+ return has;
+ };
+
+ _proto.add = function add(key) {
+ this.set_[key] = 1;
+ return this;
+ };
+
+ _proto.forEach = function forEach(callback, thisArg) {
+ for (var key in this.set_) {
+ callback.call(thisArg, key, key, this);
+ }
+ };
+
+ return SetSham;
+}();
+
+var Set = (global_window__WEBPACK_IMPORTED_MODULE_0___default().Set) ? (global_window__WEBPACK_IMPORTED_MODULE_0___default().Set) : SetSham;
+
+/**
+ * Player Component - Base class for all UI objects
+ *
+ * @file component.js
+ */
+/**
+ * Base class for all UI Components.
+ * Components are UI objects which represent both a javascript object and an element
+ * in the DOM. They can be children of other components, and can have
+ * children themselves.
+ *
+ * Components can also use methods from {@link EventTarget}
+ */
+
+var Component = /*#__PURE__*/function () {
+ /**
+ * A callback that is called when a component is ready. Does not have any
+ * paramters and any callback value will be ignored.
+ *
+ * @callback Component~ReadyCallback
+ * @this Component
+ */
+
+ /**
+ * Creates an instance of this class.
+ *
+ * @param {Player} player
+ * The `Player` that this class should be attached to.
+ *
+ * @param {Object} [options]
+ * The key/value store of player options.
+ *
+ * @param {Object[]} [options.children]
+ * An array of children objects to intialize this component with. Children objects have
+ * a name property that will be used if more than one component of the same type needs to be
+ * added.
+ *
+ * @param {Component~ReadyCallback} [ready]
+ * Function that gets called when the `Component` is ready.
+ */
+ function Component(player, options, ready) {
+ // The component might be the player itself and we can't pass `this` to super
+ if (!player && this.play) {
+ this.player_ = player = this; // eslint-disable-line
+ } else {
+ this.player_ = player;
+ }
+
+ this.isDisposed_ = false; // Hold the reference to the parent component via `addChild` method
+
+ this.parentComponent_ = null; // Make a copy of prototype.options_ to protect against overriding defaults
+
+ this.options_ = mergeOptions({}, this.options_); // Updated options with supplied options
+
+ options = this.options_ = mergeOptions(this.options_, options); // Get ID from options or options element if one is supplied
+
+ this.id_ = options.id || options.el && options.el.id; // If there was no ID from the options, generate one
+
+ if (!this.id_) {
+ // Don't require the player ID function in the case of mock players
+ var id = player && player.id && player.id() || 'no_player';
+ this.id_ = id + "_component_" + newGUID();
+ }
+
+ this.name_ = options.name || null; // Create element if one wasn't provided in options
+
+ if (options.el) {
+ this.el_ = options.el;
+ } else if (options.createEl !== false) {
+ this.el_ = this.createEl();
+ } // if evented is anything except false, we want to mixin in evented
+
+
+ if (options.evented !== false) {
+ // Make this an evented object and use `el_`, if available, as its event bus
+ evented(this, {
+ eventBusKey: this.el_ ? 'el_' : null
+ });
+ }
+
+ stateful(this, this.constructor.defaultState);
+ this.children_ = [];
+ this.childIndex_ = {};
+ this.childNameIndex_ = {};
+ this.setTimeoutIds_ = new Set();
+ this.setIntervalIds_ = new Set();
+ this.rafIds_ = new Set();
+ this.namedRafs_ = new Map$1();
+ this.clearingTimersOnDispose_ = false; // Add any child components in options
+
+ if (options.initChildren !== false) {
+ this.initChildren();
+ }
+
+ this.ready(ready); // Don't want to trigger ready here or it will before init is actually
+ // finished for all children that run this constructor
+
+ if (options.reportTouchActivity !== false) {
+ this.enableTouchActivity();
+ }
+ }
+ /**
+ * Dispose of the `Component` and all child components.
+ *
+ * @fires Component#dispose
+ */
+
+
+ var _proto = Component.prototype;
+
+ _proto.dispose = function dispose() {
+ // Bail out if the component has already been disposed.
+ if (this.isDisposed_) {
+ return;
+ }
+ /**
+ * Triggered when a `Component` is disposed.
+ *
+ * @event Component#dispose
+ * @type {EventTarget~Event}
+ *
+ * @property {boolean} [bubbles=false]
+ * set to false so that the dispose event does not
+ * bubble up
+ */
+
+
+ this.trigger({
+ type: 'dispose',
+ bubbles: false
+ });
+ this.isDisposed_ = true; // Dispose all children.
+
+ if (this.children_) {
+ for (var i = this.children_.length - 1; i >= 0; i--) {
+ if (this.children_[i].dispose) {
+ this.children_[i].dispose();
+ }
+ }
+ } // Delete child references
+
+
+ this.children_ = null;
+ this.childIndex_ = null;
+ this.childNameIndex_ = null;
+ this.parentComponent_ = null;
+
+ if (this.el_) {
+ // Remove element from DOM
+ if (this.el_.parentNode) {
+ this.el_.parentNode.removeChild(this.el_);
+ }
+
+ if (DomData.has(this.el_)) {
+ DomData["delete"](this.el_);
+ }
+
+ this.el_ = null;
+ } // remove reference to the player after disposing of the element
+
+
+ this.player_ = null;
+ }
+ /**
+ * Determine whether or not this component has been disposed.
+ *
+ * @return {boolean}
+ * If the component has been disposed, will be `true`. Otherwise, `false`.
+ */
+ ;
+
+ _proto.isDisposed = function isDisposed() {
+ return Boolean(this.isDisposed_);
+ }
+ /**
+ * Return the {@link Player} that the `Component` has attached to.
+ *
+ * @return {Player}
+ * The player that this `Component` has attached to.
+ */
+ ;
+
+ _proto.player = function player() {
+ return this.player_;
+ }
+ /**
+ * Deep merge of options objects with new options.
+ * > Note: When both `obj` and `options` contain properties whose values are objects.
+ * The two properties get merged using {@link module:mergeOptions}
+ *
+ * @param {Object} obj
+ * The object that contains new options.
+ *
+ * @return {Object}
+ * A new object of `this.options_` and `obj` merged together.
+ */
+ ;
+
+ _proto.options = function options(obj) {
+ if (!obj) {
+ return this.options_;
+ }
+
+ this.options_ = mergeOptions(this.options_, obj);
+ return this.options_;
+ }
+ /**
+ * Get the `Component`s DOM element
+ *
+ * @return {Element}
+ * The DOM element for this `Component`.
+ */
+ ;
+
+ _proto.el = function el() {
+ return this.el_;
+ }
+ /**
+ * Create the `Component`s DOM element.
+ *
+ * @param {string} [tagName]
+ * Element's DOM node type. e.g. 'div'
+ *
+ * @param {Object} [properties]
+ * An object of properties that should be set.
+ *
+ * @param {Object} [attributes]
+ * An object of attributes that should be set.
+ *
+ * @return {Element}
+ * The element that gets created.
+ */
+ ;
+
+ _proto.createEl = function createEl$1(tagName, properties, attributes) {
+ return createEl(tagName, properties, attributes);
+ }
+ /**
+ * Localize a string given the string in english.
+ *
+ * If tokens are provided, it'll try and run a simple token replacement on the provided string.
+ * The tokens it looks for look like `{1}` with the index being 1-indexed into the tokens array.
+ *
+ * If a `defaultValue` is provided, it'll use that over `string`,
+ * if a value isn't found in provided language files.
+ * This is useful if you want to have a descriptive key for token replacement
+ * but have a succinct localized string and not require `en.json` to be included.
+ *
+ * Currently, it is used for the progress bar timing.
+ * ```js
+ * {
+ * "progress bar timing: currentTime={1} duration={2}": "{1} of {2}"
+ * }
+ * ```
+ * It is then used like so:
+ * ```js
+ * this.localize('progress bar timing: currentTime={1} duration{2}',
+ * [this.player_.currentTime(), this.player_.duration()],
+ * '{1} of {2}');
+ * ```
+ *
+ * Which outputs something like: `01:23 of 24:56`.
+ *
+ *
+ * @param {string} string
+ * The string to localize and the key to lookup in the language files.
+ * @param {string[]} [tokens]
+ * If the current item has token replacements, provide the tokens here.
+ * @param {string} [defaultValue]
+ * Defaults to `string`. Can be a default value to use for token replacement
+ * if the lookup key is needed to be separate.
+ *
+ * @return {string}
+ * The localized string or if no localization exists the english string.
+ */
+ ;
+
+ _proto.localize = function localize(string, tokens, defaultValue) {
+ if (defaultValue === void 0) {
+ defaultValue = string;
+ }
+
+ var code = this.player_.language && this.player_.language();
+ var languages = this.player_.languages && this.player_.languages();
+ var language = languages && languages[code];
+ var primaryCode = code && code.split('-')[0];
+ var primaryLang = languages && languages[primaryCode];
+ var localizedString = defaultValue;
+
+ if (language && language[string]) {
+ localizedString = language[string];
+ } else if (primaryLang && primaryLang[string]) {
+ localizedString = primaryLang[string];
+ }
+
+ if (tokens) {
+ localizedString = localizedString.replace(/\{(\d+)\}/g, function (match, index) {
+ var value = tokens[index - 1];
+ var ret = value;
+
+ if (typeof value === 'undefined') {
+ ret = match;
+ }
+
+ return ret;
+ });
+ }
+
+ return localizedString;
+ }
+ /**
+ * Return the `Component`s DOM element. This is where children get inserted.
+ * This will usually be the the same as the element returned in {@link Component#el}.
+ *
+ * @return {Element}
+ * The content element for this `Component`.
+ */
+ ;
+
+ _proto.contentEl = function contentEl() {
+ return this.contentEl_ || this.el_;
+ }
+ /**
+ * Get this `Component`s ID
+ *
+ * @return {string}
+ * The id of this `Component`
+ */
+ ;
+
+ _proto.id = function id() {
+ return this.id_;
+ }
+ /**
+ * Get the `Component`s name. The name gets used to reference the `Component`
+ * and is set during registration.
+ *
+ * @return {string}
+ * The name of this `Component`.
+ */
+ ;
+
+ _proto.name = function name() {
+ return this.name_;
+ }
+ /**
+ * Get an array of all child components
+ *
+ * @return {Array}
+ * The children
+ */
+ ;
+
+ _proto.children = function children() {
+ return this.children_;
+ }
+ /**
+ * Returns the child `Component` with the given `id`.
+ *
+ * @param {string} id
+ * The id of the child `Component` to get.
+ *
+ * @return {Component|undefined}
+ * The child `Component` with the given `id` or undefined.
+ */
+ ;
+
+ _proto.getChildById = function getChildById(id) {
+ return this.childIndex_[id];
+ }
+ /**
+ * Returns the child `Component` with the given `name`.
+ *
+ * @param {string} name
+ * The name of the child `Component` to get.
+ *
+ * @return {Component|undefined}
+ * The child `Component` with the given `name` or undefined.
+ */
+ ;
+
+ _proto.getChild = function getChild(name) {
+ if (!name) {
+ return;
+ }
+
+ return this.childNameIndex_[name];
+ }
+ /**
+ * Returns the descendant `Component` following the givent
+ * descendant `names`. For instance ['foo', 'bar', 'baz'] would
+ * try to get 'foo' on the current component, 'bar' on the 'foo'
+ * component and 'baz' on the 'bar' component and return undefined
+ * if any of those don't exist.
+ *
+ * @param {...string[]|...string} names
+ * The name of the child `Component` to get.
+ *
+ * @return {Component|undefined}
+ * The descendant `Component` following the given descendant
+ * `names` or undefined.
+ */
+ ;
+
+ _proto.getDescendant = function getDescendant() {
+ for (var _len = arguments.length, names = new Array(_len), _key = 0; _key < _len; _key++) {
+ names[_key] = arguments[_key];
+ }
+
+ // flatten array argument into the main array
+ names = names.reduce(function (acc, n) {
+ return acc.concat(n);
+ }, []);
+ var currentChild = this;
+
+ for (var i = 0; i < names.length; i++) {
+ currentChild = currentChild.getChild(names[i]);
+
+ if (!currentChild || !currentChild.getChild) {
+ return;
+ }
+ }
+
+ return currentChild;
+ }
+ /**
+ * Add a child `Component` inside the current `Component`.
+ *
+ *
+ * @param {string|Component} child
+ * The name or instance of a child to add.
+ *
+ * @param {Object} [options={}]
+ * The key/value store of options that will get passed to children of
+ * the child.
+ *
+ * @param {number} [index=this.children_.length]
+ * The index to attempt to add a child into.
+ *
+ * @return {Component}
+ * The `Component` that gets added as a child. When using a string the
+ * `Component` will get created by this process.
+ */
+ ;
+
+ _proto.addChild = function addChild(child, options, index) {
+ if (options === void 0) {
+ options = {};
+ }
+
+ if (index === void 0) {
+ index = this.children_.length;
+ }
+
+ var component;
+ var componentName; // If child is a string, create component with options
+
+ if (typeof child === 'string') {
+ componentName = toTitleCase(child);
+ var componentClassName = options.componentClass || componentName; // Set name through options
+
+ options.name = componentName; // Create a new object & element for this controls set
+ // If there's no .player_, this is a player
+
+ var ComponentClass = Component.getComponent(componentClassName);
+
+ if (!ComponentClass) {
+ throw new Error("Component " + componentClassName + " does not exist");
+ } // data stored directly on the videojs object may be
+ // misidentified as a component to retain
+ // backwards-compatibility with 4.x. check to make sure the
+ // component class can be instantiated.
+
+
+ if (typeof ComponentClass !== 'function') {
+ return null;
+ }
+
+ component = new ComponentClass(this.player_ || this, options); // child is a component instance
+ } else {
+ component = child;
+ }
+
+ if (component.parentComponent_) {
+ component.parentComponent_.removeChild(component);
+ }
+
+ this.children_.splice(index, 0, component);
+ component.parentComponent_ = this;
+
+ if (typeof component.id === 'function') {
+ this.childIndex_[component.id()] = component;
+ } // If a name wasn't used to create the component, check if we can use the
+ // name function of the component
+
+
+ componentName = componentName || component.name && toTitleCase(component.name());
+
+ if (componentName) {
+ this.childNameIndex_[componentName] = component;
+ this.childNameIndex_[toLowerCase(componentName)] = component;
+ } // Add the UI object's element to the container div (box)
+ // Having an element is not required
+
+
+ if (typeof component.el === 'function' && component.el()) {
+ // If inserting before a component, insert before that component's element
+ var refNode = null;
+
+ if (this.children_[index + 1]) {
+ // Most children are components, but the video tech is an HTML element
+ if (this.children_[index + 1].el_) {
+ refNode = this.children_[index + 1].el_;
+ } else if (isEl(this.children_[index + 1])) {
+ refNode = this.children_[index + 1];
+ }
+ }
+
+ this.contentEl().insertBefore(component.el(), refNode);
+ } // Return so it can stored on parent object if desired.
+
+
+ return component;
+ }
+ /**
+ * Remove a child `Component` from this `Component`s list of children. Also removes
+ * the child `Component`s element from this `Component`s element.
+ *
+ * @param {Component} component
+ * The child `Component` to remove.
+ */
+ ;
+
+ _proto.removeChild = function removeChild(component) {
+ if (typeof component === 'string') {
+ component = this.getChild(component);
+ }
+
+ if (!component || !this.children_) {
+ return;
+ }
+
+ var childFound = false;
+
+ for (var i = this.children_.length - 1; i >= 0; i--) {
+ if (this.children_[i] === component) {
+ childFound = true;
+ this.children_.splice(i, 1);
+ break;
+ }
+ }
+
+ if (!childFound) {
+ return;
+ }
+
+ component.parentComponent_ = null;
+ this.childIndex_[component.id()] = null;
+ this.childNameIndex_[toTitleCase(component.name())] = null;
+ this.childNameIndex_[toLowerCase(component.name())] = null;
+ var compEl = component.el();
+
+ if (compEl && compEl.parentNode === this.contentEl()) {
+ this.contentEl().removeChild(component.el());
+ }
+ }
+ /**
+ * Add and initialize default child `Component`s based upon options.
+ */
+ ;
+
+ _proto.initChildren = function initChildren() {
+ var _this = this;
+
+ var children = this.options_.children;
+
+ if (children) {
+ // `this` is `parent`
+ var parentOptions = this.options_;
+
+ var handleAdd = function handleAdd(child) {
+ var name = child.name;
+ var opts = child.opts; // Allow options for children to be set at the parent options
+ // e.g. videojs(id, { controlBar: false });
+ // instead of videojs(id, { children: { controlBar: false });
+
+ if (parentOptions[name] !== undefined) {
+ opts = parentOptions[name];
+ } // Allow for disabling default components
+ // e.g. options['children']['posterImage'] = false
+
+
+ if (opts === false) {
+ return;
+ } // Allow options to be passed as a simple boolean if no configuration
+ // is necessary.
+
+
+ if (opts === true) {
+ opts = {};
+ } // We also want to pass the original player options
+ // to each component as well so they don't need to
+ // reach back into the player for options later.
+
+
+ opts.playerOptions = _this.options_.playerOptions; // Create and add the child component.
+ // Add a direct reference to the child by name on the parent instance.
+ // If two of the same component are used, different names should be supplied
+ // for each
+
+ var newChild = _this.addChild(name, opts);
+
+ if (newChild) {
+ _this[name] = newChild;
+ }
+ }; // Allow for an array of children details to passed in the options
+
+
+ var workingChildren;
+ var Tech = Component.getComponent('Tech');
+
+ if (Array.isArray(children)) {
+ workingChildren = children;
+ } else {
+ workingChildren = Object.keys(children);
+ }
+
+ workingChildren // children that are in this.options_ but also in workingChildren would
+ // give us extra children we do not want. So, we want to filter them out.
+ .concat(Object.keys(this.options_).filter(function (child) {
+ return !workingChildren.some(function (wchild) {
+ if (typeof wchild === 'string') {
+ return child === wchild;
+ }
+
+ return child === wchild.name;
+ });
+ })).map(function (child) {
+ var name;
+ var opts;
+
+ if (typeof child === 'string') {
+ name = child;
+ opts = children[name] || _this.options_[name] || {};
+ } else {
+ name = child.name;
+ opts = child;
+ }
+
+ return {
+ name: name,
+ opts: opts
+ };
+ }).filter(function (child) {
+ // we have to make sure that child.name isn't in the techOrder since
+ // techs are registerd as Components but can't aren't compatible
+ // See https://github.com/videojs/video.js/issues/2772
+ var c = Component.getComponent(child.opts.componentClass || toTitleCase(child.name));
+ return c && !Tech.isTech(c);
+ }).forEach(handleAdd);
+ }
+ }
+ /**
+ * Builds the default DOM class name. Should be overriden by sub-components.
+ *
+ * @return {string}
+ * The DOM class name for this object.
+ *
+ * @abstract
+ */
+ ;
+
+ _proto.buildCSSClass = function buildCSSClass() {
+ // Child classes can include a function that does:
+ // return 'CLASS NAME' + this._super();
+ return '';
+ }
+ /**
+ * Bind a listener to the component's ready state.
+ * Different from event listeners in that if the ready event has already happened
+ * it will trigger the function immediately.
+ *
+ * @return {Component}
+ * Returns itself; method can be chained.
+ */
+ ;
+
+ _proto.ready = function ready(fn, sync) {
+ if (sync === void 0) {
+ sync = false;
+ }
+
+ if (!fn) {
+ return;
+ }
+
+ if (!this.isReady_) {
+ this.readyQueue_ = this.readyQueue_ || [];
+ this.readyQueue_.push(fn);
+ return;
+ }
+
+ if (sync) {
+ fn.call(this);
+ } else {
+ // Call the function asynchronously by default for consistency
+ this.setTimeout(fn, 1);
+ }
+ }
+ /**
+ * Trigger all the ready listeners for this `Component`.
+ *
+ * @fires Component#ready
+ */
+ ;
+
+ _proto.triggerReady = function triggerReady() {
+ this.isReady_ = true; // Ensure ready is triggered asynchronously
+
+ this.setTimeout(function () {
+ var readyQueue = this.readyQueue_; // Reset Ready Queue
+
+ this.readyQueue_ = [];
+
+ if (readyQueue && readyQueue.length > 0) {
+ readyQueue.forEach(function (fn) {
+ fn.call(this);
+ }, this);
+ } // Allow for using event listeners also
+
+ /**
+ * Triggered when a `Component` is ready.
+ *
+ * @event Component#ready
+ * @type {EventTarget~Event}
+ */
+
+
+ this.trigger('ready');
+ }, 1);
+ }
+ /**
+ * Find a single DOM element matching a `selector`. This can be within the `Component`s
+ * `contentEl()` or another custom context.
+ *
+ * @param {string} selector
+ * A valid CSS selector, which will be passed to `querySelector`.
+ *
+ * @param {Element|string} [context=this.contentEl()]
+ * A DOM element within which to query. Can also be a selector string in
+ * which case the first matching element will get used as context. If
+ * missing `this.contentEl()` gets used. If `this.contentEl()` returns
+ * nothing it falls back to `document`.
+ *
+ * @return {Element|null}
+ * the dom element that was found, or null
+ *
+ * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)
+ */
+ ;
+
+ _proto.$ = function $$1(selector, context) {
+ return $(selector, context || this.contentEl());
+ }
+ /**
+ * Finds all DOM element matching a `selector`. This can be within the `Component`s
+ * `contentEl()` or another custom context.
+ *
+ * @param {string} selector
+ * A valid CSS selector, which will be passed to `querySelectorAll`.
+ *
+ * @param {Element|string} [context=this.contentEl()]
+ * A DOM element within which to query. Can also be a selector string in
+ * which case the first matching element will get used as context. If
+ * missing `this.contentEl()` gets used. If `this.contentEl()` returns
+ * nothing it falls back to `document`.
+ *
+ * @return {NodeList}
+ * a list of dom elements that were found
+ *
+ * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)
+ */
+ ;
+
+ _proto.$$ = function $$$1(selector, context) {
+ return $$(selector, context || this.contentEl());
+ }
+ /**
+ * Check if a component's element has a CSS class name.
+ *
+ * @param {string} classToCheck
+ * CSS class name to check.
+ *
+ * @return {boolean}
+ * - True if the `Component` has the class.
+ * - False if the `Component` does not have the class`
+ */
+ ;
+
+ _proto.hasClass = function hasClass$1(classToCheck) {
+ return hasClass(this.el_, classToCheck);
+ }
+ /**
+ * Add a CSS class name to the `Component`s element.
+ *
+ * @param {string} classToAdd
+ * CSS class name to add
+ */
+ ;
+
+ _proto.addClass = function addClass$1(classToAdd) {
+ addClass(this.el_, classToAdd);
+ }
+ /**
+ * Remove a CSS class name from the `Component`s element.
+ *
+ * @param {string} classToRemove
+ * CSS class name to remove
+ */
+ ;
+
+ _proto.removeClass = function removeClass$1(classToRemove) {
+ removeClass(this.el_, classToRemove);
+ }
+ /**
+ * Add or remove a CSS class name from the component's element.
+ * - `classToToggle` gets added when {@link Component#hasClass} would return false.
+ * - `classToToggle` gets removed when {@link Component#hasClass} would return true.
+ *
+ * @param {string} classToToggle
+ * The class to add or remove based on (@link Component#hasClass}
+ *
+ * @param {boolean|Dom~predicate} [predicate]
+ * An {@link Dom~predicate} function or a boolean
+ */
+ ;
+
+ _proto.toggleClass = function toggleClass$1(classToToggle, predicate) {
+ toggleClass(this.el_, classToToggle, predicate);
+ }
+ /**
+ * Show the `Component`s element if it is hidden by removing the
+ * 'vjs-hidden' class name from it.
+ */
+ ;
+
+ _proto.show = function show() {
+ this.removeClass('vjs-hidden');
+ }
+ /**
+ * Hide the `Component`s element if it is currently showing by adding the
+ * 'vjs-hidden` class name to it.
+ */
+ ;
+
+ _proto.hide = function hide() {
+ this.addClass('vjs-hidden');
+ }
+ /**
+ * Lock a `Component`s element in its visible state by adding the 'vjs-lock-showing'
+ * class name to it. Used during fadeIn/fadeOut.
+ *
+ * @private
+ */
+ ;
+
+ _proto.lockShowing = function lockShowing() {
+ this.addClass('vjs-lock-showing');
+ }
+ /**
+ * Unlock a `Component`s element from its visible state by removing the 'vjs-lock-showing'
+ * class name from it. Used during fadeIn/fadeOut.
+ *
+ * @private
+ */
+ ;
+
+ _proto.unlockShowing = function unlockShowing() {
+ this.removeClass('vjs-lock-showing');
+ }
+ /**
+ * Get the value of an attribute on the `Component`s element.
+ *
+ * @param {string} attribute
+ * Name of the attribute to get the value from.
+ *
+ * @return {string|null}
+ * - The value of the attribute that was asked for.
+ * - Can be an empty string on some browsers if the attribute does not exist
+ * or has no value
+ * - Most browsers will return null if the attibute does not exist or has
+ * no value.
+ *
+ * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute}
+ */
+ ;
+
+ _proto.getAttribute = function getAttribute$1(attribute) {
+ return getAttribute(this.el_, attribute);
+ }
+ /**
+ * Set the value of an attribute on the `Component`'s element
+ *
+ * @param {string} attribute
+ * Name of the attribute to set.
+ *
+ * @param {string} value
+ * Value to set the attribute to.
+ *
+ * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute}
+ */
+ ;
+
+ _proto.setAttribute = function setAttribute$1(attribute, value) {
+ setAttribute(this.el_, attribute, value);
+ }
+ /**
+ * Remove an attribute from the `Component`s element.
+ *
+ * @param {string} attribute
+ * Name of the attribute to remove.
+ *
+ * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute}
+ */
+ ;
+
+ _proto.removeAttribute = function removeAttribute$1(attribute) {
+ removeAttribute(this.el_, attribute);
+ }
+ /**
+ * Get or set the width of the component based upon the CSS styles.
+ * See {@link Component#dimension} for more detailed information.
+ *
+ * @param {number|string} [num]
+ * The width that you want to set postfixed with '%', 'px' or nothing.
+ *
+ * @param {boolean} [skipListeners]
+ * Skip the componentresize event trigger
+ *
+ * @return {number|string}
+ * The width when getting, zero if there is no width. Can be a string
+ * postpixed with '%' or 'px'.
+ */
+ ;
+
+ _proto.width = function width(num, skipListeners) {
+ return this.dimension('width', num, skipListeners);
+ }
+ /**
+ * Get or set the height of the component based upon the CSS styles.
+ * See {@link Component#dimension} for more detailed information.
+ *
+ * @param {number|string} [num]
+ * The height that you want to set postfixed with '%', 'px' or nothing.
+ *
+ * @param {boolean} [skipListeners]
+ * Skip the componentresize event trigger
+ *
+ * @return {number|string}
+ * The width when getting, zero if there is no width. Can be a string
+ * postpixed with '%' or 'px'.
+ */
+ ;
+
+ _proto.height = function height(num, skipListeners) {
+ return this.dimension('height', num, skipListeners);
+ }
+ /**
+ * Set both the width and height of the `Component` element at the same time.
+ *
+ * @param {number|string} width
+ * Width to set the `Component`s element to.
+ *
+ * @param {number|string} height
+ * Height to set the `Component`s element to.
+ */
+ ;
+
+ _proto.dimensions = function dimensions(width, height) {
+ // Skip componentresize listeners on width for optimization
+ this.width(width, true);
+ this.height(height);
+ }
+ /**
+ * Get or set width or height of the `Component` element. This is the shared code
+ * for the {@link Component#width} and {@link Component#height}.
+ *
+ * Things to know:
+ * - If the width or height in an number this will return the number postfixed with 'px'.
+ * - If the width/height is a percent this will return the percent postfixed with '%'
+ * - Hidden elements have a width of 0 with `window.getComputedStyle`. This function
+ * defaults to the `Component`s `style.width` and falls back to `window.getComputedStyle`.
+ * See [this]{@link http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/}
+ * for more information
+ * - If you want the computed style of the component, use {@link Component#currentWidth}
+ * and {@link {Component#currentHeight}
+ *
+ * @fires Component#componentresize
+ *
+ * @param {string} widthOrHeight
+ 8 'width' or 'height'
+ *
+ * @param {number|string} [num]
+ 8 New dimension
+ *
+ * @param {boolean} [skipListeners]
+ * Skip componentresize event trigger
+ *
+ * @return {number}
+ * The dimension when getting or 0 if unset
+ */
+ ;
+
+ _proto.dimension = function dimension(widthOrHeight, num, skipListeners) {
+ if (num !== undefined) {
+ // Set to zero if null or literally NaN (NaN !== NaN)
+ if (num === null || num !== num) {
+ num = 0;
+ } // Check if using css width/height (% or px) and adjust
+
+
+ if (('' + num).indexOf('%') !== -1 || ('' + num).indexOf('px') !== -1) {
+ this.el_.style[widthOrHeight] = num;
+ } else if (num === 'auto') {
+ this.el_.style[widthOrHeight] = '';
+ } else {
+ this.el_.style[widthOrHeight] = num + 'px';
+ } // skipListeners allows us to avoid triggering the resize event when setting both width and height
+
+
+ if (!skipListeners) {
+ /**
+ * Triggered when a component is resized.
+ *
+ * @event Component#componentresize
+ * @type {EventTarget~Event}
+ */
+ this.trigger('componentresize');
+ }
+
+ return;
+ } // Not setting a value, so getting it
+ // Make sure element exists
+
+
+ if (!this.el_) {
+ return 0;
+ } // Get dimension value from style
+
+
+ var val = this.el_.style[widthOrHeight];
+ var pxIndex = val.indexOf('px');
+
+ if (pxIndex !== -1) {
+ // Return the pixel value with no 'px'
+ return parseInt(val.slice(0, pxIndex), 10);
+ } // No px so using % or no style was set, so falling back to offsetWidth/height
+ // If component has display:none, offset will return 0
+ // TODO: handle display:none and no dimension style using px
+
+
+ return parseInt(this.el_['offset' + toTitleCase(widthOrHeight)], 10);
+ }
+ /**
+ * Get the computed width or the height of the component's element.
+ *
+ * Uses `window.getComputedStyle`.
+ *
+ * @param {string} widthOrHeight
+ * A string containing 'width' or 'height'. Whichever one you want to get.
+ *
+ * @return {number}
+ * The dimension that gets asked for or 0 if nothing was set
+ * for that dimension.
+ */
+ ;
+
+ _proto.currentDimension = function currentDimension(widthOrHeight) {
+ var computedWidthOrHeight = 0;
+
+ if (widthOrHeight !== 'width' && widthOrHeight !== 'height') {
+ throw new Error('currentDimension only accepts width or height value');
+ }
+
+ computedWidthOrHeight = computedStyle(this.el_, widthOrHeight); // remove 'px' from variable and parse as integer
+
+ computedWidthOrHeight = parseFloat(computedWidthOrHeight); // if the computed value is still 0, it's possible that the browser is lying
+ // and we want to check the offset values.
+ // This code also runs wherever getComputedStyle doesn't exist.
+
+ if (computedWidthOrHeight === 0 || isNaN(computedWidthOrHeight)) {
+ var rule = "offset" + toTitleCase(widthOrHeight);
+ computedWidthOrHeight = this.el_[rule];
+ }
+
+ return computedWidthOrHeight;
+ }
+ /**
+ * An object that contains width and height values of the `Component`s
+ * computed style. Uses `window.getComputedStyle`.
+ *
+ * @typedef {Object} Component~DimensionObject
+ *
+ * @property {number} width
+ * The width of the `Component`s computed style.
+ *
+ * @property {number} height
+ * The height of the `Component`s computed style.
+ */
+
+ /**
+ * Get an object that contains computed width and height values of the
+ * component's element.
+ *
+ * Uses `window.getComputedStyle`.
+ *
+ * @return {Component~DimensionObject}
+ * The computed dimensions of the component's element.
+ */
+ ;
+
+ _proto.currentDimensions = function currentDimensions() {
+ return {
+ width: this.currentDimension('width'),
+ height: this.currentDimension('height')
+ };
+ }
+ /**
+ * Get the computed width of the component's element.
+ *
+ * Uses `window.getComputedStyle`.
+ *
+ * @return {number}
+ * The computed width of the component's element.
+ */
+ ;
+
+ _proto.currentWidth = function currentWidth() {
+ return this.currentDimension('width');
+ }
+ /**
+ * Get the computed height of the component's element.
+ *
+ * Uses `window.getComputedStyle`.
+ *
+ * @return {number}
+ * The computed height of the component's element.
+ */
+ ;
+
+ _proto.currentHeight = function currentHeight() {
+ return this.currentDimension('height');
+ }
+ /**
+ * Set the focus to this component
+ */
+ ;
+
+ _proto.focus = function focus() {
+ this.el_.focus();
+ }
+ /**
+ * Remove the focus from this component
+ */
+ ;
+
+ _proto.blur = function blur() {
+ this.el_.blur();
+ }
+ /**
+ * When this Component receives a `keydown` event which it does not process,
+ * it passes the event to the Player for handling.
+ *
+ * @param {EventTarget~Event} event
+ * The `keydown` event that caused this function to be called.
+ */
+ ;
+
+ _proto.handleKeyDown = function handleKeyDown(event) {
+ if (this.player_) {
+ // We only stop propagation here because we want unhandled events to fall
+ // back to the browser.
+ event.stopPropagation();
+ this.player_.handleKeyDown(event);
+ }
+ }
+ /**
+ * Many components used to have a `handleKeyPress` method, which was poorly
+ * named because it listened to a `keydown` event. This method name now
+ * delegates to `handleKeyDown`. This means anyone calling `handleKeyPress`
+ * will not see their method calls stop working.
+ *
+ * @param {EventTarget~Event} event
+ * The event that caused this function to be called.
+ */
+ ;
+
+ _proto.handleKeyPress = function handleKeyPress(event) {
+ this.handleKeyDown(event);
+ }
+ /**
+ * Emit a 'tap' events when touch event support gets detected. This gets used to
+ * support toggling the controls through a tap on the video. They get enabled
+ * because every sub-component would have extra overhead otherwise.
+ *
+ * @private
+ * @fires Component#tap
+ * @listens Component#touchstart
+ * @listens Component#touchmove
+ * @listens Component#touchleave
+ * @listens Component#touchcancel
+ * @listens Component#touchend
+ */
+ ;
+
+ _proto.emitTapEvents = function emitTapEvents() {
+ // Track the start time so we can determine how long the touch lasted
+ var touchStart = 0;
+ var firstTouch = null; // Maximum movement allowed during a touch event to still be considered a tap
+ // Other popular libs use anywhere from 2 (hammer.js) to 15,
+ // so 10 seems like a nice, round number.
+
+ var tapMovementThreshold = 10; // The maximum length a touch can be while still being considered a tap
+
+ var touchTimeThreshold = 200;
+ var couldBeTap;
+ this.on('touchstart', function (event) {
+ // If more than one finger, don't consider treating this as a click
+ if (event.touches.length === 1) {
+ // Copy pageX/pageY from the object
+ firstTouch = {
+ pageX: event.touches[0].pageX,
+ pageY: event.touches[0].pageY
+ }; // Record start time so we can detect a tap vs. "touch and hold"
+
+ touchStart = global_window__WEBPACK_IMPORTED_MODULE_0___default().performance.now(); // Reset couldBeTap tracking
+
+ couldBeTap = true;
+ }
+ });
+ this.on('touchmove', function (event) {
+ // If more than one finger, don't consider treating this as a click
+ if (event.touches.length > 1) {
+ couldBeTap = false;
+ } else if (firstTouch) {
+ // Some devices will throw touchmoves for all but the slightest of taps.
+ // So, if we moved only a small distance, this could still be a tap
+ var xdiff = event.touches[0].pageX - firstTouch.pageX;
+ var ydiff = event.touches[0].pageY - firstTouch.pageY;
+ var touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
+
+ if (touchDistance > tapMovementThreshold) {
+ couldBeTap = false;
+ }
+ }
+ });
+
+ var noTap = function noTap() {
+ couldBeTap = false;
+ }; // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s
+
+
+ this.on('touchleave', noTap);
+ this.on('touchcancel', noTap); // When the touch ends, measure how long it took and trigger the appropriate
+ // event
+
+ this.on('touchend', function (event) {
+ firstTouch = null; // Proceed only if the touchmove/leave/cancel event didn't happen
+
+ if (couldBeTap === true) {
+ // Measure how long the touch lasted
+ var touchTime = global_window__WEBPACK_IMPORTED_MODULE_0___default().performance.now() - touchStart; // Make sure the touch was less than the threshold to be considered a tap
+
+ if (touchTime < touchTimeThreshold) {
+ // Don't let browser turn this into a click
+ event.preventDefault();
+ /**
+ * Triggered when a `Component` is tapped.
+ *
+ * @event Component#tap
+ * @type {EventTarget~Event}
+ */
+
+ this.trigger('tap'); // It may be good to copy the touchend event object and change the
+ // type to tap, if the other event properties aren't exact after
+ // Events.fixEvent runs (e.g. event.target)
+ }
+ }
+ });
+ }
+ /**
+ * This function reports user activity whenever touch events happen. This can get
+ * turned off by any sub-components that wants touch events to act another way.
+ *
+ * Report user touch activity when touch events occur. User activity gets used to
+ * determine when controls should show/hide. It is simple when it comes to mouse
+ * events, because any mouse event should show the controls. So we capture mouse
+ * events that bubble up to the player and report activity when that happens.
+ * With touch events it isn't as easy as `touchstart` and `touchend` toggle player
+ * controls. So touch events can't help us at the player level either.
+ *
+ * User activity gets checked asynchronously. So what could happen is a tap event
+ * on the video turns the controls off. Then the `touchend` event bubbles up to
+ * the player. Which, if it reported user activity, would turn the controls right
+ * back on. We also don't want to completely block touch events from bubbling up.
+ * Furthermore a `touchmove` event and anything other than a tap, should not turn
+ * controls back on.
+ *
+ * @listens Component#touchstart
+ * @listens Component#touchmove
+ * @listens Component#touchend
+ * @listens Component#touchcancel
+ */
+ ;
+
+ _proto.enableTouchActivity = function enableTouchActivity() {
+ // Don't continue if the root player doesn't support reporting user activity
+ if (!this.player() || !this.player().reportUserActivity) {
+ return;
+ } // listener for reporting that the user is active
+
+
+ var report = bind(this.player(), this.player().reportUserActivity);
+ var touchHolding;
+ this.on('touchstart', function () {
+ report(); // For as long as the they are touching the device or have their mouse down,
+ // we consider them active even if they're not moving their finger or mouse.
+ // So we want to continue to update that they are active
+
+ this.clearInterval(touchHolding); // report at the same interval as activityCheck
+
+ touchHolding = this.setInterval(report, 250);
+ });
+
+ var touchEnd = function touchEnd(event) {
+ report(); // stop the interval that maintains activity if the touch is holding
+
+ this.clearInterval(touchHolding);
+ };
+
+ this.on('touchmove', report);
+ this.on('touchend', touchEnd);
+ this.on('touchcancel', touchEnd);
+ }
+ /**
+ * A callback that has no parameters and is bound into `Component`s context.
+ *
+ * @callback Component~GenericCallback
+ * @this Component
+ */
+
+ /**
+ * Creates a function that runs after an `x` millisecond timeout. This function is a
+ * wrapper around `window.setTimeout`. There are a few reasons to use this one
+ * instead though:
+ * 1. It gets cleared via {@link Component#clearTimeout} when
+ * {@link Component#dispose} gets called.
+ * 2. The function callback will gets turned into a {@link Component~GenericCallback}
+ *
+ * > Note: You can't use `window.clearTimeout` on the id returned by this function. This
+ * will cause its dispose listener not to get cleaned up! Please use
+ * {@link Component#clearTimeout} or {@link Component#dispose} instead.
+ *
+ * @param {Component~GenericCallback} fn
+ * The function that will be run after `timeout`.
+ *
+ * @param {number} timeout
+ * Timeout in milliseconds to delay before executing the specified function.
+ *
+ * @return {number}
+ * Returns a timeout ID that gets used to identify the timeout. It can also
+ * get used in {@link Component#clearTimeout} to clear the timeout that
+ * was set.
+ *
+ * @listens Component#dispose
+ * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout}
+ */
+ ;
+
+ _proto.setTimeout = function setTimeout(fn, timeout) {
+ var _this2 = this;
+
+ // declare as variables so they are properly available in timeout function
+ // eslint-disable-next-line
+ var timeoutId;
+ fn = bind(this, fn);
+ this.clearTimersOnDispose_();
+ timeoutId = global_window__WEBPACK_IMPORTED_MODULE_0___default().setTimeout(function () {
+ if (_this2.setTimeoutIds_.has(timeoutId)) {
+ _this2.setTimeoutIds_["delete"](timeoutId);
+ }
+
+ fn();
+ }, timeout);
+ this.setTimeoutIds_.add(timeoutId);
+ return timeoutId;
+ }
+ /**
+ * Clears a timeout that gets created via `window.setTimeout` or
+ * {@link Component#setTimeout}. If you set a timeout via {@link Component#setTimeout}
+ * use this function instead of `window.clearTimout`. If you don't your dispose
+ * listener will not get cleaned up until {@link Component#dispose}!
+ *
+ * @param {number} timeoutId
+ * The id of the timeout to clear. The return value of
+ * {@link Component#setTimeout} or `window.setTimeout`.
+ *
+ * @return {number}
+ * Returns the timeout id that was cleared.
+ *
+ * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout}
+ */
+ ;
+
+ _proto.clearTimeout = function clearTimeout(timeoutId) {
+ if (this.setTimeoutIds_.has(timeoutId)) {
+ this.setTimeoutIds_["delete"](timeoutId);
+ global_window__WEBPACK_IMPORTED_MODULE_0___default().clearTimeout(timeoutId);
+ }
+
+ return timeoutId;
+ }
+ /**
+ * Creates a function that gets run every `x` milliseconds. This function is a wrapper
+ * around `window.setInterval`. There are a few reasons to use this one instead though.
+ * 1. It gets cleared via {@link Component#clearInterval} when
+ * {@link Component#dispose} gets called.
+ * 2. The function callback will be a {@link Component~GenericCallback}
+ *
+ * @param {Component~GenericCallback} fn
+ * The function to run every `x` seconds.
+ *
+ * @param {number} interval
+ * Execute the specified function every `x` milliseconds.
+ *
+ * @return {number}
+ * Returns an id that can be used to identify the interval. It can also be be used in
+ * {@link Component#clearInterval} to clear the interval.
+ *
+ * @listens Component#dispose
+ * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval}
+ */
+ ;
+
+ _proto.setInterval = function setInterval(fn, interval) {
+ fn = bind(this, fn);
+ this.clearTimersOnDispose_();
+ var intervalId = global_window__WEBPACK_IMPORTED_MODULE_0___default().setInterval(fn, interval);
+ this.setIntervalIds_.add(intervalId);
+ return intervalId;
+ }
+ /**
+ * Clears an interval that gets created via `window.setInterval` or
+ * {@link Component#setInterval}. If you set an inteval via {@link Component#setInterval}
+ * use this function instead of `window.clearInterval`. If you don't your dispose
+ * listener will not get cleaned up until {@link Component#dispose}!
+ *
+ * @param {number} intervalId
+ * The id of the interval to clear. The return value of
+ * {@link Component#setInterval} or `window.setInterval`.
+ *
+ * @return {number}
+ * Returns the interval id that was cleared.
+ *
+ * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval}
+ */
+ ;
+
+ _proto.clearInterval = function clearInterval(intervalId) {
+ if (this.setIntervalIds_.has(intervalId)) {
+ this.setIntervalIds_["delete"](intervalId);
+ global_window__WEBPACK_IMPORTED_MODULE_0___default().clearInterval(intervalId);
+ }
+
+ return intervalId;
+ }
+ /**
+ * Queues up a callback to be passed to requestAnimationFrame (rAF), but
+ * with a few extra bonuses:
+ *
+ * - Supports browsers that do not support rAF by falling back to
+ * {@link Component#setTimeout}.
+ *
+ * - The callback is turned into a {@link Component~GenericCallback} (i.e.
+ * bound to the component).
+ *
+ * - Automatic cancellation of the rAF callback is handled if the component
+ * is disposed before it is called.
+ *
+ * @param {Component~GenericCallback} fn
+ * A function that will be bound to this component and executed just
+ * before the browser's next repaint.
+ *
+ * @return {number}
+ * Returns an rAF ID that gets used to identify the timeout. It can
+ * also be used in {@link Component#cancelAnimationFrame} to cancel
+ * the animation frame callback.
+ *
+ * @listens Component#dispose
+ * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame}
+ */
+ ;
+
+ _proto.requestAnimationFrame = function requestAnimationFrame(fn) {
+ var _this3 = this;
+
+ // Fall back to using a timer.
+ if (!this.supportsRaf_) {
+ return this.setTimeout(fn, 1000 / 60);
+ }
+
+ this.clearTimersOnDispose_(); // declare as variables so they are properly available in rAF function
+ // eslint-disable-next-line
+
+ var id;
+ fn = bind(this, fn);
+ id = global_window__WEBPACK_IMPORTED_MODULE_0___default().requestAnimationFrame(function () {
+ if (_this3.rafIds_.has(id)) {
+ _this3.rafIds_["delete"](id);
+ }
+
+ fn();
+ });
+ this.rafIds_.add(id);
+ return id;
+ }
+ /**
+ * Request an animation frame, but only one named animation
+ * frame will be queued. Another will never be added until
+ * the previous one finishes.
+ *
+ * @param {string} name
+ * The name to give this requestAnimationFrame
+ *
+ * @param {Component~GenericCallback} fn
+ * A function that will be bound to this component and executed just
+ * before the browser's next repaint.
+ */
+ ;
+
+ _proto.requestNamedAnimationFrame = function requestNamedAnimationFrame(name, fn) {
+ var _this4 = this;
+
+ if (this.namedRafs_.has(name)) {
+ return;
+ }
+
+ this.clearTimersOnDispose_();
+ fn = bind(this, fn);
+ var id = this.requestAnimationFrame(function () {
+ fn();
+
+ if (_this4.namedRafs_.has(name)) {
+ _this4.namedRafs_["delete"](name);
+ }
+ });
+ this.namedRafs_.set(name, id);
+ return name;
+ }
+ /**
+ * Cancels a current named animation frame if it exists.
+ *
+ * @param {string} name
+ * The name of the requestAnimationFrame to cancel.
+ */
+ ;
+
+ _proto.cancelNamedAnimationFrame = function cancelNamedAnimationFrame(name) {
+ if (!this.namedRafs_.has(name)) {
+ return;
+ }
+
+ this.cancelAnimationFrame(this.namedRafs_.get(name));
+ this.namedRafs_["delete"](name);
+ }
+ /**
+ * Cancels a queued callback passed to {@link Component#requestAnimationFrame}
+ * (rAF).
+ *
+ * If you queue an rAF callback via {@link Component#requestAnimationFrame},
+ * use this function instead of `window.cancelAnimationFrame`. If you don't,
+ * your dispose listener will not get cleaned up until {@link Component#dispose}!
+ *
+ * @param {number} id
+ * The rAF ID to clear. The return value of {@link Component#requestAnimationFrame}.
+ *
+ * @return {number}
+ * Returns the rAF ID that was cleared.
+ *
+ * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/window/cancelAnimationFrame}
+ */
+ ;
+
+ _proto.cancelAnimationFrame = function cancelAnimationFrame(id) {
+ // Fall back to using a timer.
+ if (!this.supportsRaf_) {
+ return this.clearTimeout(id);
+ }
+
+ if (this.rafIds_.has(id)) {
+ this.rafIds_["delete"](id);
+ global_window__WEBPACK_IMPORTED_MODULE_0___default().cancelAnimationFrame(id);
+ }
+
+ return id;
+ }
+ /**
+ * A function to setup `requestAnimationFrame`, `setTimeout`,
+ * and `setInterval`, clearing on dispose.
+ *
+ * > Previously each timer added and removed dispose listeners on it's own.
+ * For better performance it was decided to batch them all, and use `Set`s
+ * to track outstanding timer ids.
+ *
+ * @private
+ */
+ ;
+
+ _proto.clearTimersOnDispose_ = function clearTimersOnDispose_() {
+ var _this5 = this;
+
+ if (this.clearingTimersOnDispose_) {
+ return;
+ }
+
+ this.clearingTimersOnDispose_ = true;
+ this.one('dispose', function () {
+ [['namedRafs_', 'cancelNamedAnimationFrame'], ['rafIds_', 'cancelAnimationFrame'], ['setTimeoutIds_', 'clearTimeout'], ['setIntervalIds_', 'clearInterval']].forEach(function (_ref) {
+ var idName = _ref[0],
+ cancelName = _ref[1];
+
+ // for a `Set` key will actually be the value again
+ // so forEach((val, val) =>` but for maps we want to use
+ // the key.
+ _this5[idName].forEach(function (val, key) {
+ return _this5[cancelName](key);
+ });
+ });
+ _this5.clearingTimersOnDispose_ = false;
+ });
+ }
+ /**
+ * Register a `Component` with `videojs` given the name and the component.
+ *
+ * > NOTE: {@link Tech}s should not be registered as a `Component`. {@link Tech}s
+ * should be registered using {@link Tech.registerTech} or
+ * {@link videojs:videojs.registerTech}.
+ *
+ * > NOTE: This function can also be seen on videojs as
+ * {@link videojs:videojs.registerComponent}.
+ *
+ * @param {string} name
+ * The name of the `Component` to register.
+ *
+ * @param {Component} ComponentToRegister
+ * The `Component` class to register.
+ *
+ * @return {Component}
+ * The `Component` that was registered.
+ */
+ ;
+
+ Component.registerComponent = function registerComponent(name, ComponentToRegister) {
+ if (typeof name !== 'string' || !name) {
+ throw new Error("Illegal component name, \"" + name + "\"; must be a non-empty string.");
+ }
+
+ var Tech = Component.getComponent('Tech'); // We need to make sure this check is only done if Tech has been registered.
+
+ var isTech = Tech && Tech.isTech(ComponentToRegister);
+ var isComp = Component === ComponentToRegister || Component.prototype.isPrototypeOf(ComponentToRegister.prototype);
+
+ if (isTech || !isComp) {
+ var reason;
+
+ if (isTech) {
+ reason = 'techs must be registered using Tech.registerTech()';
+ } else {
+ reason = 'must be a Component subclass';
+ }
+
+ throw new Error("Illegal component, \"" + name + "\"; " + reason + ".");
+ }
+
+ name = toTitleCase(name);
+
+ if (!Component.components_) {
+ Component.components_ = {};
+ }
+
+ var Player = Component.getComponent('Player');
+
+ if (name === 'Player' && Player && Player.players) {
+ var players = Player.players;
+ var playerNames = Object.keys(players); // If we have players that were disposed, then their name will still be
+ // in Players.players. So, we must loop through and verify that the value
+ // for each item is not null. This allows registration of the Player component
+ // after all players have been disposed or before any were created.
+
+ if (players && playerNames.length > 0 && playerNames.map(function (pname) {
+ return players[pname];
+ }).every(Boolean)) {
+ throw new Error('Can not register Player component after player has been created.');
+ }
+ }
+
+ Component.components_[name] = ComponentToRegister;
+ Component.components_[toLowerCase(name)] = ComponentToRegister;
+ return ComponentToRegister;
+ }
+ /**
+ * Get a `Component` based on the name it was registered with.
+ *
+ * @param {string} name
+ * The Name of the component to get.
+ *
+ * @return {Component}
+ * The `Component` that got registered under the given name.
+ *
+ * @deprecated In `videojs` 6 this will not return `Component`s that were not
+ * registered using {@link Component.registerComponent}. Currently we
+ * check the global `videojs` object for a `Component` name and
+ * return that if it exists.
+ */
+ ;
+
+ Component.getComponent = function getComponent(name) {
+ if (!name || !Component.components_) {
+ return;
+ }
+
+ return Component.components_[name];
+ };
+
+ return Component;
+}();
+/**
+ * Whether or not this component supports `requestAnimationFrame`.
+ *
+ * This is exposed primarily for testing purposes.
+ *
+ * @private
+ * @type {Boolean}
+ */
+
+
+Component.prototype.supportsRaf_ = typeof (global_window__WEBPACK_IMPORTED_MODULE_0___default().requestAnimationFrame) === 'function' && typeof (global_window__WEBPACK_IMPORTED_MODULE_0___default().cancelAnimationFrame) === 'function';
+Component.registerComponent('Component', Component);
+
+/**
+ * @file browser.js
+ * @module browser
+ */
+var USER_AGENT = (global_window__WEBPACK_IMPORTED_MODULE_0___default().navigator) && (global_window__WEBPACK_IMPORTED_MODULE_0___default().navigator.userAgent) || '';
+var webkitVersionMap = /AppleWebKit\/([\d.]+)/i.exec(USER_AGENT);
+var appleWebkitVersion = webkitVersionMap ? parseFloat(webkitVersionMap.pop()) : null;
+/**
+ * Whether or not this device is an iPod.
+ *
+ * @static
+ * @const
+ * @type {Boolean}
+ */
+
+var IS_IPOD = /iPod/i.test(USER_AGENT);
+/**
+ * The detected iOS version - or `null`.
+ *
+ * @static
+ * @const
+ * @type {string|null}
+ */
+
+var IOS_VERSION = function () {
+ var match = USER_AGENT.match(/OS (\d+)_/i);
+
+ if (match && match[1]) {
+ return match[1];
+ }
+
+ return null;
+}();
+/**
+ * Whether or not this is an Android device.
+ *
+ * @static
+ * @const
+ * @type {Boolean}
+ */
+
+var IS_ANDROID = /Android/i.test(USER_AGENT);
+/**
+ * The detected Android version - or `null`.
+ *
+ * @static
+ * @const
+ * @type {number|string|null}
+ */
+
+var ANDROID_VERSION = function () {
+ // This matches Android Major.Minor.Patch versions
+ // ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned
+ var match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i);
+
+ if (!match) {
+ return null;
+ }
+
+ var major = match[1] && parseFloat(match[1]);
+ var minor = match[2] && parseFloat(match[2]);
+
+ if (major && minor) {
+ return parseFloat(match[1] + '.' + match[2]);
+ } else if (major) {
+ return major;
+ }
+
+ return null;
+}();
+/**
+ * Whether or not this is a native Android browser.
+ *
+ * @static
+ * @const
+ * @type {Boolean}
+ */
+
+var IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537;
+/**
+ * Whether or not this is Mozilla Firefox.
+ *
+ * @static
+ * @const
+ * @type {Boolean}
+ */
+
+var IS_FIREFOX = /Firefox/i.test(USER_AGENT);
+/**
+ * Whether or not this is Microsoft Edge.
+ *
+ * @static
+ * @const
+ * @type {Boolean}
+ */
+
+var IS_EDGE = /Edg/i.test(USER_AGENT);
+/**
+ * Whether or not this is Google Chrome.
+ *
+ * This will also be `true` for Chrome on iOS, which will have different support
+ * as it is actually Safari under the hood.
+ *
+ * @static
+ * @const
+ * @type {Boolean}
+ */
+
+var IS_CHROME = !IS_EDGE && (/Chrome/i.test(USER_AGENT) || /CriOS/i.test(USER_AGENT));
+/**
+ * The detected Google Chrome version - or `null`.
+ *
+ * @static
+ * @const
+ * @type {number|null}
+ */
+
+var CHROME_VERSION = function () {
+ var match = USER_AGENT.match(/(Chrome|CriOS)\/(\d+)/);
+
+ if (match && match[2]) {
+ return parseFloat(match[2]);
+ }
+
+ return null;
+}();
+/**
+ * The detected Internet Explorer version - or `null`.
+ *
+ * @static
+ * @const
+ * @type {number|null}
+ */
+
+var IE_VERSION = function () {
+ var result = /MSIE\s(\d+)\.\d/.exec(USER_AGENT);
+ var version = result && parseFloat(result[1]);
+
+ if (!version && /Trident\/7.0/i.test(USER_AGENT) && /rv:11.0/.test(USER_AGENT)) {
+ // IE 11 has a different user agent string than other IE versions
+ version = 11.0;
+ }
+
+ return version;
+}();
+/**
+ * Whether or not this is desktop Safari.
+ *
+ * @static
+ * @const
+ * @type {Boolean}
+ */
+
+var IS_SAFARI = /Safari/i.test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE;
+/**
+ * Whether or not this is a Windows machine.
+ *
+ * @static
+ * @const
+ * @type {Boolean}
+ */
+
+var IS_WINDOWS = /Windows/i.test(USER_AGENT);
+/**
+ * Whether or not this device is touch-enabled.
+ *
+ * @static
+ * @const
+ * @type {Boolean}
+ */
+
+var TOUCH_ENABLED = isReal() && ('ontouchstart' in (global_window__WEBPACK_IMPORTED_MODULE_0___default()) || (global_window__WEBPACK_IMPORTED_MODULE_0___default().navigator.maxTouchPoints) || (global_window__WEBPACK_IMPORTED_MODULE_0___default().DocumentTouch) && (global_window__WEBPACK_IMPORTED_MODULE_0___default().document) instanceof (global_window__WEBPACK_IMPORTED_MODULE_0___default().DocumentTouch));
+/**
+ * Whether or not this device is an iPad.
+ *
+ * @static
+ * @const
+ * @type {Boolean}
+ */
+
+var IS_IPAD = /iPad/i.test(USER_AGENT) || IS_SAFARI && TOUCH_ENABLED && !/iPhone/i.test(USER_AGENT);
+/**
+ * Whether or not this device is an iPhone.
+ *
+ * @static
+ * @const
+ * @type {Boolean}
+ */
+// The Facebook app's UIWebView identifies as both an iPhone and iPad, so
+// to identify iPhones, we need to exclude iPads.
+// http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/
+
+var IS_IPHONE = /iPhone/i.test(USER_AGENT) && !IS_IPAD;
+/**
+ * Whether or not this is an iOS device.
+ *
+ * @static
+ * @const
+ * @type {Boolean}
+ */
+
+var IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD;
+/**
+ * Whether or not this is any flavor of Safari - including iOS.
+ *
+ * @static
+ * @const
+ * @type {Boolean}
+ */
+
+var IS_ANY_SAFARI = (IS_SAFARI || IS_IOS) && !IS_CHROME;
+
+var browser = /*#__PURE__*/Object.freeze({
+ __proto__: null,
+ IS_IPOD: IS_IPOD,
+ IOS_VERSION: IOS_VERSION,
+ IS_ANDROID: IS_ANDROID,
+ ANDROID_VERSION: ANDROID_VERSION,
+ IS_NATIVE_ANDROID: IS_NATIVE_ANDROID,
+ IS_FIREFOX: IS_FIREFOX,
+ IS_EDGE: IS_EDGE,
+ IS_CHROME: IS_CHROME,
+ CHROME_VERSION: CHROME_VERSION,
+ IE_VERSION: IE_VERSION,
+ IS_SAFARI: IS_SAFARI,
+ IS_WINDOWS: IS_WINDOWS,
+ TOUCH_ENABLED: TOUCH_ENABLED,
+ IS_IPAD: IS_IPAD,
+ IS_IPHONE: IS_IPHONE,
+ IS_IOS: IS_IOS,
+ IS_ANY_SAFARI: IS_ANY_SAFARI
+});
+
+/**
+ * @file time-ranges.js
+ * @module time-ranges
+ */
+
+/**
+ * Returns the time for the specified index at the start or end
+ * of a TimeRange object.
+ *
+ * @typedef {Function} TimeRangeIndex
+ *
+ * @param {number} [index=0]
+ * The range number to return the time for.
+ *
+ * @return {number}
+ * The time offset at the specified index.
+ *
+ * @deprecated The index argument must be provided.
+ * In the future, leaving it out will throw an error.
+ */
+
+/**
+ * An object that contains ranges of time.
+ *
+ * @typedef {Object} TimeRange
+ *
+ * @property {number} length
+ * The number of time ranges represented by this object.
+ *
+ * @property {module:time-ranges~TimeRangeIndex} start
+ * Returns the time offset at which a specified time range begins.
+ *
+ * @property {module:time-ranges~TimeRangeIndex} end
+ * Returns the time offset at which a specified time range ends.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges
+ */
+
+/**
+ * Check if any of the time ranges are over the maximum index.
+ *
+ * @private
+ * @param {string} fnName
+ * The function name to use for logging
+ *
+ * @param {number} index
+ * The index to check
+ *
+ * @param {number} maxIndex
+ * The maximum possible index
+ *
+ * @throws {Error} if the timeRanges provided are over the maxIndex
+ */
+function rangeCheck(fnName, index, maxIndex) {
+ if (typeof index !== 'number' || index < 0 || index > maxIndex) {
+ throw new Error("Failed to execute '" + fnName + "' on 'TimeRanges': The index provided (" + index + ") is non-numeric or out of bounds (0-" + maxIndex + ").");
+ }
+}
+/**
+ * Get the time for the specified index at the start or end
+ * of a TimeRange object.
+ *
+ * @private
+ * @param {string} fnName
+ * The function name to use for logging
+ *
+ * @param {string} valueIndex
+ * The property that should be used to get the time. should be
+ * 'start' or 'end'
+ *
+ * @param {Array} ranges
+ * An array of time ranges
+ *
+ * @param {Array} [rangeIndex=0]
+ * The index to start the search at
+ *
+ * @return {number}
+ * The time that offset at the specified index.
+ *
+ * @deprecated rangeIndex must be set to a value, in the future this will throw an error.
+ * @throws {Error} if rangeIndex is more than the length of ranges
+ */
+
+
+function getRange(fnName, valueIndex, ranges, rangeIndex) {
+ rangeCheck(fnName, rangeIndex, ranges.length - 1);
+ return ranges[rangeIndex][valueIndex];
+}
+/**
+ * Create a time range object given ranges of time.
+ *
+ * @private
+ * @param {Array} [ranges]
+ * An array of time ranges.
+ */
+
+
+function createTimeRangesObj(ranges) {
+ if (ranges === undefined || ranges.length === 0) {
+ return {
+ length: 0,
+ start: function start() {
+ throw new Error('This TimeRanges object is empty');
+ },
+ end: function end() {
+ throw new Error('This TimeRanges object is empty');
+ }
+ };
+ }
+
+ return {
+ length: ranges.length,
+ start: getRange.bind(null, 'start', 0, ranges),
+ end: getRange.bind(null, 'end', 1, ranges)
+ };
+}
+/**
+ * Create a `TimeRange` object which mimics an
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges|HTML5 TimeRanges instance}.
+ *
+ * @param {number|Array[]} start
+ * The start of a single range (a number) or an array of ranges (an
+ * array of arrays of two numbers each).
+ *
+ * @param {number} end
+ * The end of a single range. Cannot be used with the array form of
+ * the `start` argument.
+ */
+
+
+function createTimeRanges(start, end) {
+ if (Array.isArray(start)) {
+ return createTimeRangesObj(start);
+ } else if (start === undefined || end === undefined) {
+ return createTimeRangesObj();
+ }
+
+ return createTimeRangesObj([[start, end]]);
+}
+
+/**
+ * @file buffer.js
+ * @module buffer
+ */
+/**
+ * Compute the percentage of the media that has been buffered.
+ *
+ * @param {TimeRange} buffered
+ * The current `TimeRange` object representing buffered time ranges
+ *
+ * @param {number} duration
+ * Total duration of the media
+ *
+ * @return {number}
+ * Percent buffered of the total duration in decimal form.
+ */
+
+function bufferedPercent(buffered, duration) {
+ var bufferedDuration = 0;
+ var start;
+ var end;
+
+ if (!duration) {
+ return 0;
+ }
+
+ if (!buffered || !buffered.length) {
+ buffered = createTimeRanges(0, 0);
+ }
+
+ for (var i = 0; i < buffered.length; i++) {
+ start = buffered.start(i);
+ end = buffered.end(i); // buffered end can be bigger than duration by a very small fraction
+
+ if (end > duration) {
+ end = duration;
+ }
+
+ bufferedDuration += end - start;
+ }
+
+ return bufferedDuration / duration;
+}
+
+/**
+ * @file fullscreen-api.js
+ * @module fullscreen-api
+ * @private
+ */
+/**
+ * Store the browser-specific methods for the fullscreen API.
+ *
+ * @type {Object}
+ * @see [Specification]{@link https://fullscreen.spec.whatwg.org}
+ * @see [Map Approach From Screenfull.js]{@link https://github.com/sindresorhus/screenfull.js}
+ */
+
+var FullscreenApi = {
+ prefixed: true
+}; // browser API methods
+
+var apiMap = [['requestFullscreen', 'exitFullscreen', 'fullscreenElement', 'fullscreenEnabled', 'fullscreenchange', 'fullscreenerror', 'fullscreen'], // WebKit
+['webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitFullscreenElement', 'webkitFullscreenEnabled', 'webkitfullscreenchange', 'webkitfullscreenerror', '-webkit-full-screen'], // Mozilla
+['mozRequestFullScreen', 'mozCancelFullScreen', 'mozFullScreenElement', 'mozFullScreenEnabled', 'mozfullscreenchange', 'mozfullscreenerror', '-moz-full-screen'], // Microsoft
+['msRequestFullscreen', 'msExitFullscreen', 'msFullscreenElement', 'msFullscreenEnabled', 'MSFullscreenChange', 'MSFullscreenError', '-ms-fullscreen']];
+var specApi = apiMap[0];
+var browserApi; // determine the supported set of functions
+
+for (var i = 0; i < apiMap.length; i++) {
+ // check for exitFullscreen function
+ if (apiMap[i][1] in (global_document__WEBPACK_IMPORTED_MODULE_1___default())) {
+ browserApi = apiMap[i];
+ break;
+ }
+} // map the browser API names to the spec API names
+
+
+if (browserApi) {
+ for (var _i = 0; _i < browserApi.length; _i++) {
+ FullscreenApi[specApi[_i]] = browserApi[_i];
+ }
+
+ FullscreenApi.prefixed = browserApi[0] !== specApi[0];
+}
+
+/**
+ * @file media-error.js
+ */
+/**
+ * A Custom `MediaError` class which mimics the standard HTML5 `MediaError` class.
+ *
+ * @param {number|string|Object|MediaError} value
+ * This can be of multiple types:
+ * - number: should be a standard error code
+ * - string: an error message (the code will be 0)
+ * - Object: arbitrary properties
+ * - `MediaError` (native): used to populate a video.js `MediaError` object
+ * - `MediaError` (video.js): will return itself if it's already a
+ * video.js `MediaError` object.
+ *
+ * @see [MediaError Spec]{@link https://dev.w3.org/html5/spec-author-view/video.html#mediaerror}
+ * @see [Encrypted MediaError Spec]{@link https://www.w3.org/TR/2013/WD-encrypted-media-20130510/#error-codes}
+ *
+ * @class MediaError
+ */
+
+function MediaError(value) {
+ // Allow redundant calls to this constructor to avoid having `instanceof`
+ // checks peppered around the code.
+ if (value instanceof MediaError) {
+ return value;
+ }
+
+ if (typeof value === 'number') {
+ this.code = value;
+ } else if (typeof value === 'string') {
+ // default code is zero, so this is a custom error
+ this.message = value;
+ } else if (isObject(value)) {
+ // We assign the `code` property manually because native `MediaError` objects
+ // do not expose it as an own/enumerable property of the object.
+ if (typeof value.code === 'number') {
+ this.code = value.code;
+ }
+
+ assign(this, value);
+ }
+
+ if (!this.message) {
+ this.message = MediaError.defaultMessages[this.code] || '';
+ }
+}
+/**
+ * The error code that refers two one of the defined `MediaError` types
+ *
+ * @type {Number}
+ */
+
+
+MediaError.prototype.code = 0;
+/**
+ * An optional message that to show with the error. Message is not part of the HTML5
+ * video spec but allows for more informative custom errors.
+ *
+ * @type {String}
+ */
+
+MediaError.prototype.message = '';
+/**
+ * An optional status code that can be set by plugins to allow even more detail about
+ * the error. For example a plugin might provide a specific HTTP status code and an
+ * error message for that code. Then when the plugin gets that error this class will
+ * know how to display an error message for it. This allows a custom message to show
+ * up on the `Player` error overlay.
+ *
+ * @type {Array}
+ */
+
+MediaError.prototype.status = null;
+/**
+ * Errors indexed by the W3C standard. The order **CANNOT CHANGE**! See the
+ * specification listed under {@link MediaError} for more information.
+ *
+ * @enum {array}
+ * @readonly
+ * @property {string} 0 - MEDIA_ERR_CUSTOM
+ * @property {string} 1 - MEDIA_ERR_ABORTED
+ * @property {string} 2 - MEDIA_ERR_NETWORK
+ * @property {string} 3 - MEDIA_ERR_DECODE
+ * @property {string} 4 - MEDIA_ERR_SRC_NOT_SUPPORTED
+ * @property {string} 5 - MEDIA_ERR_ENCRYPTED
+ */
+
+MediaError.errorTypes = ['MEDIA_ERR_CUSTOM', 'MEDIA_ERR_ABORTED', 'MEDIA_ERR_NETWORK', 'MEDIA_ERR_DECODE', 'MEDIA_ERR_SRC_NOT_SUPPORTED', 'MEDIA_ERR_ENCRYPTED'];
+/**
+ * The default `MediaError` messages based on the {@link MediaError.errorTypes}.
+ *
+ * @type {Array}
+ * @constant
+ */
+
+MediaError.defaultMessages = {
+ 1: 'You aborted the media playback',
+ 2: 'A network error caused the media download to fail part-way.',
+ 3: 'The media playback was aborted due to a corruption problem or because the media used features your browser did not support.',
+ 4: 'The media could not be loaded, either because the server or network failed or because the format is not supported.',
+ 5: 'The media is encrypted and we do not have the keys to decrypt it.'
+}; // Add types as properties on MediaError
+// e.g. MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = 4;
+
+for (var errNum = 0; errNum < MediaError.errorTypes.length; errNum++) {
+ MediaError[MediaError.errorTypes[errNum]] = errNum; // values should be accessible on both the class and instance
+
+ MediaError.prototype[MediaError.errorTypes[errNum]] = errNum;
+} // jsdocs for instance/static members added above
+
+/**
+ * Returns whether an object is `Promise`-like (i.e. has a `then` method).
+ *
+ * @param {Object} value
+ * An object that may or may not be `Promise`-like.
+ *
+ * @return {boolean}
+ * Whether or not the object is `Promise`-like.
+ */
+function isPromise(value) {
+ return value !== undefined && value !== null && typeof value.then === 'function';
+}
+/**
+ * Silence a Promise-like object.
+ *
+ * This is useful for avoiding non-harmful, but potentially confusing "uncaught
+ * play promise" rejection error messages.
+ *
+ * @param {Object} value
+ * An object that may or may not be `Promise`-like.
+ */
+
+function silencePromise(value) {
+ if (isPromise(value)) {
+ value.then(null, function (e) {});
+ }
+}
+
+/**
+ * @file text-track-list-converter.js Utilities for capturing text track state and
+ * re-creating tracks based on a capture.
+ *
+ * @module text-track-list-converter
+ */
+
+/**
+ * Examine a single {@link TextTrack} and return a JSON-compatible javascript object that
+ * represents the {@link TextTrack}'s state.
+ *
+ * @param {TextTrack} track
+ * The text track to query.
+ *
+ * @return {Object}
+ * A serializable javascript representation of the TextTrack.
+ * @private
+ */
+var trackToJson_ = function trackToJson_(track) {
+ var ret = ['kind', 'label', 'language', 'id', 'inBandMetadataTrackDispatchType', 'mode', 'src'].reduce(function (acc, prop, i) {
+ if (track[prop]) {
+ acc[prop] = track[prop];
+ }
+
+ return acc;
+ }, {
+ cues: track.cues && Array.prototype.map.call(track.cues, function (cue) {
+ return {
+ startTime: cue.startTime,
+ endTime: cue.endTime,
+ text: cue.text,
+ id: cue.id
+ };
+ })
+ });
+ return ret;
+};
+/**
+ * Examine a {@link Tech} and return a JSON-compatible javascript array that represents the
+ * state of all {@link TextTrack}s currently configured. The return array is compatible with
+ * {@link text-track-list-converter:jsonToTextTracks}.
+ *
+ * @param {Tech} tech
+ * The tech object to query
+ *
+ * @return {Array}
+ * A serializable javascript representation of the {@link Tech}s
+ * {@link TextTrackList}.
+ */
+
+
+var textTracksToJson = function textTracksToJson(tech) {
+ var trackEls = tech.$$('track');
+ var trackObjs = Array.prototype.map.call(trackEls, function (t) {
+ return t.track;
+ });
+ var tracks = Array.prototype.map.call(trackEls, function (trackEl) {
+ var json = trackToJson_(trackEl.track);
+
+ if (trackEl.src) {
+ json.src = trackEl.src;
+ }
+
+ return json;
+ });
+ return tracks.concat(Array.prototype.filter.call(tech.textTracks(), function (track) {
+ return trackObjs.indexOf(track) === -1;
+ }).map(trackToJson_));
+};
+/**
+ * Create a set of remote {@link TextTrack}s on a {@link Tech} based on an array of javascript
+ * object {@link TextTrack} representations.
+ *
+ * @param {Array} json
+ * An array of `TextTrack` representation objects, like those that would be
+ * produced by `textTracksToJson`.
+ *
+ * @param {Tech} tech
+ * The `Tech` to create the `TextTrack`s on.
+ */
+
+
+var jsonToTextTracks = function jsonToTextTracks(json, tech) {
+ json.forEach(function (track) {
+ var addedTrack = tech.addRemoteTextTrack(track).track;
+
+ if (!track.src && track.cues) {
+ track.cues.forEach(function (cue) {
+ return addedTrack.addCue(cue);
+ });
+ }
+ });
+ return tech.textTracks();
+};
+
+var textTrackConverter = {
+ textTracksToJson: textTracksToJson,
+ jsonToTextTracks: jsonToTextTracks,
+ trackToJson_: trackToJson_
+};
+
+var MODAL_CLASS_NAME = 'vjs-modal-dialog';
+/**
+ * The `ModalDialog` displays over the video and its controls, which blocks
+ * interaction with the player until it is closed.
+ *
+ * Modal dialogs include a "Close" button and will close when that button
+ * is activated - or when ESC is pressed anywhere.
+ *
+ * @extends Component
+ */
+
+var ModalDialog = /*#__PURE__*/function (_Component) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6___default()(ModalDialog, _Component);
+
+ /**
+ * Create an instance of this class.
+ *
+ * @param {Player} player
+ * The `Player` that this class should be attached to.
+ *
+ * @param {Object} [options]
+ * The key/value store of player options.
+ *
+ * @param {Mixed} [options.content=undefined]
+ * Provide customized content for this modal.
+ *
+ * @param {string} [options.description]
+ * A text description for the modal, primarily for accessibility.
+ *
+ * @param {boolean} [options.fillAlways=false]
+ * Normally, modals are automatically filled only the first time
+ * they open. This tells the modal to refresh its content
+ * every time it opens.
+ *
+ * @param {string} [options.label]
+ * A text label for the modal, primarily for accessibility.
+ *
+ * @param {boolean} [options.pauseOnOpen=true]
+ * If `true`, playback will will be paused if playing when
+ * the modal opens, and resumed when it closes.
+ *
+ * @param {boolean} [options.temporary=true]
+ * If `true`, the modal can only be opened once; it will be
+ * disposed as soon as it's closed.
+ *
+ * @param {boolean} [options.uncloseable=false]
+ * If `true`, the user will not be able to close the modal
+ * through the UI in the normal ways. Programmatic closing is
+ * still possible.
+ */
+ function ModalDialog(player, options) {
+ var _this;
+
+ _this = _Component.call(this, player, options) || this;
+ _this.opened_ = _this.hasBeenOpened_ = _this.hasBeenFilled_ = false;
+
+ _this.closeable(!_this.options_.uncloseable);
+
+ _this.content(_this.options_.content); // Make sure the contentEl is defined AFTER any children are initialized
+ // because we only want the contents of the modal in the contentEl
+ // (not the UI elements like the close button).
+
+
+ _this.contentEl_ = createEl('div', {
+ className: MODAL_CLASS_NAME + "-content"
+ }, {
+ role: 'document'
+ });
+ _this.descEl_ = createEl('p', {
+ className: MODAL_CLASS_NAME + "-description vjs-control-text",
+ id: _this.el().getAttribute('aria-describedby')
+ });
+ textContent(_this.descEl_, _this.description());
+
+ _this.el_.appendChild(_this.descEl_);
+
+ _this.el_.appendChild(_this.contentEl_);
+
+ return _this;
+ }
+ /**
+ * Create the `ModalDialog`'s DOM element
+ *
+ * @return {Element}
+ * The DOM element that gets created.
+ */
+
+
+ var _proto = ModalDialog.prototype;
+
+ _proto.createEl = function createEl() {
+ return _Component.prototype.createEl.call(this, 'div', {
+ className: this.buildCSSClass(),
+ tabIndex: -1
+ }, {
+ 'aria-describedby': this.id() + "_description",
+ 'aria-hidden': 'true',
+ 'aria-label': this.label(),
+ 'role': 'dialog'
+ });
+ };
+
+ _proto.dispose = function dispose() {
+ this.contentEl_ = null;
+ this.descEl_ = null;
+ this.previouslyActiveEl_ = null;
+
+ _Component.prototype.dispose.call(this);
+ }
+ /**
+ * Builds the default DOM `className`.
+ *
+ * @return {string}
+ * The DOM `className` for this object.
+ */
+ ;
+
+ _proto.buildCSSClass = function buildCSSClass() {
+ return MODAL_CLASS_NAME + " vjs-hidden " + _Component.prototype.buildCSSClass.call(this);
+ }
+ /**
+ * Returns the label string for this modal. Primarily used for accessibility.
+ *
+ * @return {string}
+ * the localized or raw label of this modal.
+ */
+ ;
+
+ _proto.label = function label() {
+ return this.localize(this.options_.label || 'Modal Window');
+ }
+ /**
+ * Returns the description string for this modal. Primarily used for
+ * accessibility.
+ *
+ * @return {string}
+ * The localized or raw description of this modal.
+ */
+ ;
+
+ _proto.description = function description() {
+ var desc = this.options_.description || this.localize('This is a modal window.'); // Append a universal closeability message if the modal is closeable.
+
+ if (this.closeable()) {
+ desc += ' ' + this.localize('This modal can be closed by pressing the Escape key or activating the close button.');
+ }
+
+ return desc;
+ }
+ /**
+ * Opens the modal.
+ *
+ * @fires ModalDialog#beforemodalopen
+ * @fires ModalDialog#modalopen
+ */
+ ;
+
+ _proto.open = function open() {
+ if (!this.opened_) {
+ var player = this.player();
+ /**
+ * Fired just before a `ModalDialog` is opened.
+ *
+ * @event ModalDialog#beforemodalopen
+ * @type {EventTarget~Event}
+ */
+
+ this.trigger('beforemodalopen');
+ this.opened_ = true; // Fill content if the modal has never opened before and
+ // never been filled.
+
+ if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) {
+ this.fill();
+ } // If the player was playing, pause it and take note of its previously
+ // playing state.
+
+
+ this.wasPlaying_ = !player.paused();
+
+ if (this.options_.pauseOnOpen && this.wasPlaying_) {
+ player.pause();
+ }
+
+ this.on('keydown', this.handleKeyDown); // Hide controls and note if they were enabled.
+
+ this.hadControls_ = player.controls();
+ player.controls(false);
+ this.show();
+ this.conditionalFocus_();
+ this.el().setAttribute('aria-hidden', 'false');
+ /**
+ * Fired just after a `ModalDialog` is opened.
+ *
+ * @event ModalDialog#modalopen
+ * @type {EventTarget~Event}
+ */
+
+ this.trigger('modalopen');
+ this.hasBeenOpened_ = true;
+ }
+ }
+ /**
+ * If the `ModalDialog` is currently open or closed.
+ *
+ * @param {boolean} [value]
+ * If given, it will open (`true`) or close (`false`) the modal.
+ *
+ * @return {boolean}
+ * the current open state of the modaldialog
+ */
+ ;
+
+ _proto.opened = function opened(value) {
+ if (typeof value === 'boolean') {
+ this[value ? 'open' : 'close']();
+ }
+
+ return this.opened_;
+ }
+ /**
+ * Closes the modal, does nothing if the `ModalDialog` is
+ * not open.
+ *
+ * @fires ModalDialog#beforemodalclose
+ * @fires ModalDialog#modalclose
+ */
+ ;
+
+ _proto.close = function close() {
+ if (!this.opened_) {
+ return;
+ }
+
+ var player = this.player();
+ /**
+ * Fired just before a `ModalDialog` is closed.
+ *
+ * @event ModalDialog#beforemodalclose
+ * @type {EventTarget~Event}
+ */
+
+ this.trigger('beforemodalclose');
+ this.opened_ = false;
+
+ if (this.wasPlaying_ && this.options_.pauseOnOpen) {
+ player.play();
+ }
+
+ this.off('keydown', this.handleKeyDown);
+
+ if (this.hadControls_) {
+ player.controls(true);
+ }
+
+ this.hide();
+ this.el().setAttribute('aria-hidden', 'true');
+ /**
+ * Fired just after a `ModalDialog` is closed.
+ *
+ * @event ModalDialog#modalclose
+ * @type {EventTarget~Event}
+ */
+
+ this.trigger('modalclose');
+ this.conditionalBlur_();
+
+ if (this.options_.temporary) {
+ this.dispose();
+ }
+ }
+ /**
+ * Check to see if the `ModalDialog` is closeable via the UI.
+ *
+ * @param {boolean} [value]
+ * If given as a boolean, it will set the `closeable` option.
+ *
+ * @return {boolean}
+ * Returns the final value of the closable option.
+ */
+ ;
+
+ _proto.closeable = function closeable(value) {
+ if (typeof value === 'boolean') {
+ var closeable = this.closeable_ = !!value;
+ var close = this.getChild('closeButton'); // If this is being made closeable and has no close button, add one.
+
+ if (closeable && !close) {
+ // The close button should be a child of the modal - not its
+ // content element, so temporarily change the content element.
+ var temp = this.contentEl_;
+ this.contentEl_ = this.el_;
+ close = this.addChild('closeButton', {
+ controlText: 'Close Modal Dialog'
+ });
+ this.contentEl_ = temp;
+ this.on(close, 'close', this.close);
+ } // If this is being made uncloseable and has a close button, remove it.
+
+
+ if (!closeable && close) {
+ this.off(close, 'close', this.close);
+ this.removeChild(close);
+ close.dispose();
+ }
+ }
+
+ return this.closeable_;
+ }
+ /**
+ * Fill the modal's content element with the modal's "content" option.
+ * The content element will be emptied before this change takes place.
+ */
+ ;
+
+ _proto.fill = function fill() {
+ this.fillWith(this.content());
+ }
+ /**
+ * Fill the modal's content element with arbitrary content.
+ * The content element will be emptied before this change takes place.
+ *
+ * @fires ModalDialog#beforemodalfill
+ * @fires ModalDialog#modalfill
+ *
+ * @param {Mixed} [content]
+ * The same rules apply to this as apply to the `content` option.
+ */
+ ;
+
+ _proto.fillWith = function fillWith(content) {
+ var contentEl = this.contentEl();
+ var parentEl = contentEl.parentNode;
+ var nextSiblingEl = contentEl.nextSibling;
+ /**
+ * Fired just before a `ModalDialog` is filled with content.
+ *
+ * @event ModalDialog#beforemodalfill
+ * @type {EventTarget~Event}
+ */
+
+ this.trigger('beforemodalfill');
+ this.hasBeenFilled_ = true; // Detach the content element from the DOM before performing
+ // manipulation to avoid modifying the live DOM multiple times.
+
+ parentEl.removeChild(contentEl);
+ this.empty();
+ insertContent(contentEl, content);
+ /**
+ * Fired just after a `ModalDialog` is filled with content.
+ *
+ * @event ModalDialog#modalfill
+ * @type {EventTarget~Event}
+ */
+
+ this.trigger('modalfill'); // Re-inject the re-filled content element.
+
+ if (nextSiblingEl) {
+ parentEl.insertBefore(contentEl, nextSiblingEl);
+ } else {
+ parentEl.appendChild(contentEl);
+ } // make sure that the close button is last in the dialog DOM
+
+
+ var closeButton = this.getChild('closeButton');
+
+ if (closeButton) {
+ parentEl.appendChild(closeButton.el_);
+ }
+ }
+ /**
+ * Empties the content element. This happens anytime the modal is filled.
+ *
+ * @fires ModalDialog#beforemodalempty
+ * @fires ModalDialog#modalempty
+ */
+ ;
+
+ _proto.empty = function empty() {
+ /**
+ * Fired just before a `ModalDialog` is emptied.
+ *
+ * @event ModalDialog#beforemodalempty
+ * @type {EventTarget~Event}
+ */
+ this.trigger('beforemodalempty');
+ emptyEl(this.contentEl());
+ /**
+ * Fired just after a `ModalDialog` is emptied.
+ *
+ * @event ModalDialog#modalempty
+ * @type {EventTarget~Event}
+ */
+
+ this.trigger('modalempty');
+ }
+ /**
+ * Gets or sets the modal content, which gets normalized before being
+ * rendered into the DOM.
+ *
+ * This does not update the DOM or fill the modal, but it is called during
+ * that process.
+ *
+ * @param {Mixed} [value]
+ * If defined, sets the internal content value to be used on the
+ * next call(s) to `fill`. This value is normalized before being
+ * inserted. To "clear" the internal content value, pass `null`.
+ *
+ * @return {Mixed}
+ * The current content of the modal dialog
+ */
+ ;
+
+ _proto.content = function content(value) {
+ if (typeof value !== 'undefined') {
+ this.content_ = value;
+ }
+
+ return this.content_;
+ }
+ /**
+ * conditionally focus the modal dialog if focus was previously on the player.
+ *
+ * @private
+ */
+ ;
+
+ _proto.conditionalFocus_ = function conditionalFocus_() {
+ var activeEl = (global_document__WEBPACK_IMPORTED_MODULE_1___default().activeElement);
+ var playerEl = this.player_.el_;
+ this.previouslyActiveEl_ = null;
+
+ if (playerEl.contains(activeEl) || playerEl === activeEl) {
+ this.previouslyActiveEl_ = activeEl;
+ this.focus();
+ }
+ }
+ /**
+ * conditionally blur the element and refocus the last focused element
+ *
+ * @private
+ */
+ ;
+
+ _proto.conditionalBlur_ = function conditionalBlur_() {
+ if (this.previouslyActiveEl_) {
+ this.previouslyActiveEl_.focus();
+ this.previouslyActiveEl_ = null;
+ }
+ }
+ /**
+ * Keydown handler. Attached when modal is focused.
+ *
+ * @listens keydown
+ */
+ ;
+
+ _proto.handleKeyDown = function handleKeyDown(event) {
+ // Do not allow keydowns to reach out of the modal dialog.
+ event.stopPropagation();
+
+ if (keycode__WEBPACK_IMPORTED_MODULE_8___default().isEventKey(event, 'Escape') && this.closeable()) {
+ event.preventDefault();
+ this.close();
+ return;
+ } // exit early if it isn't a tab key
+
+
+ if (!keycode__WEBPACK_IMPORTED_MODULE_8___default().isEventKey(event, 'Tab')) {
+ return;
+ }
+
+ var focusableEls = this.focusableEls_();
+ var activeEl = this.el_.querySelector(':focus');
+ var focusIndex;
+
+ for (var i = 0; i < focusableEls.length; i++) {
+ if (activeEl === focusableEls[i]) {
+ focusIndex = i;
+ break;
+ }
+ }
+
+ if ((global_document__WEBPACK_IMPORTED_MODULE_1___default().activeElement) === this.el_) {
+ focusIndex = 0;
+ }
+
+ if (event.shiftKey && focusIndex === 0) {
+ focusableEls[focusableEls.length - 1].focus();
+ event.preventDefault();
+ } else if (!event.shiftKey && focusIndex === focusableEls.length - 1) {
+ focusableEls[0].focus();
+ event.preventDefault();
+ }
+ }
+ /**
+ * get all focusable elements
+ *
+ * @private
+ */
+ ;
+
+ _proto.focusableEls_ = function focusableEls_() {
+ var allChildren = this.el_.querySelectorAll('*');
+ return Array.prototype.filter.call(allChildren, function (child) {
+ return (child instanceof (global_window__WEBPACK_IMPORTED_MODULE_0___default().HTMLAnchorElement) || child instanceof (global_window__WEBPACK_IMPORTED_MODULE_0___default().HTMLAreaElement)) && child.hasAttribute('href') || (child instanceof (global_window__WEBPACK_IMPORTED_MODULE_0___default().HTMLInputElement) || child instanceof (global_window__WEBPACK_IMPORTED_MODULE_0___default().HTMLSelectElement) || child instanceof (global_window__WEBPACK_IMPORTED_MODULE_0___default().HTMLTextAreaElement) || child instanceof (global_window__WEBPACK_IMPORTED_MODULE_0___default().HTMLButtonElement)) && !child.hasAttribute('disabled') || child instanceof (global_window__WEBPACK_IMPORTED_MODULE_0___default().HTMLIFrameElement) || child instanceof (global_window__WEBPACK_IMPORTED_MODULE_0___default().HTMLObjectElement) || child instanceof (global_window__WEBPACK_IMPORTED_MODULE_0___default().HTMLEmbedElement) || child.hasAttribute('tabindex') && child.getAttribute('tabindex') !== -1 || child.hasAttribute('contenteditable');
+ });
+ };
+
+ return ModalDialog;
+}(Component);
+/**
+ * Default options for `ModalDialog` default options.
+ *
+ * @type {Object}
+ * @private
+ */
+
+
+ModalDialog.prototype.options_ = {
+ pauseOnOpen: true,
+ temporary: true
+};
+Component.registerComponent('ModalDialog', ModalDialog);
+
+/**
+ * Common functionaliy between {@link TextTrackList}, {@link AudioTrackList}, and
+ * {@link VideoTrackList}
+ *
+ * @extends EventTarget
+ */
+
+var TrackList = /*#__PURE__*/function (_EventTarget) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6___default()(TrackList, _EventTarget);
+
+ /**
+ * Create an instance of this class
+ *
+ * @param {Track[]} tracks
+ * A list of tracks to initialize the list with.
+ *
+ * @abstract
+ */
+ function TrackList(tracks) {
+ var _this;
+
+ if (tracks === void 0) {
+ tracks = [];
+ }
+
+ _this = _EventTarget.call(this) || this;
+ _this.tracks_ = [];
+ /**
+ * @memberof TrackList
+ * @member {number} length
+ * The current number of `Track`s in the this Trackist.
+ * @instance
+ */
+
+ Object.defineProperty(_babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3___default()(_this), 'length', {
+ get: function get() {
+ return this.tracks_.length;
+ }
+ });
+
+ for (var i = 0; i < tracks.length; i++) {
+ _this.addTrack(tracks[i]);
+ }
+
+ return _this;
+ }
+ /**
+ * Add a {@link Track} to the `TrackList`
+ *
+ * @param {Track} track
+ * The audio, video, or text track to add to the list.
+ *
+ * @fires TrackList#addtrack
+ */
+
+
+ var _proto = TrackList.prototype;
+
+ _proto.addTrack = function addTrack(track) {
+ var index = this.tracks_.length;
+
+ if (!('' + index in this)) {
+ Object.defineProperty(this, index, {
+ get: function get() {
+ return this.tracks_[index];
+ }
+ });
+ } // Do not add duplicate tracks
+
+
+ if (this.tracks_.indexOf(track) === -1) {
+ this.tracks_.push(track);
+ /**
+ * Triggered when a track is added to a track list.
+ *
+ * @event TrackList#addtrack
+ * @type {EventTarget~Event}
+ * @property {Track} track
+ * A reference to track that was added.
+ */
+
+ this.trigger({
+ track: track,
+ type: 'addtrack',
+ target: this
+ });
+ }
+ }
+ /**
+ * Remove a {@link Track} from the `TrackList`
+ *
+ * @param {Track} rtrack
+ * The audio, video, or text track to remove from the list.
+ *
+ * @fires TrackList#removetrack
+ */
+ ;
+
+ _proto.removeTrack = function removeTrack(rtrack) {
+ var track;
+
+ for (var i = 0, l = this.length; i < l; i++) {
+ if (this[i] === rtrack) {
+ track = this[i];
+
+ if (track.off) {
+ track.off();
+ }
+
+ this.tracks_.splice(i, 1);
+ break;
+ }
+ }
+
+ if (!track) {
+ return;
+ }
+ /**
+ * Triggered when a track is removed from track list.
+ *
+ * @event TrackList#removetrack
+ * @type {EventTarget~Event}
+ * @property {Track} track
+ * A reference to track that was removed.
+ */
+
+
+ this.trigger({
+ track: track,
+ type: 'removetrack',
+ target: this
+ });
+ }
+ /**
+ * Get a Track from the TrackList by a tracks id
+ *
+ * @param {string} id - the id of the track to get
+ * @method getTrackById
+ * @return {Track}
+ * @private
+ */
+ ;
+
+ _proto.getTrackById = function getTrackById(id) {
+ var result = null;
+
+ for (var i = 0, l = this.length; i < l; i++) {
+ var track = this[i];
+
+ if (track.id === id) {
+ result = track;
+ break;
+ }
+ }
+
+ return result;
+ };
+
+ return TrackList;
+}(EventTarget);
+/**
+ * Triggered when a different track is selected/enabled.
+ *
+ * @event TrackList#change
+ * @type {EventTarget~Event}
+ */
+
+/**
+ * Events that can be called with on + eventName. See {@link EventHandler}.
+ *
+ * @property {Object} TrackList#allowedEvents_
+ * @private
+ */
+
+
+TrackList.prototype.allowedEvents_ = {
+ change: 'change',
+ addtrack: 'addtrack',
+ removetrack: 'removetrack'
+}; // emulate attribute EventHandler support to allow for feature detection
+
+for (var event in TrackList.prototype.allowedEvents_) {
+ TrackList.prototype['on' + event] = null;
+}
+
+/**
+ * Anywhere we call this function we diverge from the spec
+ * as we only support one enabled audiotrack at a time
+ *
+ * @param {AudioTrackList} list
+ * list to work on
+ *
+ * @param {AudioTrack} track
+ * The track to skip
+ *
+ * @private
+ */
+
+var disableOthers = function disableOthers(list, track) {
+ for (var i = 0; i < list.length; i++) {
+ if (!Object.keys(list[i]).length || track.id === list[i].id) {
+ continue;
+ } // another audio track is enabled, disable it
+
+
+ list[i].enabled = false;
+ }
+};
+/**
+ * The current list of {@link AudioTrack} for a media file.
+ *
+ * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist}
+ * @extends TrackList
+ */
+
+
+var AudioTrackList = /*#__PURE__*/function (_TrackList) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6___default()(AudioTrackList, _TrackList);
+
+ /**
+ * Create an instance of this class.
+ *
+ * @param {AudioTrack[]} [tracks=[]]
+ * A list of `AudioTrack` to instantiate the list with.
+ */
+ function AudioTrackList(tracks) {
+ var _this;
+
+ if (tracks === void 0) {
+ tracks = [];
+ }
+
+ // make sure only 1 track is enabled
+ // sorted from last index to first index
+ for (var i = tracks.length - 1; i >= 0; i--) {
+ if (tracks[i].enabled) {
+ disableOthers(tracks, tracks[i]);
+ break;
+ }
+ }
+
+ _this = _TrackList.call(this, tracks) || this;
+ _this.changing_ = false;
+ return _this;
+ }
+ /**
+ * Add an {@link AudioTrack} to the `AudioTrackList`.
+ *
+ * @param {AudioTrack} track
+ * The AudioTrack to add to the list
+ *
+ * @fires TrackList#addtrack
+ */
+
+
+ var _proto = AudioTrackList.prototype;
+
+ _proto.addTrack = function addTrack(track) {
+ var _this2 = this;
+
+ if (track.enabled) {
+ disableOthers(this, track);
+ }
+
+ _TrackList.prototype.addTrack.call(this, track); // native tracks don't have this
+
+
+ if (!track.addEventListener) {
+ return;
+ }
+
+ track.enabledChange_ = function () {
+ // when we are disabling other tracks (since we don't support
+ // more than one track at a time) we will set changing_
+ // to true so that we don't trigger additional change events
+ if (_this2.changing_) {
+ return;
+ }
+
+ _this2.changing_ = true;
+ disableOthers(_this2, track);
+ _this2.changing_ = false;
+
+ _this2.trigger('change');
+ };
+ /**
+ * @listens AudioTrack#enabledchange
+ * @fires TrackList#change
+ */
+
+
+ track.addEventListener('enabledchange', track.enabledChange_);
+ };
+
+ _proto.removeTrack = function removeTrack(rtrack) {
+ _TrackList.prototype.removeTrack.call(this, rtrack);
+
+ if (rtrack.removeEventListener && rtrack.enabledChange_) {
+ rtrack.removeEventListener('enabledchange', rtrack.enabledChange_);
+ rtrack.enabledChange_ = null;
+ }
+ };
+
+ return AudioTrackList;
+}(TrackList);
+
+/**
+ * Un-select all other {@link VideoTrack}s that are selected.
+ *
+ * @param {VideoTrackList} list
+ * list to work on
+ *
+ * @param {VideoTrack} track
+ * The track to skip
+ *
+ * @private
+ */
+
+var disableOthers$1 = function disableOthers(list, track) {
+ for (var i = 0; i < list.length; i++) {
+ if (!Object.keys(list[i]).length || track.id === list[i].id) {
+ continue;
+ } // another video track is enabled, disable it
+
+
+ list[i].selected = false;
+ }
+};
+/**
+ * The current list of {@link VideoTrack} for a video.
+ *
+ * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist}
+ * @extends TrackList
+ */
+
+
+var VideoTrackList = /*#__PURE__*/function (_TrackList) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6___default()(VideoTrackList, _TrackList);
+
+ /**
+ * Create an instance of this class.
+ *
+ * @param {VideoTrack[]} [tracks=[]]
+ * A list of `VideoTrack` to instantiate the list with.
+ */
+ function VideoTrackList(tracks) {
+ var _this;
+
+ if (tracks === void 0) {
+ tracks = [];
+ }
+
+ // make sure only 1 track is enabled
+ // sorted from last index to first index
+ for (var i = tracks.length - 1; i >= 0; i--) {
+ if (tracks[i].selected) {
+ disableOthers$1(tracks, tracks[i]);
+ break;
+ }
+ }
+
+ _this = _TrackList.call(this, tracks) || this;
+ _this.changing_ = false;
+ /**
+ * @member {number} VideoTrackList#selectedIndex
+ * The current index of the selected {@link VideoTrack`}.
+ */
+
+ Object.defineProperty(_babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3___default()(_this), 'selectedIndex', {
+ get: function get() {
+ for (var _i = 0; _i < this.length; _i++) {
+ if (this[_i].selected) {
+ return _i;
+ }
+ }
+
+ return -1;
+ },
+ set: function set() {}
+ });
+ return _this;
+ }
+ /**
+ * Add a {@link VideoTrack} to the `VideoTrackList`.
+ *
+ * @param {VideoTrack} track
+ * The VideoTrack to add to the list
+ *
+ * @fires TrackList#addtrack
+ */
+
+
+ var _proto = VideoTrackList.prototype;
+
+ _proto.addTrack = function addTrack(track) {
+ var _this2 = this;
+
+ if (track.selected) {
+ disableOthers$1(this, track);
+ }
+
+ _TrackList.prototype.addTrack.call(this, track); // native tracks don't have this
+
+
+ if (!track.addEventListener) {
+ return;
+ }
+
+ track.selectedChange_ = function () {
+ if (_this2.changing_) {
+ return;
+ }
+
+ _this2.changing_ = true;
+ disableOthers$1(_this2, track);
+ _this2.changing_ = false;
+
+ _this2.trigger('change');
+ };
+ /**
+ * @listens VideoTrack#selectedchange
+ * @fires TrackList#change
+ */
+
+
+ track.addEventListener('selectedchange', track.selectedChange_);
+ };
+
+ _proto.removeTrack = function removeTrack(rtrack) {
+ _TrackList.prototype.removeTrack.call(this, rtrack);
+
+ if (rtrack.removeEventListener && rtrack.selectedChange_) {
+ rtrack.removeEventListener('selectedchange', rtrack.selectedChange_);
+ rtrack.selectedChange_ = null;
+ }
+ };
+
+ return VideoTrackList;
+}(TrackList);
+
+/**
+ * The current list of {@link TextTrack} for a media file.
+ *
+ * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist}
+ * @extends TrackList
+ */
+
+var TextTrackList = /*#__PURE__*/function (_TrackList) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6___default()(TextTrackList, _TrackList);
+
+ function TextTrackList() {
+ return _TrackList.apply(this, arguments) || this;
+ }
+
+ var _proto = TextTrackList.prototype;
+
+ /**
+ * Add a {@link TextTrack} to the `TextTrackList`
+ *
+ * @param {TextTrack} track
+ * The text track to add to the list.
+ *
+ * @fires TrackList#addtrack
+ */
+ _proto.addTrack = function addTrack(track) {
+ var _this = this;
+
+ _TrackList.prototype.addTrack.call(this, track);
+
+ if (!this.queueChange_) {
+ this.queueChange_ = function () {
+ return _this.queueTrigger('change');
+ };
+ }
+
+ if (!this.triggerSelectedlanguagechange) {
+ this.triggerSelectedlanguagechange_ = function () {
+ return _this.trigger('selectedlanguagechange');
+ };
+ }
+ /**
+ * @listens TextTrack#modechange
+ * @fires TrackList#change
+ */
+
+
+ track.addEventListener('modechange', this.queueChange_);
+ var nonLanguageTextTrackKind = ['metadata', 'chapters'];
+
+ if (nonLanguageTextTrackKind.indexOf(track.kind) === -1) {
+ track.addEventListener('modechange', this.triggerSelectedlanguagechange_);
+ }
+ };
+
+ _proto.removeTrack = function removeTrack(rtrack) {
+ _TrackList.prototype.removeTrack.call(this, rtrack); // manually remove the event handlers we added
+
+
+ if (rtrack.removeEventListener) {
+ if (this.queueChange_) {
+ rtrack.removeEventListener('modechange', this.queueChange_);
+ }
+
+ if (this.selectedlanguagechange_) {
+ rtrack.removeEventListener('modechange', this.triggerSelectedlanguagechange_);
+ }
+ }
+ };
+
+ return TextTrackList;
+}(TrackList);
+
+/**
+ * @file html-track-element-list.js
+ */
+
+/**
+ * The current list of {@link HtmlTrackElement}s.
+ */
+var HtmlTrackElementList = /*#__PURE__*/function () {
+ /**
+ * Create an instance of this class.
+ *
+ * @param {HtmlTrackElement[]} [tracks=[]]
+ * A list of `HtmlTrackElement` to instantiate the list with.
+ */
+ function HtmlTrackElementList(trackElements) {
+ if (trackElements === void 0) {
+ trackElements = [];
+ }
+
+ this.trackElements_ = [];
+ /**
+ * @memberof HtmlTrackElementList
+ * @member {number} length
+ * The current number of `Track`s in the this Trackist.
+ * @instance
+ */
+
+ Object.defineProperty(this, 'length', {
+ get: function get() {
+ return this.trackElements_.length;
+ }
+ });
+
+ for (var i = 0, length = trackElements.length; i < length; i++) {
+ this.addTrackElement_(trackElements[i]);
+ }
+ }
+ /**
+ * Add an {@link HtmlTrackElement} to the `HtmlTrackElementList`
+ *
+ * @param {HtmlTrackElement} trackElement
+ * The track element to add to the list.
+ *
+ * @private
+ */
+
+
+ var _proto = HtmlTrackElementList.prototype;
+
+ _proto.addTrackElement_ = function addTrackElement_(trackElement) {
+ var index = this.trackElements_.length;
+
+ if (!('' + index in this)) {
+ Object.defineProperty(this, index, {
+ get: function get() {
+ return this.trackElements_[index];
+ }
+ });
+ } // Do not add duplicate elements
+
+
+ if (this.trackElements_.indexOf(trackElement) === -1) {
+ this.trackElements_.push(trackElement);
+ }
+ }
+ /**
+ * Get an {@link HtmlTrackElement} from the `HtmlTrackElementList` given an
+ * {@link TextTrack}.
+ *
+ * @param {TextTrack} track
+ * The track associated with a track element.
+ *
+ * @return {HtmlTrackElement|undefined}
+ * The track element that was found or undefined.
+ *
+ * @private
+ */
+ ;
+
+ _proto.getTrackElementByTrack_ = function getTrackElementByTrack_(track) {
+ var trackElement_;
+
+ for (var i = 0, length = this.trackElements_.length; i < length; i++) {
+ if (track === this.trackElements_[i].track) {
+ trackElement_ = this.trackElements_[i];
+ break;
+ }
+ }
+
+ return trackElement_;
+ }
+ /**
+ * Remove a {@link HtmlTrackElement} from the `HtmlTrackElementList`
+ *
+ * @param {HtmlTrackElement} trackElement
+ * The track element to remove from the list.
+ *
+ * @private
+ */
+ ;
+
+ _proto.removeTrackElement_ = function removeTrackElement_(trackElement) {
+ for (var i = 0, length = this.trackElements_.length; i < length; i++) {
+ if (trackElement === this.trackElements_[i]) {
+ if (this.trackElements_[i].track && typeof this.trackElements_[i].track.off === 'function') {
+ this.trackElements_[i].track.off();
+ }
+
+ if (typeof this.trackElements_[i].off === 'function') {
+ this.trackElements_[i].off();
+ }
+
+ this.trackElements_.splice(i, 1);
+ break;
+ }
+ }
+ };
+
+ return HtmlTrackElementList;
+}();
+
+/**
+ * @file text-track-cue-list.js
+ */
+
+/**
+ * @typedef {Object} TextTrackCueList~TextTrackCue
+ *
+ * @property {string} id
+ * The unique id for this text track cue
+ *
+ * @property {number} startTime
+ * The start time for this text track cue
+ *
+ * @property {number} endTime
+ * The end time for this text track cue
+ *
+ * @property {boolean} pauseOnExit
+ * Pause when the end time is reached if true.
+ *
+ * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcue}
+ */
+
+/**
+ * A List of TextTrackCues.
+ *
+ * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist}
+ */
+var TextTrackCueList = /*#__PURE__*/function () {
+ /**
+ * Create an instance of this class..
+ *
+ * @param {Array} cues
+ * A list of cues to be initialized with
+ */
+ function TextTrackCueList(cues) {
+ TextTrackCueList.prototype.setCues_.call(this, cues);
+ /**
+ * @memberof TextTrackCueList
+ * @member {number} length
+ * The current number of `TextTrackCue`s in the TextTrackCueList.
+ * @instance
+ */
+
+ Object.defineProperty(this, 'length', {
+ get: function get() {
+ return this.length_;
+ }
+ });
+ }
+ /**
+ * A setter for cues in this list. Creates getters
+ * an an index for the cues.
+ *
+ * @param {Array} cues
+ * An array of cues to set
+ *
+ * @private
+ */
+
+
+ var _proto = TextTrackCueList.prototype;
+
+ _proto.setCues_ = function setCues_(cues) {
+ var oldLength = this.length || 0;
+ var i = 0;
+ var l = cues.length;
+ this.cues_ = cues;
+ this.length_ = cues.length;
+
+ var defineProp = function defineProp(index) {
+ if (!('' + index in this)) {
+ Object.defineProperty(this, '' + index, {
+ get: function get() {
+ return this.cues_[index];
+ }
+ });
+ }
+ };
+
+ if (oldLength < l) {
+ i = oldLength;
+
+ for (; i < l; i++) {
+ defineProp.call(this, i);
+ }
+ }
+ }
+ /**
+ * Get a `TextTrackCue` that is currently in the `TextTrackCueList` by id.
+ *
+ * @param {string} id
+ * The id of the cue that should be searched for.
+ *
+ * @return {TextTrackCueList~TextTrackCue|null}
+ * A single cue or null if none was found.
+ */
+ ;
+
+ _proto.getCueById = function getCueById(id) {
+ var result = null;
+
+ for (var i = 0, l = this.length; i < l; i++) {
+ var cue = this[i];
+
+ if (cue.id === id) {
+ result = cue;
+ break;
+ }
+ }
+
+ return result;
+ };
+
+ return TextTrackCueList;
+}();
+
+/**
+ * @file track-kinds.js
+ */
+
+/**
+ * All possible `VideoTrackKind`s
+ *
+ * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-videotrack-kind
+ * @typedef VideoTrack~Kind
+ * @enum
+ */
+var VideoTrackKind = {
+ alternative: 'alternative',
+ captions: 'captions',
+ main: 'main',
+ sign: 'sign',
+ subtitles: 'subtitles',
+ commentary: 'commentary'
+};
+/**
+ * All possible `AudioTrackKind`s
+ *
+ * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-audiotrack-kind
+ * @typedef AudioTrack~Kind
+ * @enum
+ */
+
+var AudioTrackKind = {
+ 'alternative': 'alternative',
+ 'descriptions': 'descriptions',
+ 'main': 'main',
+ 'main-desc': 'main-desc',
+ 'translation': 'translation',
+ 'commentary': 'commentary'
+};
+/**
+ * All possible `TextTrackKind`s
+ *
+ * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-texttrack-kind
+ * @typedef TextTrack~Kind
+ * @enum
+ */
+
+var TextTrackKind = {
+ subtitles: 'subtitles',
+ captions: 'captions',
+ descriptions: 'descriptions',
+ chapters: 'chapters',
+ metadata: 'metadata'
+};
+/**
+ * All possible `TextTrackMode`s
+ *
+ * @see https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode
+ * @typedef TextTrack~Mode
+ * @enum
+ */
+
+var TextTrackMode = {
+ disabled: 'disabled',
+ hidden: 'hidden',
+ showing: 'showing'
+};
+
+/**
+ * A Track class that contains all of the common functionality for {@link AudioTrack},
+ * {@link VideoTrack}, and {@link TextTrack}.
+ *
+ * > Note: This class should not be used directly
+ *
+ * @see {@link https://html.spec.whatwg.org/multipage/embedded-content.html}
+ * @extends EventTarget
+ * @abstract
+ */
+
+var Track = /*#__PURE__*/function (_EventTarget) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6___default()(Track, _EventTarget);
+
+ /**
+ * Create an instance of this class.
+ *
+ * @param {Object} [options={}]
+ * Object of option names and values
+ *
+ * @param {string} [options.kind='']
+ * A valid kind for the track type you are creating.
+ *
+ * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
+ * A unique id for this AudioTrack.
+ *
+ * @param {string} [options.label='']
+ * The menu label for this track.
+ *
+ * @param {string} [options.language='']
+ * A valid two character language code.
+ *
+ * @abstract
+ */
+ function Track(options) {
+ var _this;
+
+ if (options === void 0) {
+ options = {};
+ }
+
+ _this = _EventTarget.call(this) || this;
+ var trackProps = {
+ id: options.id || 'vjs_track_' + newGUID(),
+ kind: options.kind || '',
+ label: options.label || '',
+ language: options.language || ''
+ };
+ /**
+ * @memberof Track
+ * @member {string} id
+ * The id of this track. Cannot be changed after creation.
+ * @instance
+ *
+ * @readonly
+ */
+
+ /**
+ * @memberof Track
+ * @member {string} kind
+ * The kind of track that this is. Cannot be changed after creation.
+ * @instance
+ *
+ * @readonly
+ */
+
+ /**
+ * @memberof Track
+ * @member {string} label
+ * The label of this track. Cannot be changed after creation.
+ * @instance
+ *
+ * @readonly
+ */
+
+ /**
+ * @memberof Track
+ * @member {string} language
+ * The two letter language code for this track. Cannot be changed after
+ * creation.
+ * @instance
+ *
+ * @readonly
+ */
+
+ var _loop = function _loop(key) {
+ Object.defineProperty(_babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3___default()(_this), key, {
+ get: function get() {
+ return trackProps[key];
+ },
+ set: function set() {}
+ });
+ };
+
+ for (var key in trackProps) {
+ _loop(key);
+ }
+
+ return _this;
+ }
+
+ return Track;
+}(EventTarget);
+
+/**
+ * @file url.js
+ * @module url
+ */
+/**
+ * @typedef {Object} url:URLObject
+ *
+ * @property {string} protocol
+ * The protocol of the url that was parsed.
+ *
+ * @property {string} hostname
+ * The hostname of the url that was parsed.
+ *
+ * @property {string} port
+ * The port of the url that was parsed.
+ *
+ * @property {string} pathname
+ * The pathname of the url that was parsed.
+ *
+ * @property {string} search
+ * The search query of the url that was parsed.
+ *
+ * @property {string} hash
+ * The hash of the url that was parsed.
+ *
+ * @property {string} host
+ * The host of the url that was parsed.
+ */
+
+/**
+ * Resolve and parse the elements of a URL.
+ *
+ * @function
+ * @param {String} url
+ * The url to parse
+ *
+ * @return {url:URLObject}
+ * An object of url details
+ */
+
+var parseUrl = function parseUrl(url) {
+ var props = ['protocol', 'hostname', 'port', 'pathname', 'search', 'hash', 'host']; // add the url to an anchor and let the browser parse the URL
+
+ var a = global_document__WEBPACK_IMPORTED_MODULE_1___default().createElement('a');
+ a.href = url; // IE8 (and 9?) Fix
+ // ie8 doesn't parse the URL correctly until the anchor is actually
+ // added to the body, and an innerHTML is needed to trigger the parsing
+
+ var addToBody = a.host === '' && a.protocol !== 'file:';
+ var div;
+
+ if (addToBody) {
+ div = global_document__WEBPACK_IMPORTED_MODULE_1___default().createElement('div');
+ div.innerHTML = "";
+ a = div.firstChild; // prevent the div from affecting layout
+
+ div.setAttribute('style', 'display:none; position:absolute;');
+ global_document__WEBPACK_IMPORTED_MODULE_1___default().body.appendChild(div);
+ } // Copy the specific URL properties to a new object
+ // This is also needed for IE8 because the anchor loses its
+ // properties when it's removed from the dom
+
+
+ var details = {};
+
+ for (var i = 0; i < props.length; i++) {
+ details[props[i]] = a[props[i]];
+ } // IE9 adds the port to the host property unlike everyone else. If
+ // a port identifier is added for standard ports, strip it.
+
+
+ if (details.protocol === 'http:') {
+ details.host = details.host.replace(/:80$/, '');
+ }
+
+ if (details.protocol === 'https:') {
+ details.host = details.host.replace(/:443$/, '');
+ }
+
+ if (!details.protocol) {
+ details.protocol = (global_window__WEBPACK_IMPORTED_MODULE_0___default().location.protocol);
+ }
+
+ if (addToBody) {
+ global_document__WEBPACK_IMPORTED_MODULE_1___default().body.removeChild(div);
+ }
+
+ return details;
+};
+/**
+ * Get absolute version of relative URL. Used to tell Flash the correct URL.
+ *
+ * @function
+ * @param {string} url
+ * URL to make absolute
+ *
+ * @return {string}
+ * Absolute URL
+ *
+ * @see http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
+ */
+
+var getAbsoluteURL = function getAbsoluteURL(url) {
+ // Check if absolute URL
+ if (!url.match(/^https?:\/\//)) {
+ // Convert to absolute URL. Flash hosted off-site needs an absolute URL.
+ var div = global_document__WEBPACK_IMPORTED_MODULE_1___default().createElement('div');
+ div.innerHTML = "x";
+ url = div.firstChild.href;
+ }
+
+ return url;
+};
+/**
+ * Returns the extension of the passed file name. It will return an empty string
+ * if passed an invalid path.
+ *
+ * @function
+ * @param {string} path
+ * The fileName path like '/path/to/file.mp4'
+ *
+ * @return {string}
+ * The extension in lower case or an empty string if no
+ * extension could be found.
+ */
+
+var getFileExtension = function getFileExtension(path) {
+ if (typeof path === 'string') {
+ var splitPathRe = /^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/;
+ var pathParts = splitPathRe.exec(path);
+
+ if (pathParts) {
+ return pathParts.pop().toLowerCase();
+ }
+ }
+
+ return '';
+};
+/**
+ * Returns whether the url passed is a cross domain request or not.
+ *
+ * @function
+ * @param {string} url
+ * The url to check.
+ *
+ * @param {Object} [winLoc]
+ * the domain to check the url against, defaults to window.location
+ *
+ * @param {string} [winLoc.protocol]
+ * The window location protocol defaults to window.location.protocol
+ *
+ * @param {string} [winLoc.host]
+ * The window location host defaults to window.location.host
+ *
+ * @return {boolean}
+ * Whether it is a cross domain request or not.
+ */
+
+var isCrossOrigin = function isCrossOrigin(url, winLoc) {
+ if (winLoc === void 0) {
+ winLoc = (global_window__WEBPACK_IMPORTED_MODULE_0___default().location);
+ }
+
+ var urlInfo = parseUrl(url); // IE8 protocol relative urls will return ':' for protocol
+
+ var srcProtocol = urlInfo.protocol === ':' ? winLoc.protocol : urlInfo.protocol; // Check if url is for another domain/origin
+ // IE8 doesn't know location.origin, so we won't rely on it here
+
+ var crossOrigin = srcProtocol + urlInfo.host !== winLoc.protocol + winLoc.host;
+ return crossOrigin;
+};
+
+var Url = /*#__PURE__*/Object.freeze({
+ __proto__: null,
+ parseUrl: parseUrl,
+ getAbsoluteURL: getAbsoluteURL,
+ getFileExtension: getFileExtension,
+ isCrossOrigin: isCrossOrigin
+});
+
+/**
+ * Takes a webvtt file contents and parses it into cues
+ *
+ * @param {string} srcContent
+ * webVTT file contents
+ *
+ * @param {TextTrack} track
+ * TextTrack to add cues to. Cues come from the srcContent.
+ *
+ * @private
+ */
+
+var parseCues = function parseCues(srcContent, track) {
+ var parser = new (global_window__WEBPACK_IMPORTED_MODULE_0___default().WebVTT.Parser)((global_window__WEBPACK_IMPORTED_MODULE_0___default()), (global_window__WEBPACK_IMPORTED_MODULE_0___default().vttjs), global_window__WEBPACK_IMPORTED_MODULE_0___default().WebVTT.StringDecoder());
+ var errors = [];
+
+ parser.oncue = function (cue) {
+ track.addCue(cue);
+ };
+
+ parser.onparsingerror = function (error) {
+ errors.push(error);
+ };
+
+ parser.onflush = function () {
+ track.trigger({
+ type: 'loadeddata',
+ target: track
+ });
+ };
+
+ parser.parse(srcContent);
+
+ if (errors.length > 0) {
+ if ((global_window__WEBPACK_IMPORTED_MODULE_0___default().console) && (global_window__WEBPACK_IMPORTED_MODULE_0___default().console.groupCollapsed)) {
+ global_window__WEBPACK_IMPORTED_MODULE_0___default().console.groupCollapsed("Text Track parsing errors for " + track.src);
+ }
+
+ errors.forEach(function (error) {
+ return log.error(error);
+ });
+
+ if ((global_window__WEBPACK_IMPORTED_MODULE_0___default().console) && (global_window__WEBPACK_IMPORTED_MODULE_0___default().console.groupEnd)) {
+ global_window__WEBPACK_IMPORTED_MODULE_0___default().console.groupEnd();
+ }
+ }
+
+ parser.flush();
+};
+/**
+ * Load a `TextTrack` from a specified url.
+ *
+ * @param {string} src
+ * Url to load track from.
+ *
+ * @param {TextTrack} track
+ * Track to add cues to. Comes from the content at the end of `url`.
+ *
+ * @private
+ */
+
+
+var loadTrack = function loadTrack(src, track) {
+ var opts = {
+ uri: src
+ };
+ var crossOrigin = isCrossOrigin(src);
+
+ if (crossOrigin) {
+ opts.cors = crossOrigin;
+ }
+
+ var withCredentials = track.tech_.crossOrigin() === 'use-credentials';
+
+ if (withCredentials) {
+ opts.withCredentials = withCredentials;
+ }
+
+ _videojs_xhr__WEBPACK_IMPORTED_MODULE_9___default()(opts, bind(this, function (err, response, responseBody) {
+ if (err) {
+ return log.error(err, response);
+ }
+
+ track.loaded_ = true; // Make sure that vttjs has loaded, otherwise, wait till it finished loading
+ // NOTE: this is only used for the alt/video.novtt.js build
+
+ if (typeof (global_window__WEBPACK_IMPORTED_MODULE_0___default().WebVTT) !== 'function') {
+ if (track.tech_) {
+ // to prevent use before define eslint error, we define loadHandler
+ // as a let here
+ track.tech_.any(['vttjsloaded', 'vttjserror'], function (event) {
+ if (event.type === 'vttjserror') {
+ log.error("vttjs failed to load, stopping trying to process " + track.src);
+ return;
+ }
+
+ return parseCues(responseBody, track);
+ });
+ }
+ } else {
+ parseCues(responseBody, track);
+ }
+ }));
+};
+/**
+ * A representation of a single `TextTrack`.
+ *
+ * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack}
+ * @extends Track
+ */
+
+
+var TextTrack = /*#__PURE__*/function (_Track) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6___default()(TextTrack, _Track);
+
+ /**
+ * Create an instance of this class.
+ *
+ * @param {Object} options={}
+ * Object of option names and values
+ *
+ * @param {Tech} options.tech
+ * A reference to the tech that owns this TextTrack.
+ *
+ * @param {TextTrack~Kind} [options.kind='subtitles']
+ * A valid text track kind.
+ *
+ * @param {TextTrack~Mode} [options.mode='disabled']
+ * A valid text track mode.
+ *
+ * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
+ * A unique id for this TextTrack.
+ *
+ * @param {string} [options.label='']
+ * The menu label for this track.
+ *
+ * @param {string} [options.language='']
+ * A valid two character language code.
+ *
+ * @param {string} [options.srclang='']
+ * A valid two character language code. An alternative, but deprioritized
+ * version of `options.language`
+ *
+ * @param {string} [options.src]
+ * A url to TextTrack cues.
+ *
+ * @param {boolean} [options.default]
+ * If this track should default to on or off.
+ */
+ function TextTrack(options) {
+ var _this;
+
+ if (options === void 0) {
+ options = {};
+ }
+
+ if (!options.tech) {
+ throw new Error('A tech was not provided.');
+ }
+
+ var settings = mergeOptions(options, {
+ kind: TextTrackKind[options.kind] || 'subtitles',
+ language: options.language || options.srclang || ''
+ });
+ var mode = TextTrackMode[settings.mode] || 'disabled';
+ var default_ = settings["default"];
+
+ if (settings.kind === 'metadata' || settings.kind === 'chapters') {
+ mode = 'hidden';
+ }
+
+ _this = _Track.call(this, settings) || this;
+ _this.tech_ = settings.tech;
+ _this.cues_ = [];
+ _this.activeCues_ = [];
+ _this.preload_ = _this.tech_.preloadTextTracks !== false;
+ var cues = new TextTrackCueList(_this.cues_);
+ var activeCues = new TextTrackCueList(_this.activeCues_);
+ var changed = false;
+ var timeupdateHandler = bind(_babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3___default()(_this), function () {
+ // Accessing this.activeCues for the side-effects of updating itself
+ // due to its nature as a getter function. Do not remove or cues will
+ // stop updating!
+ // Use the setter to prevent deletion from uglify (pure_getters rule)
+ this.activeCues = this.activeCues;
+
+ if (changed) {
+ this.trigger('cuechange');
+ changed = false;
+ }
+ });
+
+ if (mode !== 'disabled') {
+ _this.tech_.ready(function () {
+ _this.tech_.on('timeupdate', timeupdateHandler);
+ }, true);
+ }
+
+ Object.defineProperties(_babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3___default()(_this), {
+ /**
+ * @memberof TextTrack
+ * @member {boolean} default
+ * If this track was set to be on or off by default. Cannot be changed after
+ * creation.
+ * @instance
+ *
+ * @readonly
+ */
+ "default": {
+ get: function get() {
+ return default_;
+ },
+ set: function set() {}
+ },
+
+ /**
+ * @memberof TextTrack
+ * @member {string} mode
+ * Set the mode of this TextTrack to a valid {@link TextTrack~Mode}. Will
+ * not be set if setting to an invalid mode.
+ * @instance
+ *
+ * @fires TextTrack#modechange
+ */
+ mode: {
+ get: function get() {
+ return mode;
+ },
+ set: function set(newMode) {
+ var _this2 = this;
+
+ if (!TextTrackMode[newMode]) {
+ return;
+ }
+
+ mode = newMode;
+
+ if (!this.preload_ && mode !== 'disabled' && this.cues.length === 0) {
+ // On-demand load.
+ loadTrack(this.src, this);
+ }
+
+ if (mode !== 'disabled') {
+ this.tech_.ready(function () {
+ _this2.tech_.on('timeupdate', timeupdateHandler);
+ }, true);
+ } else {
+ this.tech_.off('timeupdate', timeupdateHandler);
+ }
+ /**
+ * An event that fires when mode changes on this track. This allows
+ * the TextTrackList that holds this track to act accordingly.
+ *
+ * > Note: This is not part of the spec!
+ *
+ * @event TextTrack#modechange
+ * @type {EventTarget~Event}
+ */
+
+
+ this.trigger('modechange');
+ }
+ },
+
+ /**
+ * @memberof TextTrack
+ * @member {TextTrackCueList} cues
+ * The text track cue list for this TextTrack.
+ * @instance
+ */
+ cues: {
+ get: function get() {
+ if (!this.loaded_) {
+ return null;
+ }
+
+ return cues;
+ },
+ set: function set() {}
+ },
+
+ /**
+ * @memberof TextTrack
+ * @member {TextTrackCueList} activeCues
+ * The list text track cues that are currently active for this TextTrack.
+ * @instance
+ */
+ activeCues: {
+ get: function get() {
+ if (!this.loaded_) {
+ return null;
+ } // nothing to do
+
+
+ if (this.cues.length === 0) {
+ return activeCues;
+ }
+
+ var ct = this.tech_.currentTime();
+ var active = [];
+
+ for (var i = 0, l = this.cues.length; i < l; i++) {
+ var cue = this.cues[i];
+
+ if (cue.startTime <= ct && cue.endTime >= ct) {
+ active.push(cue);
+ } else if (cue.startTime === cue.endTime && cue.startTime <= ct && cue.startTime + 0.5 >= ct) {
+ active.push(cue);
+ }
+ }
+
+ changed = false;
+
+ if (active.length !== this.activeCues_.length) {
+ changed = true;
+ } else {
+ for (var _i = 0; _i < active.length; _i++) {
+ if (this.activeCues_.indexOf(active[_i]) === -1) {
+ changed = true;
+ }
+ }
+ }
+
+ this.activeCues_ = active;
+ activeCues.setCues_(this.activeCues_);
+ return activeCues;
+ },
+ // /!\ Keep this setter empty (see the timeupdate handler above)
+ set: function set() {}
+ }
+ });
+
+ if (settings.src) {
+ _this.src = settings.src;
+
+ if (!_this.preload_) {
+ // Tracks will load on-demand.
+ // Act like we're loaded for other purposes.
+ _this.loaded_ = true;
+ }
+
+ if (_this.preload_ || default_ || settings.kind !== 'subtitles' && settings.kind !== 'captions') {
+ loadTrack(_this.src, _babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3___default()(_this));
+ }
+ } else {
+ _this.loaded_ = true;
+ }
+
+ return _this;
+ }
+ /**
+ * Add a cue to the internal list of cues.
+ *
+ * @param {TextTrack~Cue} cue
+ * The cue to add to our internal list
+ */
+
+
+ var _proto = TextTrack.prototype;
+
+ _proto.addCue = function addCue(originalCue) {
+ var cue = originalCue;
+
+ if ((global_window__WEBPACK_IMPORTED_MODULE_0___default().vttjs) && !(originalCue instanceof (global_window__WEBPACK_IMPORTED_MODULE_0___default().vttjs.VTTCue))) {
+ cue = new (global_window__WEBPACK_IMPORTED_MODULE_0___default().vttjs.VTTCue)(originalCue.startTime, originalCue.endTime, originalCue.text);
+
+ for (var prop in originalCue) {
+ if (!(prop in cue)) {
+ cue[prop] = originalCue[prop];
+ }
+ } // make sure that `id` is copied over
+
+
+ cue.id = originalCue.id;
+ cue.originalCue_ = originalCue;
+ }
+
+ var tracks = this.tech_.textTracks();
+
+ for (var i = 0; i < tracks.length; i++) {
+ if (tracks[i] !== this) {
+ tracks[i].removeCue(cue);
+ }
+ }
+
+ this.cues_.push(cue);
+ this.cues.setCues_(this.cues_);
+ }
+ /**
+ * Remove a cue from our internal list
+ *
+ * @param {TextTrack~Cue} removeCue
+ * The cue to remove from our internal list
+ */
+ ;
+
+ _proto.removeCue = function removeCue(_removeCue) {
+ var i = this.cues_.length;
+
+ while (i--) {
+ var cue = this.cues_[i];
+
+ if (cue === _removeCue || cue.originalCue_ && cue.originalCue_ === _removeCue) {
+ this.cues_.splice(i, 1);
+ this.cues.setCues_(this.cues_);
+ break;
+ }
+ }
+ };
+
+ return TextTrack;
+}(Track);
+/**
+ * cuechange - One or more cues in the track have become active or stopped being active.
+ */
+
+
+TextTrack.prototype.allowedEvents_ = {
+ cuechange: 'cuechange'
+};
+
+/**
+ * A representation of a single `AudioTrack`. If it is part of an {@link AudioTrackList}
+ * only one `AudioTrack` in the list will be enabled at a time.
+ *
+ * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotrack}
+ * @extends Track
+ */
+
+var AudioTrack = /*#__PURE__*/function (_Track) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6___default()(AudioTrack, _Track);
+
+ /**
+ * Create an instance of this class.
+ *
+ * @param {Object} [options={}]
+ * Object of option names and values
+ *
+ * @param {AudioTrack~Kind} [options.kind='']
+ * A valid audio track kind
+ *
+ * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
+ * A unique id for this AudioTrack.
+ *
+ * @param {string} [options.label='']
+ * The menu label for this track.
+ *
+ * @param {string} [options.language='']
+ * A valid two character language code.
+ *
+ * @param {boolean} [options.enabled]
+ * If this track is the one that is currently playing. If this track is part of
+ * an {@link AudioTrackList}, only one {@link AudioTrack} will be enabled.
+ */
+ function AudioTrack(options) {
+ var _this;
+
+ if (options === void 0) {
+ options = {};
+ }
+
+ var settings = mergeOptions(options, {
+ kind: AudioTrackKind[options.kind] || ''
+ });
+ _this = _Track.call(this, settings) || this;
+ var enabled = false;
+ /**
+ * @memberof AudioTrack
+ * @member {boolean} enabled
+ * If this `AudioTrack` is enabled or not. When setting this will
+ * fire {@link AudioTrack#enabledchange} if the state of enabled is changed.
+ * @instance
+ *
+ * @fires VideoTrack#selectedchange
+ */
+
+ Object.defineProperty(_babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3___default()(_this), 'enabled', {
+ get: function get() {
+ return enabled;
+ },
+ set: function set(newEnabled) {
+ // an invalid or unchanged value
+ if (typeof newEnabled !== 'boolean' || newEnabled === enabled) {
+ return;
+ }
+
+ enabled = newEnabled;
+ /**
+ * An event that fires when enabled changes on this track. This allows
+ * the AudioTrackList that holds this track to act accordingly.
+ *
+ * > Note: This is not part of the spec! Native tracks will do
+ * this internally without an event.
+ *
+ * @event AudioTrack#enabledchange
+ * @type {EventTarget~Event}
+ */
+
+ this.trigger('enabledchange');
+ }
+ }); // if the user sets this track to selected then
+ // set selected to that true value otherwise
+ // we keep it false
+
+ if (settings.enabled) {
+ _this.enabled = settings.enabled;
+ }
+
+ _this.loaded_ = true;
+ return _this;
+ }
+
+ return AudioTrack;
+}(Track);
+
+/**
+ * A representation of a single `VideoTrack`.
+ *
+ * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotrack}
+ * @extends Track
+ */
+
+var VideoTrack = /*#__PURE__*/function (_Track) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6___default()(VideoTrack, _Track);
+
+ /**
+ * Create an instance of this class.
+ *
+ * @param {Object} [options={}]
+ * Object of option names and values
+ *
+ * @param {string} [options.kind='']
+ * A valid {@link VideoTrack~Kind}
+ *
+ * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
+ * A unique id for this AudioTrack.
+ *
+ * @param {string} [options.label='']
+ * The menu label for this track.
+ *
+ * @param {string} [options.language='']
+ * A valid two character language code.
+ *
+ * @param {boolean} [options.selected]
+ * If this track is the one that is currently playing.
+ */
+ function VideoTrack(options) {
+ var _this;
+
+ if (options === void 0) {
+ options = {};
+ }
+
+ var settings = mergeOptions(options, {
+ kind: VideoTrackKind[options.kind] || ''
+ });
+ _this = _Track.call(this, settings) || this;
+ var selected = false;
+ /**
+ * @memberof VideoTrack
+ * @member {boolean} selected
+ * If this `VideoTrack` is selected or not. When setting this will
+ * fire {@link VideoTrack#selectedchange} if the state of selected changed.
+ * @instance
+ *
+ * @fires VideoTrack#selectedchange
+ */
+
+ Object.defineProperty(_babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3___default()(_this), 'selected', {
+ get: function get() {
+ return selected;
+ },
+ set: function set(newSelected) {
+ // an invalid or unchanged value
+ if (typeof newSelected !== 'boolean' || newSelected === selected) {
+ return;
+ }
+
+ selected = newSelected;
+ /**
+ * An event that fires when selected changes on this track. This allows
+ * the VideoTrackList that holds this track to act accordingly.
+ *
+ * > Note: This is not part of the spec! Native tracks will do
+ * this internally without an event.
+ *
+ * @event VideoTrack#selectedchange
+ * @type {EventTarget~Event}
+ */
+
+ this.trigger('selectedchange');
+ }
+ }); // if the user sets this track to selected then
+ // set selected to that true value otherwise
+ // we keep it false
+
+ if (settings.selected) {
+ _this.selected = settings.selected;
+ }
+
+ return _this;
+ }
+
+ return VideoTrack;
+}(Track);
+
+/**
+ * @memberof HTMLTrackElement
+ * @typedef {HTMLTrackElement~ReadyState}
+ * @enum {number}
+ */
+
+var NONE = 0;
+var LOADING = 1;
+var LOADED = 2;
+var ERROR = 3;
+/**
+ * A single track represented in the DOM.
+ *
+ * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#htmltrackelement}
+ * @extends EventTarget
+ */
+
+var HTMLTrackElement = /*#__PURE__*/function (_EventTarget) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6___default()(HTMLTrackElement, _EventTarget);
+
+ /**
+ * Create an instance of this class.
+ *
+ * @param {Object} options={}
+ * Object of option names and values
+ *
+ * @param {Tech} options.tech
+ * A reference to the tech that owns this HTMLTrackElement.
+ *
+ * @param {TextTrack~Kind} [options.kind='subtitles']
+ * A valid text track kind.
+ *
+ * @param {TextTrack~Mode} [options.mode='disabled']
+ * A valid text track mode.
+ *
+ * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
+ * A unique id for this TextTrack.
+ *
+ * @param {string} [options.label='']
+ * The menu label for this track.
+ *
+ * @param {string} [options.language='']
+ * A valid two character language code.
+ *
+ * @param {string} [options.srclang='']
+ * A valid two character language code. An alternative, but deprioritized
+ * vesion of `options.language`
+ *
+ * @param {string} [options.src]
+ * A url to TextTrack cues.
+ *
+ * @param {boolean} [options.default]
+ * If this track should default to on or off.
+ */
+ function HTMLTrackElement(options) {
+ var _this;
+
+ if (options === void 0) {
+ options = {};
+ }
+
+ _this = _EventTarget.call(this) || this;
+ var readyState;
+ var track = new TextTrack(options);
+ _this.kind = track.kind;
+ _this.src = track.src;
+ _this.srclang = track.language;
+ _this.label = track.label;
+ _this["default"] = track["default"];
+ Object.defineProperties(_babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3___default()(_this), {
+ /**
+ * @memberof HTMLTrackElement
+ * @member {HTMLTrackElement~ReadyState} readyState
+ * The current ready state of the track element.
+ * @instance
+ */
+ readyState: {
+ get: function get() {
+ return readyState;
+ }
+ },
+
+ /**
+ * @memberof HTMLTrackElement
+ * @member {TextTrack} track
+ * The underlying TextTrack object.
+ * @instance
+ *
+ */
+ track: {
+ get: function get() {
+ return track;
+ }
+ }
+ });
+ readyState = NONE;
+ /**
+ * @listens TextTrack#loadeddata
+ * @fires HTMLTrackElement#load
+ */
+
+ track.addEventListener('loadeddata', function () {
+ readyState = LOADED;
+
+ _this.trigger({
+ type: 'load',
+ target: _babel_runtime_helpers_assertThisInitialized__WEBPACK_IMPORTED_MODULE_3___default()(_this)
+ });
+ });
+ return _this;
+ }
+
+ return HTMLTrackElement;
+}(EventTarget);
+
+HTMLTrackElement.prototype.allowedEvents_ = {
+ load: 'load'
+};
+HTMLTrackElement.NONE = NONE;
+HTMLTrackElement.LOADING = LOADING;
+HTMLTrackElement.LOADED = LOADED;
+HTMLTrackElement.ERROR = ERROR;
+
+/*
+ * This file contains all track properties that are used in
+ * player.js, tech.js, html5.js and possibly other techs in the future.
+ */
+
+var NORMAL = {
+ audio: {
+ ListClass: AudioTrackList,
+ TrackClass: AudioTrack,
+ capitalName: 'Audio'
+ },
+ video: {
+ ListClass: VideoTrackList,
+ TrackClass: VideoTrack,
+ capitalName: 'Video'
+ },
+ text: {
+ ListClass: TextTrackList,
+ TrackClass: TextTrack,
+ capitalName: 'Text'
+ }
+};
+Object.keys(NORMAL).forEach(function (type) {
+ NORMAL[type].getterName = type + "Tracks";
+ NORMAL[type].privateName = type + "Tracks_";
+});
+var REMOTE = {
+ remoteText: {
+ ListClass: TextTrackList,
+ TrackClass: TextTrack,
+ capitalName: 'RemoteText',
+ getterName: 'remoteTextTracks',
+ privateName: 'remoteTextTracks_'
+ },
+ remoteTextEl: {
+ ListClass: HtmlTrackElementList,
+ TrackClass: HTMLTrackElement,
+ capitalName: 'RemoteTextTrackEls',
+ getterName: 'remoteTextTrackEls',
+ privateName: 'remoteTextTrackEls_'
+ }
+};
+
+var ALL = _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_2___default()({}, NORMAL, REMOTE);
+
+REMOTE.names = Object.keys(REMOTE);
+NORMAL.names = Object.keys(NORMAL);
+ALL.names = [].concat(REMOTE.names).concat(NORMAL.names);
+
+/**
+ * An Object containing a structure like: `{src: 'url', type: 'mimetype'}` or string
+ * that just contains the src url alone.
+ * * `var SourceObject = {src: 'http://ex.com/video.mp4', type: 'video/mp4'};`
+ * `var SourceString = 'http://example.com/some-video.mp4';`
+ *
+ * @typedef {Object|string} Tech~SourceObject
+ *
+ * @property {string} src
+ * The url to the source
+ *
+ * @property {string} type
+ * The mime type of the source
+ */
+
+/**
+ * A function used by {@link Tech} to create a new {@link TextTrack}.
+ *
+ * @private
+ *
+ * @param {Tech} self
+ * An instance of the Tech class.
+ *
+ * @param {string} kind
+ * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)
+ *
+ * @param {string} [label]
+ * Label to identify the text track
+ *
+ * @param {string} [language]
+ * Two letter language abbreviation
+ *
+ * @param {Object} [options={}]
+ * An object with additional text track options
+ *
+ * @return {TextTrack}
+ * The text track that was created.
+ */
+
+function createTrackHelper(self, kind, label, language, options) {
+ if (options === void 0) {
+ options = {};
+ }
+
+ var tracks = self.textTracks();
+ options.kind = kind;
+
+ if (label) {
+ options.label = label;
+ }
+
+ if (language) {
+ options.language = language;
+ }
+
+ options.tech = self;
+ var track = new ALL.text.TrackClass(options);
+ tracks.addTrack(track);
+ return track;
+}
+/**
+ * This is the base class for media playback technology controllers, such as
+ * {@link Flash} and {@link HTML5}
+ *
+ * @extends Component
+ */
+
+
+var Tech = /*#__PURE__*/function (_Component) {
+ _babel_runtime_helpers_inheritsLoose__WEBPACK_IMPORTED_MODULE_6___default()(Tech, _Component);
+
+ /**
+ * Create an instance of this Tech.
+ *
+ * @param {Object} [options]
+ * The key/value store of player options.
+ *
+ * @param {Component~ReadyCallback} ready
+ * Callback function to call when the `HTML5` Tech is ready.
+ */
+ function Tech(options, ready) {
+ var _this;
+
+ if (options === void 0) {
+ options = {};
+ }
+
+ if (ready === void 0) {
+ ready = function ready() {};
+ }
+
+ // we don't want the tech to report user activity automatically.
+ // This is done manually in addControlsListeners
+ options.reportTouchActivity = false;
+ _this = _Component.call(this, null, options, ready) || this; // keep track of whether the current source has played at all to
+ // implement a very limited played()
+
+ _this.hasStarted_ = false;
+
+ _this.on('playing', function () {
+ this.hasStarted_ = true;
+ });
+
+ _this.on('loadstart', function () {
+ this.hasStarted_ = false;
+ });
+
+ ALL.names.forEach(function (name) {
+ var props = ALL[name];
+
+ if (options && options[props.getterName]) {
+ _this[props.privateName] = options[props.getterName];
+ }
+ }); // Manually track progress in cases where the browser/flash player doesn't report it.
+
+ if (!_this.featuresProgressEvents) {
+ _this.manualProgressOn();
+ } // Manually track timeupdates in cases where the browser/flash player doesn't report it.
+
+
+ if (!_this.featuresTimeupdateEvents) {
+ _this.manualTimeUpdatesOn();
+ }
+
+ ['Text', 'Audio', 'Video'].forEach(function (track) {
+ if (options["native" + track + "Tracks"] === false) {
+ _this["featuresNative" + track + "Tracks"] = false;
+ }
+ });
+
+ if (options.nativeCaptions === false || options.nativeTextTracks === false) {
+ _this.featuresNativeTextTracks = false;
+ } else if (options.nativeCaptions === true || options.nativeTextTracks === true) {
+ _this.featuresNativeTextTracks = true;
+ }
+
+ if (!_this.featuresNativeTextTracks) {
+ _this.emulateTextTracks();
+ }
+
+ _this.preloadTextTracks = options.preloadTextTracks !== false;
+ _this.autoRemoteTextTracks_ = new ALL.text.ListClass();
+
+ _this.initTrackListeners(); // Turn on component tap events only if not using native controls
+
+
+ if (!options.nativeControlsForTouch) {
+ _this.emitTapEvents();
+ }
+
+ if (_this.constructor) {
+ _this.name_ = _this.constructor.name || 'Unknown Tech';
+ }
+
+ return _this;
+ }
+ /**
+ * A special function to trigger source set in a way that will allow player
+ * to re-trigger if the player or tech are not ready yet.
+ *
+ * @fires Tech#sourceset
+ * @param {string} src The source string at the time of the source changing.
+ */
+
+
+ var _proto = Tech.prototype;
+
+ _proto.triggerSourceset = function triggerSourceset(src) {
+ var _this2 = this;
+
+ if (!this.isReady_) {
+ // on initial ready we have to trigger source set
+ // 1ms after ready so that player can watch for it.
+ this.one('ready', function () {
+ return _this2.setTimeout(function () {
+ return _this2.triggerSourceset(src);
+ }, 1);
+ });
+ }
+ /**
+ * Fired when the source is set on the tech causing the media element
+ * to reload.
+ *
+ * @see {@link Player#event:sourceset}
+ * @event Tech#sourceset
+ * @type {EventTarget~Event}
+ */
+
+
+ this.trigger({
+ src: src,
+ type: 'sourceset'
+ });
+ }
+ /* Fallbacks for unsupported event types
+ ================================================================================ */
+
+ /**
+ * Polyfill the `progress` event for browsers that don't support it natively.
+ *
+ * @see {@link Tech#trackProgress}
+ */
+ ;
+
+ _proto.manualProgressOn = function manualProgressOn() {
+ this.on('durationchange', this.onDurationChange);
+ this.manualProgress = true; // Trigger progress watching when a source begins loading
+
+ this.one('ready', this.trackProgress);
+ }
+ /**
+ * Turn off the polyfill for `progress` events that was created in
+ * {@link Tech#manualProgressOn}
+ */
+ ;
+
+ _proto.manualProgressOff = function manualProgressOff() {
+ this.manualProgress = false;
+ this.stopTrackingProgress();
+ this.off('durationchange', this.onDurationChange);
+ }
+ /**
+ * This is used to trigger a `progress` event when the buffered percent changes. It
+ * sets an interval function that will be called every 500 milliseconds to check if the
+ * buffer end percent has changed.
+ *
+ * > This function is called by {@link Tech#manualProgressOn}
+ *
+ * @param {EventTarget~Event} event
+ * The `ready` event that caused this to run.
+ *
+ * @listens Tech#ready
+ * @fires Tech#progress
+ */
+ ;
+
+ _proto.trackProgress = function trackProgress(event) {
+ this.stopTrackingProgress();
+ this.progressInterval = this.setInterval(bind(this, function () {
+ // Don't trigger unless buffered amount is greater than last time
+ var numBufferedPercent = this.bufferedPercent();
+
+ if (this.bufferedPercent_ !== numBufferedPercent) {
+ /**
+ * See {@link Player#progress}
+ *
+ * @event Tech#progress
+ * @type {EventTarget~Event}
+ */
+ this.trigger('progress');
+ }
+
+ this.bufferedPercent_ = numBufferedPercent;
+
+ if (numBufferedPercent === 1) {
+ this.stopTrackingProgress();
+ }
+ }), 500);
+ }
+ /**
+ * Update our internal duration on a `durationchange` event by calling
+ * {@link Tech#duration}.
+ *
+ * @param {EventTarget~Event} event
+ * The `durationchange` event that caused this to run.
+ *
+ * @listens Tech#durationchange
+ */
+ ;
+
+ _proto.onDurationChange = function onDurationChange(event) {
+ this.duration_ = this.duration();
+ }
+ /**
+ * Get and create a `TimeRange` object for buffering.
+ *
+ * @return {TimeRange}
+ * The time range object that was created.
+ */
+ ;
+
+ _proto.buffered = function buffered() {
+ return createTimeRanges(0, 0);
+ }
+ /**
+ * Get the percentage of the current video that is currently buffered.
+ *
+ * @return {number}
+ * A number from 0 to 1 that represents the decimal percentage of the
+ * video that is buffered.
+ *
+ */
+ ;
+
+ _proto.bufferedPercent = function bufferedPercent$1() {
+ return bufferedPercent(this.buffered(), this.duration_);
+ }
+ /**
+ * Turn off the polyfill for `progress` events that was created in
+ * {@link Tech#manualProgressOn}
+ * Stop manually tracking progress events by clearing the interval that was set in
+ * {@link Tech#trackProgress}.
+ */
+ ;
+
+ _proto.stopTrackingProgress = function stopTrackingProgress() {
+ this.clearInterval(this.progressInterval);
+ }
+ /**
+ * Polyfill the `timeupdate` event for browsers that don't support it.
+ *
+ * @see {@link Tech#trackCurrentTime}
+ */
+ ;
+
+ _proto.manualTimeUpdatesOn = function manualTimeUpdatesOn() {
+ this.manualTimeUpdates = true;
+ this.on('play', this.trackCurrentTime);
+ this.on('pause', this.stopTrackingCurrentTime);
+ }
+ /**
+ * Turn off the polyfill for `timeupdate` events that was created in
+ * {@link Tech#manualTimeUpdatesOn}
+ */
+ ;
+
+ _proto.manualTimeUpdatesOff = function manualTimeUpdatesOff() {
+ this.manualTimeUpdates = false;
+ this.stopTrackingCurrentTime();
+ this.off('play', this.trackCurrentTime);
+ this.off('pause', this.stopTrackingCurrentTime);
+ }
+ /**
+ * Sets up an interval function to track current time and trigger `timeupdate` every
+ * 250 milliseconds.
+ *
+ * @listens Tech#play
+ * @triggers Tech#timeupdate
+ */
+ ;
+
+ _proto.trackCurrentTime = function trackCurrentTime() {
+ if (this.currentTimeInterval) {
+ this.stopTrackingCurrentTime();
+ }
+
+ this.currentTimeInterval = this.setInterval(function () {
+ /**
+ * Triggered at an interval of 250ms to indicated that time is passing in the video.
+ *
+ * @event Tech#timeupdate
+ * @type {EventTarget~Event}
+ */
+ this.trigger({
+ type: 'timeupdate',
+ target: this,
+ manuallyTriggered: true
+ }); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
+ }, 250);
+ }
+ /**
+ * Stop the interval function created in {@link Tech#trackCurrentTime} so that the
+ * `timeupdate` event is no longer triggered.
+ *
+ * @listens {Tech#pause}
+ */
+ ;
+
+ _proto.stopTrackingCurrentTime = function stopTrackingCurrentTime() {
+ this.clearInterval(this.currentTimeInterval); // #1002 - if the video ends right before the next timeupdate would happen,
+ // the progress bar won't make it all the way to the end
+
+ this.trigger({
+ type: 'timeupdate',
+ target: this,
+ manuallyTriggered: true
+ });
+ }
+ /**
+ * Turn off all event polyfills, clear the `Tech`s {@link AudioTrackList},
+ * {@link VideoTrackList}, and {@link TextTrackList}, and dispose of this Tech.
+ *
+ * @fires Component#dispose
+ */
+ ;
+
+ _proto.dispose = function dispose() {
+ // clear out all tracks because we can't reuse them between techs
+ this.clearTracks(NORMAL.names); // Turn off any manual progress or timeupdate tracking
+
+ if (this.manualProgress) {
+ this.manualProgressOff();
+ }
+
+ if (this.manualTimeUpdates) {
+ this.manualTimeUpdatesOff();
+ }
+
+ _Component.prototype.dispose.call(this);
+ }
+ /**
+ * Clear out a single `TrackList` or an array of `TrackLists` given their names.
+ *
+ * > Note: Techs without source handlers should call this between sources for `video`
+ * & `audio` tracks. You don't want to use them between tracks!
+ *
+ * @param {string[]|string} types
+ * TrackList names to clear, valid names are `video`, `audio`, and
+ * `text`.
+ */
+ ;
+
+ _proto.clearTracks = function clearTracks(types) {
+ var _this3 = this;
+
+ types = [].concat(types); // clear out all tracks because we can't reuse them between techs
+
+ types.forEach(function (type) {
+ var list = _this3[type + "Tracks"]() || [];
+ var i = list.length;
+
+ while (i--) {
+ var track = list[i];
+
+ if (type === 'text') {
+ _this3.removeRemoteTextTrack(track);
+ }
+
+ list.removeTrack(track);
+ }
+ });
+ }
+ /**
+ * Remove any TextTracks added via addRemoteTextTrack that are
+ * flagged for automatic garbage collection
+ */
+ ;
+
+ _proto.cleanupAutoTextTracks = function cleanupAutoTextTracks() {
+ var list = this.autoRemoteTextTracks_ || [];
+ var i = list.length;
+
+ while (i--) {
+ var track = list[i];
+ this.removeRemoteTextTrack(track);
+ }
+ }
+ /**
+ * Reset the tech, which will removes all sources and reset the internal readyState.
+ *
+ * @abstract
+ */
+ ;
+
+ _proto.reset = function reset() {}
+ /**
+ * Get the value of `crossOrigin` from the tech.
+ *
+ * @abstract
+ *
+ * @see {Html5#crossOrigin}
+ */
+ ;
+
+ _proto.crossOrigin = function crossOrigin() {}
+ /**
+ * Set the value of `crossOrigin` on the tech.
+ *
+ * @abstract
+ *
+ * @param {string} crossOrigin the crossOrigin value
+ * @see {Html5#setCrossOrigin}
+ */
+ ;
+
+ _proto.setCrossOrigin = function setCrossOrigin() {}
+ /**
+ * Get or set an error on the Tech.
+ *
+ * @param {MediaError} [err]
+ * Error to set on the Tech
+ *
+ * @return {MediaError|null}
+ * The current error object on the tech, or null if there isn't one.
+ */
+ ;
+
+ _proto.error = function error(err) {
+ if (err !== undefined) {
+ this.error_ = new MediaError(err);
+ this.trigger('error');
+ }
+
+ return this.error_;
+ }
+ /**
+ * Returns the `TimeRange`s that have been played through for the current source.
+ *
+ * > NOTE: This implementation is incomplete. It does not track the played `TimeRange`.
+ * It only checks whether the source has played at all or not.
+ *
+ * @return {TimeRange}
+ * - A single time range if this video has played
+ * - An empty set of ranges if not.
+ */
+ ;
+
+ _proto.played = function played() {
+ if (this.hasStarted_) {
+ return createTimeRanges(0, 0);
+ }
+
+ return createTimeRanges();
+ }
+ /**
+ * Set whether we are scrubbing or not
+ *
+ * @abstract
+ *
+ * @see {Html5#setScrubbing}
+ */
+ ;
+
+ _proto.setScrubbing = function setScrubbing() {}
+ /**
+ * Causes a manual time update to occur if {@link Tech#manualTimeUpdatesOn} was
+ * previously called.
+ *
+ * @fires Tech#timeupdate
+ */
+ ;
+
+ _proto.setCurrentTime = function setCurrentTime() {
+ // improve the accuracy of manual timeupdates
+ if (this.manualTimeUpdates) {
+ /**
+ * A manual `timeupdate` event.
+ *
+ * @event Tech#timeupdate
+ * @type {EventTarget~Event}
+ */
+ this.trigger({
+ type: 'timeupdate',
+ target: this,
+ manuallyTriggered: true
+ });
+ }
+ }
+ /**
+ * Turn on listeners for {@link VideoTrackList}, {@link {AudioTrackList}, and
+ * {@link TextTrackList} events.
+ *
+ * This adds {@link EventTarget~EventListeners} for `addtrack`, and `removetrack`.
+ *
+ * @fires Tech#audiotrackchange
+ * @fires Tech#videotrackchange
+ * @fires Tech#texttrackchange
+ */
+ ;
+
+ _proto.initTrackListeners = function initTrackListeners() {
+ var _this4 = this;
+
+ /**
+ * Triggered when tracks are added or removed on the Tech {@link AudioTrackList}
+ *
+ * @event Tech#audiotrackchange
+ * @type {EventTarget~Event}
+ */
+
+ /**
+ * Triggered when tracks are added or removed on the Tech {@link VideoTrackList}
+ *
+ * @event Tech#videotrackchange
+ * @type {EventTarget~Event}
+ */
+
+ /**
+ * Triggered when tracks are added or removed on the Tech {@link TextTrackList}
+ *
+ * @event Tech#texttrackchange
+ * @type {EventTarget~Event}
+ */
+ NORMAL.names.forEach(function (name) {
+ var props = NORMAL[name];
+
+ var trackListChanges = function trackListChanges() {
+ _this4.trigger(name + "trackchange");
+ };
+
+ var tracks = _this4[props.getterName]();
+
+ tracks.addEventListener('removetrack', trackListChanges);
+ tracks.addEventListener('addtrack', trackListChanges);
+
+ _this4.on('dispose', function () {
+ tracks.removeEventListener('removetrack', trackListChanges);
+ tracks.removeEventListener('addtrack', trackListChanges);
+ });
+ });
+ }
+ /**
+ * Emulate TextTracks using vtt.js if necessary
+ *
+ * @fires Tech#vttjsloaded
+ * @fires Tech#vttjserror
+ */
+ ;
+
+ _proto.addWebVttScript_ = function addWebVttScript_() {
+ var _this5 = this;
+
+ if ((global_window__WEBPACK_IMPORTED_MODULE_0___default().WebVTT)) {
+ return;
+ } // Initially, Tech.el_ is a child of a dummy-div wait until the Component system
+ // signals that the Tech is ready at which point Tech.el_ is part of the DOM
+ // before inserting the WebVTT script
+
+
+ if (global_document__WEBPACK_IMPORTED_MODULE_1___default().body.contains(this.el())) {
+ // load via require if available and vtt.js script location was not passed in
+ // as an option. novtt builds will turn the above require call into an empty object
+ // which will cause this if check to always fail.
+ if (!this.options_['vtt.js'] && isPlain((videojs_vtt_js__WEBPACK_IMPORTED_MODULE_10___default())) && Object.keys((videojs_vtt_js__WEBPACK_IMPORTED_MODULE_10___default())).length > 0) {
+ this.trigger('vttjsloaded');
+ return;
+ } // load vtt.js via the script location option or the cdn of no location was
+ // passed in
+
+
+ var script = global_document__WEBPACK_IMPORTED_MODULE_1___default().createElement('script');
+ script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.14.1/vtt.min.js';
+
+ script.onload = function () {
+ /**
+ * Fired when vtt.js is loaded.
+ *
+ * @event Tech#vttjsloaded
+ * @type {EventTarget~Event}
+ */
+ _this5.trigger('vttjsloaded');
+ };
+
+ script.onerror = function () {
+ /**
+ * Fired when vtt.js was not loaded due to an error
+ *
+ * @event Tech#vttjsloaded
+ * @type {EventTarget~Event}
+ */
+ _this5.trigger('vttjserror');
+ };
+
+ this.on('dispose', function () {
+ script.onload = null;
+ script.onerror = null;
+ }); // but have not loaded yet and we set it to true before the inject so that
+ // we don't overwrite the injected window.WebVTT if it loads right away
+
+ (global_window__WEBPACK_IMPORTED_MODULE_0___default().WebVTT) = true;
+ this.el().parentNode.appendChild(script);
+ } else {
+ this.ready(this.addWebVttScript_);
+ }
+ }
+ /**
+ * Emulate texttracks
+ *
+ */
+ ;
+
+ _proto.emulateTextTracks = function emulateTextTracks() {
+ var _this6 = this;
+
+ var tracks = this.textTracks();
+ var remoteTracks = this.remoteTextTracks();
+
+ var handleAddTrack = function handleAddTrack(e) {
+ return tracks.addTrack(e.track);
+ };
+
+ var handleRemoveTrack = function handleRemoveTrack(e) {
+ return tracks.removeTrack(e.track);
+ };
+
+ remoteTracks.on('addtrack', handleAddTrack);
+ remoteTracks.on('removetrack', handleRemoveTrack);
+ this.addWebVttScript_();
+
+ var updateDisplay = function updateDisplay() {
+ return _this6.trigger('texttrackchange');
+ };
+
+ var textTracksChanges = function textTracksChanges() {
+ updateDisplay();
+
+ for (var i = 0; i < tracks.length; i++) {
+ var track = tracks[i];
+ track.removeEventListener('cuechange', updateDisplay);
+
+ if (track.mode === 'showing') {
+ track.addEventListener('cuechange', updateDisplay);
+ }
+ }
+ };
+
+ textTracksChanges();
+ tracks.addEventListener('change', textTracksChanges);
+ tracks.addEventListener('addtrack', textTracksChanges);
+ tracks.addEventListener('removetrack', textTracksChanges);
+ this.on('dispose', function () {
+ remoteTracks.off('addtrack', handleAddTrack);
+ remoteTracks.off('removetrack', handleRemoveTrack);
+ tracks.removeEventListener('change', textTracksChanges);
+ tracks.removeEventListener('addtrack', textTracksChanges);
+ tracks.removeEventListener('removetrack', textTracksChanges);
+
+ for (var i = 0; i < tracks.length; i++) {
+ var track = tracks[i];
+ track.removeEventListener('cuechange', updateDisplay);
+ }
+ });
+ }
+ /**
+ * Create and returns a remote {@link TextTrack} object.
+ *
+ * @param {string} kind
+ * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)
+ *
+ * @param {string} [label]
+ * Label to identify the text track
+ *
+ * @param {string} [language]
+ * Two letter language abbreviation
+ *
+ * @return {TextTrack}
+ * The TextTrack that gets created.
+ */
+ ;
+
+ _proto.addTextTrack = function addTextTrack(kind, label, language) {
+ if (!kind) {
+ throw new Error('TextTrack kind is required but was not provided');
+ }
+
+ return createTrackHelper(this, kind, label, language);
+ }
+ /**
+ * Create an emulated TextTrack for use by addRemoteTextTrack
+ *
+ * This is intended to be overridden by classes that inherit from
+ * Tech in order to create native or custom TextTracks.
+ *
+ * @param {Object} options
+ * The object should contain the options to initialize the TextTrack with.
+ *
+ * @param {string} [options.kind]
+ * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata).
+ *
+ * @param {string} [options.label].
+ * Label to identify the text track
+ *
+ * @param {string} [options.language]
+ * Two letter language abbreviation.
+ *
+ * @return {HTMLTrackElement}
+ * The track element that gets created.
+ */
+ ;
+
+ _proto.createRemoteTextTrack = function createRemoteTextTrack(options) {
+ var track = mergeOptions(options, {
+ tech: this
+ });
+ return new REMOTE.remoteTextEl.TrackClass(track);
+ }
+ /**
+ * Creates a remote text track object and returns an html track element.
+ *
+ * > Note: This can be an emulated {@link HTMLTrackElement} or a native one.
+ *
+ * @param {Object} options
+ * See {@link Tech#createRemoteTextTrack} for more detailed properties.
+ *
+ * @param {boolean} [manualCleanup=true]
+ * - When false: the TextTrack will be automatically removed from the video
+ * element whenever the source changes
+ * - When True: The TextTrack will have to be cleaned up manually
+ *
+ * @return {HTMLTrackElement}
+ * An Html Track Element.
+ *
+ * @deprecated The default functionality for this function will be equivalent
+ * to "manualCleanup=false" in the future. The manualCleanup parameter will
+ * also be removed.
+ */
+ ;
+
+ _proto.addRemoteTextTrack = function addRemoteTextTrack(options, manualCleanup) {
+ var _this7 = this;
+
+ if (options === void 0) {
+ options = {};
+ }
+
+ var htmlTrackElement = this.createRemoteTextTrack(options);
+
+ if (manualCleanup !== true && manualCleanup !== false) {
+ // deprecation warning
+ log.warn('Calling addRemoteTextTrack without explicitly setting the "manualCleanup" parameter to `true` is deprecated and default to `false` in future version of video.js');
+ manualCleanup = true;
+ } // store HTMLTrackElement and TextTrack to remote list
+
+
+ this.remoteTextTrackEls().addTrackElement_(htmlTrackElement);
+ this.remoteTextTracks().addTrack(htmlTrackElement.track);
+
+ if (manualCleanup !== true) {
+ // create the TextTrackList if it doesn't exist
+ this.ready(function () {
+ return _this7.autoRemoteTextTracks_.addTrack(htmlTrackElement.track);
+ });
+ }
+
+ return htmlTrackElement;
+ }
+ /**
+ * Remove a remote text track from the remote `TextTrackList`.
+ *
+ * @param {TextTrack} track
+ * `TextTrack` to remove from the `TextTrackList`
+ */
+ ;
+
+ _proto.removeRemoteTextTrack = function removeRemoteTextTrack(track) {
+ var trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track); // remove HTMLTrackElement and TextTrack from remote list
+
+ this.remoteTextTrackEls().removeTrackElement_(trackElement);
+ this.remoteTextTracks().removeTrack(track);
+ this.autoRemoteTextTracks_.removeTrack(track);
+ }
+ /**
+ * Gets available media playback quality metrics as specified by the W3C's Media
+ * Playback Quality API.
+ *
+ * @see [Spec]{@link https://wicg.github.io/media-playback-quality}
+ *
+ * @return {Object}
+ * An object with supported media playback quality metrics
+ *
+ * @abstract
+ */
+ ;
+
+ _proto.getVideoPlaybackQuality = function getVideoPlaybackQuality() {
+ return {};
+ }
+ /**
+ * Attempt to create a floating video window always on top of other windows
+ * so that users may continue consuming media while they interact with other
+ * content sites, or applications on their device.
+ *
+ * @see [Spec]{@link https://wicg.github.io/picture-in-picture}
+ *
+ * @return {Promise|undefined}
+ * A promise with a Picture-in-Picture window if the browser supports
+ * Promises (or one was passed in as an option). It returns undefined
+ * otherwise.
+ *
+ * @abstract
+ */
+ ;
+
+ _proto.requestPictureInPicture = function requestPictureInPicture() {
+ var PromiseClass = this.options_.Promise || (global_window__WEBPACK_IMPORTED_MODULE_0___default().Promise);
+
+ if (PromiseClass) {
+ return PromiseClass.reject();
+ }
+ }
+ /**
+ * A method to check for the value of the 'disablePictureInPicture'