cloudinary-video-player
Version:
Cloudinary Video Player
3,415 lines • 1.78 MB
JavaScript
/*!
* Cloudinary Video Player v3.2.1
* Built on 2025-08-12T18:54:00.175Z
* https://github.com/cloudinary/cloudinary-video-player
*/
/*
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["cloudinary-video-player"] = factory();
else
root["cloudinary-video-player"] = factory();
})(self, () => {
return /******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./components/component-utils.js":
/*!***************************************!*\
!*** ./components/component-utils.js ***!
\***************************************/
/***/ ((module) => {
eval("const hide = el => {\n el.style.display = 'none';\n};\nconst show = el => {\n el.style.display = '';\n};\nconst setText = (el, text) => {\n if (!text || text.length <= 0) {\n el.innerText = '';\n hide(el);\n return;\n }\n el.innerText = text;\n show(el);\n};\nmodule.exports = {\n hide,\n show,\n setText\n};\n\n//# sourceURL=webpack://cloudinary-video-player/./components/component-utils.js?");
/***/ }),
/***/ "./components/index.js":
/*!*****************************!*\
!*** ./components/index.js ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ JumpBackButton: () => (/* reexport safe */ _jumpButtons_jump_10_minus__WEBPACK_IMPORTED_MODULE_1__[\"default\"]),\n/* harmony export */ JumpForwardButton: () => (/* reexport safe */ _jumpButtons_jump_10_plus__WEBPACK_IMPORTED_MODULE_0__[\"default\"]),\n/* harmony export */ LogoButton: () => (/* reexport safe */ _logoButton_logo_button__WEBPACK_IMPORTED_MODULE_2__[\"default\"]),\n/* harmony export */ ProgressControlEventsBlocker: () => (/* reexport safe */ _progress_control_events_blocker_progress_control_events_blocker__WEBPACK_IMPORTED_MODULE_3__[\"default\"]),\n/* harmony export */ TitleBar: () => (/* reexport safe */ _title_bar_title_bar__WEBPACK_IMPORTED_MODULE_4__[\"default\"])\n/* harmony export */ });\n/* harmony import */ var _jumpButtons_jump_10_plus__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./jumpButtons/jump-10-plus */ \"./components/jumpButtons/jump-10-plus.js\");\n/* harmony import */ var _jumpButtons_jump_10_minus__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./jumpButtons/jump-10-minus */ \"./components/jumpButtons/jump-10-minus.js\");\n/* harmony import */ var _logoButton_logo_button__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./logoButton/logo-button */ \"./components/logoButton/logo-button.js\");\n/* harmony import */ var _progress_control_events_blocker_progress_control_events_blocker__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./progress-control-events-blocker/progress-control-events-blocker */ \"./components/progress-control-events-blocker/progress-control-events-blocker.js\");\n/* harmony import */ var _title_bar_title_bar__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./title-bar/title-bar */ \"./components/title-bar/title-bar.js\");\n\n\n\n\n\n\n\n//# sourceURL=webpack://cloudinary-video-player/./components/index.js?");
/***/ }),
/***/ "./components/jumpButtons/jump-10-minus.js":
/*!*************************************************!*\
!*** ./components/jumpButtons/jump-10-minus.js ***!
\*************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n\nconst ClickableComponent = video_js__WEBPACK_IMPORTED_MODULE_0___default().getComponent('ClickableComponent');\nclass JumpBackButton extends ClickableComponent {\n handleClick(event) {\n super.handleClick(event);\n this.player().currentTime(this.player().currentTime() - 10);\n }\n createEl() {\n return video_js__WEBPACK_IMPORTED_MODULE_0___default().dom.createEl('button', {\n className: 'vjs-control vjs-icon-skip-10-min vjs-icon-replay-10 vjs-button',\n ariaLabel: 'Jump back 10 seconds'\n });\n }\n}\nvideo_js__WEBPACK_IMPORTED_MODULE_0___default().registerComponent('JumpBackButton', JumpBackButton);\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (JumpBackButton);\n\n//# sourceURL=webpack://cloudinary-video-player/./components/jumpButtons/jump-10-minus.js?");
/***/ }),
/***/ "./components/jumpButtons/jump-10-plus.js":
/*!************************************************!*\
!*** ./components/jumpButtons/jump-10-plus.js ***!
\************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n\nconst ClickableComponent = video_js__WEBPACK_IMPORTED_MODULE_0___default().getComponent('ClickableComponent');\nclass JumpForwardButton extends ClickableComponent {\n handleClick(event) {\n super.handleClick(event);\n this.player().currentTime(this.player().currentTime() + 10);\n }\n createEl() {\n return video_js__WEBPACK_IMPORTED_MODULE_0___default().dom.createEl('button', {\n className: 'vjs-control vjs-icon-skip-10-plus vjs-icon-forward-10 vjs-button',\n ariaLabel: 'Jump forward 10 seconds'\n });\n }\n}\nvideo_js__WEBPACK_IMPORTED_MODULE_0___default().registerComponent('JumpForwardButton', JumpForwardButton);\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (JumpForwardButton);\n\n//# sourceURL=webpack://cloudinary-video-player/./components/jumpButtons/jump-10-plus.js?");
/***/ }),
/***/ "./components/logoButton/logo-button.js":
/*!**********************************************!*\
!*** ./components/logoButton/logo-button.js ***!
\**********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _logo_button_scss__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./logo-button.scss */ \"./components/logoButton/logo-button.scss\");\n\n\n\n// support VJS5 & VJS6 at the same time\nconst ClickableComponent = video_js__WEBPACK_IMPORTED_MODULE_0___default().getComponent('ClickableComponent');\nclass LogoButton extends ClickableComponent {\n createEl() {\n const opts = this.options_.playerOptions;\n const display = opts.showLogo ? 'block' : 'none';\n const bgImage = opts.logoImageUrl ? `background-image: url(${opts.logoImageUrl})` : '';\n return video_js__WEBPACK_IMPORTED_MODULE_0___default().dom.createEl('a', {}, {\n class: 'vjs-control vjs-cloudinary-button vjs-button',\n href: opts.logoOnclickUrl,\n target: '_blank',\n style: `display: ${display}; ${bgImage}`,\n 'aria-label': 'Logo link'\n });\n }\n}\nvideo_js__WEBPACK_IMPORTED_MODULE_0___default().registerComponent('logoButton', LogoButton);\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (LogoButton);\n\n//# sourceURL=webpack://cloudinary-video-player/./components/logoButton/logo-button.js?");
/***/ }),
/***/ "./components/progress-control-events-blocker/progress-control-events-blocker.js":
/*!***************************************************************************************!*\
!*** ./components/progress-control-events-blocker/progress-control-events-blocker.js ***!
\***************************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n\nconst Component = video_js__WEBPACK_IMPORTED_MODULE_0___default().getComponent('Component');\nclass ProgressControlEventsBlocker extends Component {\n constructor(player) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n super(player, options);\n }\n createEl() {\n return super.createEl('div', {\n className: 'vjs-progress-control-events-blocker'\n });\n }\n}\nvideo_js__WEBPACK_IMPORTED_MODULE_0___default().registerComponent('progressControlEventsBlocker', ProgressControlEventsBlocker);\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ProgressControlEventsBlocker);\n\n//# sourceURL=webpack://cloudinary-video-player/./components/progress-control-events-blocker/progress-control-events-blocker.js?");
/***/ }),
/***/ "./components/recommendations-overlay/index.js":
/*!*****************************************************!*\
!*** ./components/recommendations-overlay/index.js ***!
\*****************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ lazyRecommendationsOverlayComponent)\n/* harmony export */ });\nasync function lazyRecommendationsOverlayComponent(player) {\n try {\n if (!player.getChild('recommendationsOverlay')) {\n await Promise.all(/*! import() | recommendations-overlay */[__webpack_require__.e(\"styles\"), __webpack_require__.e(\"recommendations-overlay\")]).then(__webpack_require__.bind(__webpack_require__, /*! ./recommendations-overlay */ \"./components/recommendations-overlay/recommendations-overlay.js\"));\n player.addChild('recommendationsOverlay');\n }\n return player;\n } catch (error) {\n console.error('Failed to load plugin:', error);\n }\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./components/recommendations-overlay/index.js?");
/***/ }),
/***/ "./components/title-bar/title-bar.js":
/*!*******************************************!*\
!*** ./components/title-bar/title-bar.js ***!
\*******************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var assets_styles_components_title_bar_scss__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! assets/styles/components/title-bar.scss */ \"./assets/styles/components/title-bar.scss\");\n/* harmony import */ var _component_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../component-utils */ \"./components/component-utils.js\");\n/* harmony import */ var _component_utils__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_component_utils__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! plugins/cloudinary/common */ \"./plugins/cloudinary/common.js\");\n\n\n\n\n\n// support VJS5 & VJS6 at the same time\nconst dom = (video_js__WEBPACK_IMPORTED_MODULE_0___default().dom) || (video_js__WEBPACK_IMPORTED_MODULE_0___default());\nconst Component = video_js__WEBPACK_IMPORTED_MODULE_0___default().getComponent('Component');\nclass TitleBar extends Component {\n constructor(player) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n super(player, options);\n this.on(player, 'cldsourcechanged', (_, _ref) => {\n let {\n source\n } = _ref;\n return this.setItem(source);\n });\n }\n setItem(source) {\n if (!source) {\n this.setTitle('');\n this.setDescription('');\n return;\n }\n const info = source.info();\n this.setTitle(info.title);\n this.setDescription(info.subtitle);\n\n // auto-fetch title/description if `true`\n const shouldFetchTitle = source.title && source.title() === true;\n const shouldFetchDescription = source.description && source.description() === true;\n if (shouldFetchTitle || shouldFetchDescription) {\n this.fetchAutoMetadata(source, shouldFetchTitle, shouldFetchDescription);\n }\n }\n fetchAutoMetadata(source, fetchTitle, fetchDescription) {\n if (source.isRawUrl) return;\n const config = source.cloudinaryConfig();\n const publicId = source.publicId();\n if (!config?.cloud_name || !publicId) return;\n const urlPrefix = (0,plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_3__.getCloudinaryUrlPrefix)(config);\n const deliveryType = source.getInitOptions().type || 'upload';\n const metadataUrl = `${urlPrefix}/_applet_/video_service/video_metadata/${deliveryType}/${publicId}.json`;\n fetch(metadataUrl).then(response => {\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\n return response.json();\n }).then(metadata => {\n if (fetchTitle && metadata.title) {\n this.setTitle(metadata.title);\n }\n if (fetchDescription && metadata.description) {\n this.setDescription(metadata.description);\n }\n }).catch(error => {\n console.warn(`Failed to fetch metadata for ${publicId}:`, error);\n });\n }\n setTitle(text) {\n const displayText = typeof text === 'string' ? text : '';\n _component_utils__WEBPACK_IMPORTED_MODULE_2___default().setText(this.titleEl, displayText);\n this.refresh();\n return displayText;\n }\n setDescription(text) {\n const displayText = typeof text === 'string' ? text : '';\n _component_utils__WEBPACK_IMPORTED_MODULE_2___default().setText(this.descriptionEl, displayText);\n this.refresh();\n return displayText;\n }\n refresh() {\n const titleValue = () => this.titleEl.innerText;\n const descriptionValue = () => this.descriptionEl.innerText;\n if (!titleValue() && !descriptionValue()) {\n this.hide();\n return;\n }\n this.show();\n }\n createEl() {\n this.titleEl = dom.createEl('div', {\n className: 'vjs-title-bar-title'\n });\n this.descriptionEl = dom.createEl('div', {\n className: 'vjs-title-bar-subtitle'\n });\n const el = super.createEl('div', {\n append: this.titleEl,\n className: 'vjs-title-bar'\n });\n el.appendChild(this.titleEl);\n el.appendChild(this.descriptionEl);\n return el;\n }\n}\nvideo_js__WEBPACK_IMPORTED_MODULE_0___default().registerComponent('titleBar', TitleBar);\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (TitleBar);\n\n//# sourceURL=webpack://cloudinary-video-player/./components/title-bar/title-bar.js?");
/***/ }),
/***/ "./config/defaults.js":
/*!****************************!*\
!*** ./config/defaults.js ***!
\****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _plugins_context_menu_contextMenuContent__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../plugins/context-menu/contextMenuContent */ \"./plugins/context-menu/contextMenuContent.js\");\n/* harmony import */ var _video_player_const__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../video-player.const */ \"./video-player.const.js\");\n\n\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({\n logoOnclickUrl: 'https://cloudinary.com/',\n showLogo: true,\n showJumpControls: false,\n playsinline: (video_js__WEBPACK_IMPORTED_MODULE_0___default().browser).IS_IOS,\n skin: 'dark',\n controls: false,\n chaptersButton: false,\n pictureInPictureToggle: false,\n seekThumbnails: true,\n aiHighlightsGraph: false,\n visualSearch: false,\n download: false,\n preload: _video_player_const__WEBPACK_IMPORTED_MODULE_2__.PRELOAD.AUTO,\n textTrackSettings: false,\n loop: false,\n muted: false,\n posterOptions: {},\n sourceTypes: ['auto'],\n contextMenu: {\n content: _plugins_context_menu_contextMenuContent__WEBPACK_IMPORTED_MODULE_1__[\"default\"]\n },\n floatingWhenNotVisible: _video_player_const__WEBPACK_IMPORTED_MODULE_2__.FLOATING_TO.NONE,\n hideContextMenu: false,\n analytics: false,\n cloudinaryAnalytics: true,\n allowUsageReport: true,\n playedEventPercents: [25, 50, 75, 100],\n adaptiveStreaming: {\n strategy: 'balanced'\n },\n html5: {\n handlePartialData: false,\n nativeTextTracks: false\n },\n disableSeekWhileScrubbingOnMobile: true\n});\n\n//# sourceURL=webpack://cloudinary-video-player/./config/defaults.js?");
/***/ }),
/***/ "./extended-events.js":
/*!****************************!*\
!*** ./extended-events.js ***!
\****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__),\n/* harmony export */ normalizeEventsParam: () => (/* binding */ normalizeEventsParam)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var events__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! events */ \"../node_modules/events/events.js\");\n/* harmony import */ var events__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(events__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var lodash_isObject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! lodash/isObject */ \"../node_modules/lodash/isObject.js\");\n/* harmony import */ var lodash_isObject__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(lodash_isObject__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _utils_consts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./utils/consts */ \"./utils/consts.js\");\n\n\n\n\nconst EVENT_DEFAULTS = {\n percentsplayed: {\n percents: [25, 50, 75, 100]\n }\n};\nconst DEFAULT_EVENTS = [_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PERCENTS_PLAYED, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PAUSE_NO_SEEK, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.SEEK, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.MUTE, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.UNMUTE, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.QUALITY_CHANGED];\nconst DEFAULT_OPTIONS = {\n events: DEFAULT_EVENTS\n};\n\n// Emits the following additional events:\n// percentsplayed, timeplayed, pausenoseek, seek, mute, unmute\nclass ExtendedEvents extends (events__WEBPACK_IMPORTED_MODULE_1___default()) {\n constructor(player) {\n let initOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n super();\n this.player = player;\n const options = video_js__WEBPACK_IMPORTED_MODULE_0___default().obj.merge(DEFAULT_OPTIONS, initOptions);\n let _muteData = {\n lastState: undefined\n };\n let _seekStart = 0;\n let _seekEnd = 0;\n let _seeking = false;\n let _percentsTracked = [];\n let _timesTracked = [];\n let _currentSource = null;\n let _ended = false;\n const volumechange = event => {\n if (this.player.muted() && _muteData.lastState !== 'muted') {\n _muteData.lastState = 'muted';\n this.emit(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.MUTE, event);\n } else if (!this.player.muted() && _muteData.lastState !== 'unmuted') {\n _muteData.lastState = 'unmuted';\n this.emit(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.UNMUTE, event);\n }\n };\n const timeupdate = event => {\n const currentTime = this.player.currentTime();\n const duration = this.player.duration();\n const _emit = (type, data) => {\n data.originalType = 'timeupdate';\n this.emit(type, event, data);\n };\n if (this.events.percentsplayed) {\n this.events.percentsplayed.percents.forEach(percent => {\n if (playedAtPercentage(currentTime, duration, percent) && _percentsTracked.indexOf(percent) === -1) {\n _percentsTracked.push(percent);\n _emit(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PERCENTS_PLAYED, {\n percent\n });\n }\n });\n }\n if (this.events.timeplayed) {\n const timeplayed = this.events.timeplayed;\n const times = timeplayed.interval ? [Math.floor(currentTime / timeplayed.interval) * timeplayed.interval] : timeplayed.times;\n times.forEach(time => {\n if (playedAtTime(currentTime, time) && _timesTracked.indexOf(time) === -1) {\n _timesTracked.push(time);\n _emit(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.TIME_PLAYED, {\n time\n });\n }\n });\n }\n if (this.events.seek) {\n _seekStart = _seekEnd;\n _seekEnd = currentTime;\n if (Math.abs(_seekStart - _seekEnd) > 1) {\n _seeking = true;\n\n // should empty _timesTracked array on seek, needed for 'timeplayed' event\n resetPerVideoState();\n _emit(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.SEEK, {\n seekStart: _seekStart,\n seekEnd: _seekEnd\n });\n }\n }\n };\n const pause = event => {\n const currentTime = Math.round(this.player.currentTime());\n const duration = Math.round(this.player.duration());\n if (currentTime !== duration && !_seeking) {\n this.emit(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PAUSE_NO_SEEK, event);\n }\n };\n const play = () => {\n _seeking = false;\n };\n const replay = () => {\n if (_ended) {\n this.player.trigger('replay');\n _ended = false;\n }\n };\n const loadedmetadata = () => {\n if (this.player.currentSource().src !== _currentSource) {\n resetPerVideoState();\n _currentSource = this.player.currentSource().src;\n }\n };\n const adaptiveEvents = event => {\n let ee = this;\n let tracks = this.player.textTracks();\n let segmentMetadataTrack = null;\n for (let i = 0; i < tracks.length; i++) {\n if (tracks[i].label === 'segment-metadata') {\n segmentMetadataTrack = tracks[i];\n }\n }\n let previousResolution = null;\n if (segmentMetadataTrack) {\n segmentMetadataTrack.on('cuechange', function () {\n let activeCue = segmentMetadataTrack.activeCues[0];\n if (activeCue) {\n let currentRes = activeCue.value.resolution;\n if (previousResolution !== currentRes) {\n let data = {\n from: previousResolution,\n to: currentRes\n };\n ee.emit(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.QUALITY_CHANGED, event, data);\n }\n previousResolution = currentRes;\n }\n });\n }\n };\n const resetState = () => {\n _muteData = {\n lastState: undefined\n };\n _seekStart = _seekEnd = 0;\n _seeking = false;\n resetPerVideoState();\n };\n const resetPerVideoState = () => {\n _percentsTracked = [];\n _timesTracked = [];\n };\n const ended = () => {\n _ended = true;\n };\n this.events = normalizeEventsParam(options.events, EVENT_DEFAULTS);\n resetState();\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PLAY, replay.bind(this));\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.ENDED, ended.bind(this));\n if (this.events.percentsplayed || this.events.timeplayed || this.events.seek || this.events.totaltimeplayed) {\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.TIME_UPDATE, timeupdate.bind(this));\n }\n if (this.events.mute || this.events.unmute) {\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.VOLUME_CHANGE, volumechange.bind(this));\n }\n if (this.events.pausenoseek) {\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PAUSE, pause.bind(this));\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PLAY, play.bind(this));\n }\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.LOADED_METADATA, loadedmetadata.bind(this));\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.LOADED_DATA, adaptiveEvents.bind(this));\n }\n}\nconst normalizeEventsParam = (events, defaults) => {\n let normalized = events;\n if (events.constructor.name === 'Array') {\n normalized = events.reduce((agg, item) => {\n const eventDefaults = defaults[item] || {};\n if (lodash_isObject__WEBPACK_IMPORTED_MODULE_2___default()(item)) {\n agg[item.type] = Object.assign({}, eventDefaults, item);\n } else {\n agg[item] = eventDefaults;\n }\n return agg;\n }, {});\n }\n return normalized;\n};\nconst playedAtPercentage = function (currentTime, duration, percentageCheckpoint) {\n let graceRangeSeconds = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0.5;\n const checkPoint = duration * percentageCheckpoint / 100;\n return playedAtTime(currentTime, checkPoint, graceRangeSeconds);\n};\nconst playedAtTime = function (currentTime, checkpoint) {\n let graceRangeSeconds = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0.5;\n return currentTime <= checkpoint + graceRangeSeconds && currentTime >= checkpoint - graceRangeSeconds;\n};\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ExtendedEvents);\n\n//# sourceURL=webpack://cloudinary-video-player/./extended-events.js?");
/***/ }),
/***/ "./index.js":
/*!******************!*\
!*** ./index.js ***!
\******************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__),\n/* harmony export */ player: () => (/* binding */ player),\n/* harmony export */ players: () => (/* binding */ players),\n/* harmony export */ videoPlayer: () => (/* binding */ videoPlayer),\n/* harmony export */ videoPlayers: () => (/* binding */ videoPlayers)\n/* harmony export */ });\n/* harmony import */ var assets_styles_main_scss__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! assets/styles/main.scss */ \"./assets/styles/main.scss\");\n/* harmony import */ var lodash_pick__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lodash/pick */ \"../node_modules/lodash/pick.js\");\n/* harmony import */ var lodash_pick__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(lodash_pick__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _video_player__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./video-player */ \"./video-player.js\");\n/* harmony import */ var _player__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./player */ \"./player.js\");\n/* harmony import */ var _utils_object__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./utils/object */ \"./utils/object.js\");\n/* harmony import */ var _video_player_const__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./video-player.const */ \"./video-player.const.js\");\n\n\n\n\n\n\nconst getConfig = function () {\n let playerOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n let cloudinaryConfig = arguments.length > 1 ? arguments[1] : undefined;\n const snakeCaseCloudinaryConfig = lodash_pick__WEBPACK_IMPORTED_MODULE_1___default()((0,_utils_object__WEBPACK_IMPORTED_MODULE_4__.convertKeysToSnakeCase)(playerOptions), _video_player_const__WEBPACK_IMPORTED_MODULE_5__.CLOUDINARY_CONFIG_PARAM);\n\n // pick cld-configurations and assign them to cloudinaryConfig\n return Object.assign(playerOptions, {\n cloudinaryConfig: cloudinaryConfig || snakeCaseCloudinaryConfig\n });\n};\nconst getVideoPlayer = config => (id, playerOptions, ready) => new _video_player__WEBPACK_IMPORTED_MODULE_2__[\"default\"](id, getConfig(playerOptions, config), ready);\nconst getVideoPlayers = config => (selector, playerOptions, ready) => _video_player__WEBPACK_IMPORTED_MODULE_2__[\"default\"].all(selector, getConfig(playerOptions, config), ready);\nconst getPlayer = config => (id, playerOptions, ready) => (0,_player__WEBPACK_IMPORTED_MODULE_3__[\"default\"])(id, getConfig(playerOptions, config), ready);\nconst getPlayers = config => (selector, playerOptions, ready) => {\n const nodeList = document.querySelectorAll(selector);\n const playerConfig = getConfig(playerOptions, config);\n return [...nodeList].map(node => (0,_player__WEBPACK_IMPORTED_MODULE_3__[\"default\"])(node, playerConfig, ready));\n};\nconst videoPlayer = getVideoPlayer();\nconst videoPlayers = getVideoPlayers();\nconst player = getPlayer();\nconst players = getPlayers();\nconst cloudinaryVideoPlayerLegacyConfig = config => {\n console.warn('Cloudinary.new() is deprecated and will be removed. Please use cloudinary.videoPlayer() instead.');\n return {\n videoPlayer: getVideoPlayer(config),\n videoPlayers: getVideoPlayers(config)\n };\n};\nconst cloudinary = {\n ...(window.cloudinary || {}),\n videoPlayer,\n videoPlayers,\n player,\n players,\n Cloudinary: {\n // Backwards compatibility with SDK v1\n new: cloudinaryVideoPlayerLegacyConfig\n }\n};\nwindow.cloudinary = cloudinary;\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (cloudinary);\n\n//# sourceURL=webpack://cloudinary-video-player/./index.js?");
/***/ }),
/***/ "./mixins/eventable.js":
/*!*****************************!*\
!*** ./mixins/eventable.js ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nconst Eventable = superclass => class extends superclass {\n constructor() {\n var _this;\n super();\n _this = this;\n const eventable = {\n data: {},\n handlers: {}\n };\n this.on = function () {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n const lastIndex = args.length - 1;\n const func = args[lastIndex];\n eventable.handlers[func] = function (event) {\n event.Player = _this;\n for (var _len2 = arguments.length, _args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {\n _args[_key2 - 1] = arguments[_key2];\n }\n func(event, ..._args);\n };\n args[lastIndex] = eventable.handlers[func];\n return _this.videojs.on(...args);\n };\n this.one = function () {\n for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {\n args[_key3] = arguments[_key3];\n }\n const lastIndex = args.length - 1;\n const func = args[lastIndex];\n eventable.handlers[func] = function (event) {\n event.Player = _this;\n for (var _len4 = arguments.length, _args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {\n _args[_key4 - 1] = arguments[_key4];\n }\n func(event, ..._args);\n delete eventable.handlers[func];\n };\n args[lastIndex] = eventable.handlers[func];\n return _this.videojs.one(...args);\n };\n this.off = function () {\n for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {\n args[_key5] = arguments[_key5];\n }\n const lastIndex = args.length - 1;\n const func = args[lastIndex];\n args[lastIndex] = eventable.handlers[func];\n const res = _this.videojs.off(...args);\n delete eventable.handlers[func];\n return res;\n };\n this.trigger = function () {\n _this.videojs.trigger(...arguments);\n };\n }\n};\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Eventable);\n\n//# sourceURL=webpack://cloudinary-video-player/./mixins/eventable.js?");
/***/ }),
/***/ "./player.js":
/*!*******************!*\
!*** ./player.js ***!
\*******************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__),\n/* harmony export */ getProfile: () => (/* binding */ getProfile)\n/* harmony export */ });\n/* harmony import */ var _video_player__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./video-player */ \"./video-player.js\");\n/* harmony import */ var cloudinary_video_player_profiles__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! cloudinary-video-player-profiles */ \"../node_modules/cloudinary-video-player-profiles/dist/index.js\");\n/* harmony import */ var cloudinary_video_player_profiles__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(cloudinary_video_player_profiles__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./plugins/cloudinary/common */ \"./plugins/cloudinary/common.js\");\n\n\n\nconst isDefaultProfile = profileName => !!cloudinary_video_player_profiles__WEBPACK_IMPORTED_MODULE_1__.defaultProfiles.find(_ref => {\n let {\n name\n } = _ref;\n return profileName === name;\n});\nconst getDefaultProfileConfig = profileName => {\n const profile = cloudinary_video_player_profiles__WEBPACK_IMPORTED_MODULE_1__.defaultProfiles.find(_ref2 => {\n let {\n name\n } = _ref2;\n return profileName === name;\n });\n if (!profile) {\n throw new Error(`Default profile with name ${profileName} does not exist`);\n }\n return profile.config;\n};\nconst getProfile = async (profile, initOptions) => {\n if (isDefaultProfile(profile)) {\n return getDefaultProfileConfig(profile);\n }\n const urlPrefix = (0,_plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_2__.getCloudinaryUrlPrefix)(initOptions.cloudinaryConfig);\n const profileUrl = (0,_plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_2__.isRawUrl)(profile) ? profile : `${urlPrefix}/_applet_/video_service/video_player_profiles/${profile.replaceAll(' ', '+')}.json`;\n return fetch(profileUrl, {\n method: 'GET'\n }).then(res => res.json());\n};\nconst player = async (elem, initOptions, ready) => {\n const {\n profile,\n ...otherInitOptions\n } = initOptions;\n try {\n const profileOptions = profile ? await getProfile(profile, otherInitOptions) : {};\n const options = Object.assign({}, profileOptions.playerOptions, profileOptions.sourceOptions, otherInitOptions, {\n _internalAnalyticsMetadata: {\n newPlayerMethod: true,\n profile: isDefaultProfile(profile) ? profile : !!profile\n }\n });\n const videoPlayer = new _video_player__WEBPACK_IMPORTED_MODULE_0__[\"default\"](elem, options, ready);\n const nativeVideoPlayerSourceMethod = videoPlayer.source;\n videoPlayer.source = (id, options) => {\n const extendedOptions = Object.assign({}, profileOptions.sourceOptions, options);\n return nativeVideoPlayerSourceMethod.call(videoPlayer, id, extendedOptions);\n };\n return videoPlayer;\n } catch (e) {\n const videoPlayer = new _video_player__WEBPACK_IMPORTED_MODULE_0__[\"default\"](elem, otherInitOptions);\n videoPlayer.videojs.error('Invalid profile');\n throw e;\n }\n};\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (player);\n\n//# sourceURL=webpack://cloudinary-video-player/./player.js?");
/***/ }),
/***/ "./plugins/adaptive-streaming/index.js":
/*!*********************************************!*\
!*** ./plugins/adaptive-streaming/index.js ***!
\*********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ lazyAdaptiveStreamingPlugin)\n/* harmony export */ });\nasync function lazyAdaptiveStreamingPlugin(options) {\n const player = this;\n try {\n if (options.isDash && !window.dashjs) {\n await __webpack_require__.e(/*! import() | dash */ \"dash\").then(__webpack_require__.bind(__webpack_require__, /*! videojs-contrib-dash */ \"../node_modules/videojs-contrib-dash/dist/videojs-dash.es.js\"));\n }\n const {\n default: abrPlugin\n } = await __webpack_require__.e(/*! import() | adaptive-streaming */ \"adaptive-streaming\").then(__webpack_require__.bind(__webpack_require__, /*! ./adaptive-streaming */ \"./plugins/adaptive-streaming/adaptive-streaming.js\"));\n abrPlugin(player, options);\n } catch (error) {\n console.error('Failed to load plugin:', error);\n }\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/adaptive-streaming/index.js?");
/***/ }),
/***/ "./plugins/ai-highlights-graph/index.js":
/*!**********************************************!*\
!*** ./plugins/ai-highlights-graph/index.js ***!
\**********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _ai_highlights_graph_scss__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ai-highlights-graph.scss */ \"./plugins/ai-highlights-graph/ai-highlights-graph.scss\");\n\n\n\n// Default options for the plugin.\nlet defaults = {};\n\n/**\n * Function to invoke when the player is ready.\n *\n * @function onPlayerReady\n * @param {Player} player\n * A Video.js player object.\n *\n * @param {Object} [options={}]\n * A plain object containing options for the plugin.\n */\nconst onPlayerReady = function onPlayerReady(player, options) {\n player.addClass('vjs-ai-highlights-graph');\n player.aiHighlightsGraph = new HighlightsGraphPlugin(player, options);\n};\n\n/**\n * A video.js plugin.\n *\n * In the plugin function, the value of `this` is a video.js `Player`\n * instance. You cannot rely on the player being in a \"ready\" state here,\n * depending on how the plugin is invoked. This may or may not be important\n * to you; if not, remove the wait for \"ready\"!\n *\n * @function aiHighlightsGraph\n * @param {Object} [options={}]\n * An object of options left to the plugin author to define.\n */\nfunction aiHighlightsGraph(options) {\n this.ready(() => {\n onPlayerReady(this, video_js__WEBPACK_IMPORTED_MODULE_0___default().obj.merge(defaults, options));\n });\n}\n\n/**\n * HighlightsGraphPlugin class.\n *\n * This class performs all functions related to displaying the AI highlights graph.\n */\nconst HighlightsGraphPlugin = function () {\n /**\n * Plugin class constructor, called by videojs on\n * ready event.\n *\n * @function constructor\n * @param {Player} player\n * A Video.js player object.\n *\n * @param {Object} [options={}]\n * A plain object containing options for the plugin.\n */\n function HighlightsGraphPlugin(player, options) {\n this.player = player;\n this.options = options;\n this.initializeHighlightsGraph();\n return this;\n }\n HighlightsGraphPlugin.prototype.src = function src(source) {\n this.resetPlugin();\n this.options.src = source;\n this.initializeHighlightsGraph();\n };\n HighlightsGraphPlugin.prototype.detach = function detach() {\n this.resetPlugin();\n };\n HighlightsGraphPlugin.prototype.resetPlugin = function resetPlugin() {\n if (this.graphHolder) {\n this.graphHolder.parentNode.removeChild(this.graphHolder);\n }\n delete this.progressBar;\n delete this.graphHolder;\n delete this.lastStyle;\n };\n\n /**\n * Bootstrap the plugin.\n */\n HighlightsGraphPlugin.prototype.initializeHighlightsGraph = function initializeHighlightsGraph() {\n if (!this.options.src) {\n return;\n }\n fetch(this.options.src, {\n credentials: this.player.cloudinary.source?.().withCredentials ? 'include' : 'omit'\n }).then(res => {\n return res.json();\n }).then(res => {\n this.setupHighlightsGraphElement();\n if (this.graphHolder) {\n this.createHighlightsGraph(res);\n }\n });\n };\n HighlightsGraphPlugin.prototype.setupHighlightsGraphElement = function setupHighlightsGraphElement() {\n this.progressBar = this.player.$('.vjs-progress-control');\n if (!this.progressBar) {\n return;\n }\n const graphHolder = this.player.$('.vjs-highlights-graph-display') || document.createElement('div');\n graphHolder.setAttribute('class', 'vjs-highlights-graph-display');\n this.progressBar.appendChild(graphHolder);\n this.graphHolder = graphHolder;\n };\n\n /**\n * Function to create the SVG path element\n */\n HighlightsGraphPlugin.prototype.createPath = function createPath(dataArray, containerWidth, containerHeight) {\n // Calculate the x and y coordinates for each point\n const stepX = containerWidth / (dataArray.length - 1);\n const points = dataArray.map((value, index) => ({\n x: index * stepX,\n y: containerHeight - value * containerHeight\n }));\n\n // Create a smooth line path\n const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n path.setAttribute('fill', 'lightblue');\n\n // Generate the smooth line path data\n let d = `M ${points[0].x},${points[0].y}`;\n for (let i = 0; i < points.length - 1; i++) {\n const xc = (points[i].x + points[i + 1].x) / 2;\n const yc = (points[i].y + points[i + 1].y) / 2;\n d += ` Q ${points[i].x},${points[i].y} ${xc},${yc}`;\n }\n d += ` Q ${points[points.length - 1].x},${points[points.length - 1].y} ${points[points.length - 1].x},${points[points.length - 1].y}`;\n\n // Close the path to fill the region under the line\n d += ` L ${points[points.length - 1].x},${containerHeight} L ${points[0].x},${containerHeight} Z`;\n path.setAttribute('d', d);\n return path;\n };\n HighlightsGraphPlugin.prototype.createHighlightsGraph = function createHighlightsGraph(info) {\n const data = info.data;\n const svgWidth = 600;\n const svgHeight = 20;\n const svg = this.player.$('.vjs-highlights-graph-display > svg') || document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('viewBox', `0 0 ${svgWidth} ${svgHeight}`);\n svg.setAttribute('preserveAspectRatio', 'none');\n svg.setAttribute('width', svgWidth);\n svg.setAttribute('height', svgHeight);\n svg.innerHTML = '';\n const path = this.createPath(data, svgWidth, svgHeight);\n svg.appendChild(path);\n this.graphHolder.appendChild(svg);\n };\n return HighlightsGraphPlugin;\n}();\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (aiHighlightsGraph);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/ai-highlights-graph/index.js?");
/***/ }),
/***/ "./plugins/analytics/index.js":
/*!************************************!*\
!*** ./plugins/analytics/index.js ***!
\************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var utils_slicing__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! utils/slicing */ \"./utils/slicing.js\");\n/* harmony import */ var extended_events__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! extended-events */ \"./extended-events.js\");\n/* harmony import */ var _utils_consts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../utils/consts */ \"./utils/consts.js\");\n\n\n\n\nconst DEFAULT_EVENTS = [_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PLAY, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PAUSE, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.ENDED, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.VOLUME_CHANGE, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.RESIZE, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.ERROR, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.FULL_SCREEN_CHANGE, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.START, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.VIDEO_LOAD, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PERCENTS_PLAYED, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.SEEK, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PLAYER_LOAD];\nconst EVENT_DEFAULTS = {\n percentsplayed: {\n percents: [25, 50, 75, 100]\n }\n};\nconst DEFAULT_OPTIONS = {\n events: DEFAULT_EVENTS,\n category: 'Video',\n defaultLabel: player => player.cloudinary?.currentPublicId() || player.currentSource().src\n};\nclass AnalyticsPlugin {\n constructor(player) {\n let initOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n this.player = player;\n this.options = video_js__WEBPACK_IMPORTED_MODULE_0___default().obj.merge(DEFAULT_OPTIONS, initOptions);\n this.events = (0,extended_events__WEBPACK_IMPORTED_MODULE_2__.normalizeEventsParam)(this.options.events, EVENT_DEFAULTS);\n const extendedEvents = (0,utils_slicing__WEBPACK_IMPORTED_MODULE_1__.sliceProperties)(this.events, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PERCENTS_PLAYED, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.TIME_PLAYED, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PAUSE, _utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.SEEK);\n if (extendedEvents.pause) {\n delete extendedEvents.pause;\n extendedEvents.pausenoseek = {};\n }\n this._extendedEvents = new extended_events__WEBPACK_IMPORTED_MODULE_2__[\"default\"](player, {\n events: extendedEvents\n });\n this._currentSource = null;\n this._startTracked = null;\n this._endTracked = null;\n this.resetState();\n }\n init() {\n const playerLoad = () => {\n this.track({\n action: 'Player Load',\n label: window.location.href,\n nonInteraction: true\n });\n };\n const play = () => {\n this.track({\n action: 'Play'\n });\n };\n const start = () => {\n if (this._startTracked) {\n this.track({\n action: 'Start'\n });\n this._startTracked = true;\n }\n };\n const pause = () => {\n this.track({\n action: 'Pause'\n });\n };\n const ended = () => {\n if (!this._endTracked) {\n this.track({\n action: 'Ended',\n nonInteraction: true\n });\n this._endTracked = true;\n }\n };\n const error = () => {\n this.track({\n action: 'Error',\n nonInteraction: true\n });\n };\n const volumechange = () => {\n const value = this.player.muted() ? 0 : this.player.volume();\n this.track({\n action: 'Volume Change',\n value\n });\n };\n const resize = () => {\n const action = `Resize - ${this.player.width()}x${this.player.height()}}`;\n this.track({\n action\n });\n };\n const fullscreenchange = () => {\n const action = this.player.isFullscreen() ? 'Enter Fullscreen' : 'Exit Fullscreen';\n this.track({\n action\n });\n };\n const percentsPlayed = (event, data) => {\n const {\n percent\n } = data;\n this.track({\n action: `${percent} Percents Played`,\n nonInteraction: true\n });\n };\n const timePlayed = (event, data) => {\n const {\n time\n } = data;\n this.track({\n action: `${time} Seconds Played`,\n value: time,\n nonInteraction: true\n });\n };\n const seek = (event, data) => {\n const {\n seekStart,\n seekEnd\n } = data;\n this.track({\n action: 'Seek Start',\n value: seekStart\n });\n this.track({\n action: 'Seek End',\n value: seekEnd\n });\n };\n const shoppableProductHover = (event, data) => {\n this.track({\n action: 'productHover',\n label: data.productName\n });\n };\n const shoppableProductClick = (event, data) => {\n this.track({\n action: 'productClick',\n label: data.productName\n });\n };\n const shoppableBarMax = () => {\n this.track({\n action: 'shoppableBar',\n label: 'opened'\n });\n };\n const shoppableBarMin = () => {\n this.track({\n action: 'shoppableBar',\n label: 'closed'\n });\n };\n const shoppableReplay = () => {\n this.track({\n action: 'replay'\n });\n };\n const shoppableProductClickPost = (event, data) => {\n this.track({\n action: 'productClickPostPlay',\n label: data.productName\n });\n };\n const shoppableProductHoverPost = (event, data) => {\n this.track({\n action: 'productHoverPostPlay',\n label: data.productName\n });\n };\n if (this.events.shoppable) {\n this.player.on('productHover', shoppableProductHover.bind(this));\n this.player.on('productClick', shoppableProductClick.bind(this));\n this.player.on('productHoverPost', shoppableProductHoverPost.bind(this));\n this.player.on('productClickPost', shoppableProductClickPost.bind(this));\n this.player.on('productBarMin', shoppableBarMin.bind(this));\n this.player.on('productBarMax', shoppableBarMax.bind(this));\n this.player.on('replay', shoppableReplay.bind(this));\n }\n if (this.events.play) {\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PLAY, play.bind(this));\n }\n if (this.events.ended) {\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.ENDED, ended.bind(this));\n }\n if (this.events.volumechange) {\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.VOLUME_CHANGE, volumechange.bind(this));\n }\n if (this.events.resize) {\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.RESIZE, resize.bind(this));\n }\n if (this.events.error) {\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.ERROR, error.bind(this));\n }\n if (this.events.start) {\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PLAYING, start.bind(this));\n }\n if (this.events.fullscreenchange) {\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.FULL_SCREEN_CHANGE, fullscreenchange.bind(this));\n }\n if (this.events.percentsplayed) {\n this._extendedEvents.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PERCENTS_PLAYED, percentsPlayed.bind(this));\n }\n if (this.events.timeplayed) {\n this._extendedEvents.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.TIME_PLAYED, timePlayed.bind(this));\n }\n if (this.events.pause) {\n this._extendedEvents.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.PAUSE_NO_SEEK, pause.bind(this));\n }\n if (this.events.seek) {\n this._extendedEvents.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.SEEK, seek.bind(this));\n }\n if (this.events.playerload) {\n playerLoad();\n }\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_3__.PLAYER_EVENT.LOADED_METADATA, this.loadedmetadata.bind(this));\n }\n track(_ref) {\n let {\n action,\n label,\n value = null,\n nonInteraction = false\n } = _ref;\n const eventData = {\n event_category: this.options.category,\n event_label: label || this.options.defaultLabel(this.player),\n value: value || Math.round(this.player.currentTime()),\n non_interaction: nonInteraction\n };\n window.gtag('event', action, eventData);\n }\n videoload() {\n this.track({\n action: 'Video Load',\n nonInteraction: true\n });\n }\n resetState() {\n this._currentSource = '';\n this._startTracked = false;\n this._endTracked = false;\n }\n loadedmetadata() {\n const src = this.player.currentSource().src;\n if (src !== this._currentSource) {\n this.resetState();\n this._currentSource = src;\n if (this.events.videoload) {\n this.videoload();\n }\n }\n }\n}\n/* harmony default export */ function __WEBPACK_DEFAULT_EXPORT__() {\n let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n new AnalyticsPlugin(this, opts).init();\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/analytics/index.js?");
/***/ }),
/***/ "./plugins/autoplay-on-scroll/index.js":
/*!*********************************************!*\
!*** ./plugins/autoplay-on-scroll/index.js ***!
\*********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var utils_positioning__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! utils/positioning */ \"./utils/positioning.js\");\n/* harmony import */ var utils_slicing__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! utils/slicing */ \"./utils/slicing.js\");\n\n\nconst defaults = {\n fraction: 0.5,\n isMuted: true\n};\nclass AutoplayOnScrollPlugin {\n constructor(player) {\n let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n opts = Object.assign({}, defaults, opts);\n this.player = player;\n let _options = (0,utils_slicing__WEBPACK_IMPORTED_MODULE_1__.sliceProperties)(opts, 'fraction');\n let _pausedByScroll = false;\n let _playedByScroll = false;\n let _pauseHandler = null;\n let _playHandler = null;\n this.init = () => {\n registerEventHandlers();\n checkViewportState();\n };\n const clearEventHandlers = () => {\n window.removeEventListener('DOMContentLoaded', checkViewportState, false);\n window.removeEventListener('load', checkViewportState, false);\n window.removeEventListener('scroll', checkViewportState, false);\n window.removeEventListener('resize', checkViewportState, false);\n this.player.off('pause', _pauseHandler);\n this.player.off('play', _playHandler);\n };\n const pause = () => {\n _pausedByScroll = true;\n _playedByScroll = false;\n this.player.pause();\n };\n const play = () => {\n _pausedByScroll = false;\n _playedByScroll = true;\n this.player.play();\n };\n const checkViewportState = () => {\n const visible = (0,utils_positioning__WEBPACK_IMPORTED_MODULE_0__.isElementInViewport)(this.player.el(), {\n fraction: _options.fraction\n });\n if (visible) {\n if (this.player.paused()) {\n play();\n }\n } else if (!this.player.paused() && !this.player.activePlugins_.floatingPlayer) {\n pause();\n }\n };\n const registerEventHandlers = () => {\n // TODO: find a better replacement for 'pause' since it's being triggered\n // by 'buffering' as well.\n _pauseHandler = () => {\n if (!this.player.waiting && !_pausedByScroll) {\n clearEventHandlers();\n }\n };\n _playHandler = () => {\n if (!_playedByScroll) {\n clearEventHandlers();\n }\n };\n window.addEventListener('DOMContentLoaded', checkViewportState, false);\n window.addEventListener('load', checkViewportState, false);\n window.addEventListener('scroll', checkViewportState, false);\n window.addEventListener('resize', checkViewportState, false);\n this.player.on('pause', _pauseHandler);\n this.player.on('play', _playHandler);\n };\n }\n}\n/* harmony default export */ function __WEBPACK_DEFAULT_EXPORT__() {\n let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n new AutoplayOnScrollPlugin(this, opts).init();\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/autoplay-on-scroll/index.js?");
/***/ }),
/***/ "./plugins/chapters/index.js":
/*!***********************************!*\
!*** ./plugins/chapters/index.js ***!
\***********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ lazyChaptersPlugin)\n/* harmony export */ });\nasync function lazyChaptersPlugin(options) {\n const player = this;\n try {\n const {\n default: initPlugin\n } = await Promise.all(/*! import() | chapters */[__webpack_require__.e(\"styles\"), __webpack_require__.e(\"chapters\")]).then(__webpack_require__.bind(__webpack_require__, /*! ./chapters */ \"./plugins/chapters/chapters.js\"));\n player.ready(() => initPlugin(options, player));\n } catch (error) {\n console.error('Failed to load plugin:', error);\n }\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/chapters/index.js?");
/***/ }),
/***/ "./plugins/cloudinary-analytics/index.js":
/*!***********************************************!*\
!*** ./plugins/cloudinary-analytics/index.js ***!
\***********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var lodash_isPlainObject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lodash/isPlainObject */ \"../node_modules/lodash/isPlainObject.js\");\n/* harmony import */ var lodash_isPlainObject__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(lodash_isPlainObject__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var cloudinary_video_analytics__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! cloudinary-video-analytics */ \"../node_modules/cloudinary-video-analytics/dist/main.js\");\n/* harmony import */ var cloudinary_video_analytics__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(cloudinary_video_analytics__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _utils_consts__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../utils/consts */ \"./utils/consts.js\");\n\n\n\nclass CloudinaryAnalytics {\n constructor(player, options) {\n this.player = player;\n this.cloudinaryAnalytics = (0,cloudinary_video_analytics__WEBPACK_IMPORTED_MODULE_1__.connectCloudinaryAnalytics)(this.player.videoElement, {\n playerAdapter: this.getCloudinaryVideoPlayerAdapter()\n });\n this.currentVideoMetadata = {\n cloudName: null,\n publicId: null\n };\n this.analyticsOptions = options;\n }\n getMetadata = () => ({\n cloudName: this.player.cloudinary.cloudinaryConfig().cloud_name,\n publicId: this.player.cloudinary.currentPublicId()\n });\n sourceChanged = (e, _ref) => {\n let {\n source\n } = _ref;\n const metadata = this.getMetadata();\n if (metadata.cloudName && metadata.publicId) {\n const isLiveStream = source?.resourceConfig().type === 'live';\n this.currentVideoMetadata = metadata;\n this.cloudinaryAnalytics.startManualTracking({\n ...metadata,\n ...(isLiveStream ? {\n type: 'live'\n } : {})\n }, {\n ...(lodash_isPlainObject__WEBPACK_IMPORTED_MODULE_0___default()(this.analyticsOptions) ? this.analyticsOptions : {}),\n videoPlayerType: 'cloudinary video player',\n videoPlayerVersion: \"3.2.1\"\n });\n } else if (this.currentVideoMetadata.cloudName !== metadata.cloudName || this.currentVideoMetadata.publicId !== metadata.publicId) {\n this.cloudinaryAnalytics.stopManualTracking();\n }\n };\n getCloudinaryVideoPlayerAdapter = () => {\n const createCldVPEventListener = (eventName, callback) => {\n this.player.on(eventName, callback);\n return () => {\n this.player.off(eventName, callback);\n };\n };\n return {\n onCanPlay: callback => createCldVPEventListener('canplay', callback),\n onCanPlayThrough: callback => createCldVPEventListener('canplaythrough', callback),\n onComplete: callback => createCldVPEventListener('complete', callback),\n onDurationChange: callback => createCldVPEventListener('durationchange', callback),\n onEmptied: callback => createCldVPEventListener('emptied', callback),\n onEnded: callback => createCldVPEventListener('ended', callback),\n onError: callback => createCldVPEventListener('error', callback),\n onLoadedData: callback => createCldVPEventListener('loadeddata', callback),\n onLoadedMetadata: callback => createCldVPEventListener('loadedmetadata', callback),\n onLoadStart: callback => createCldVPEventListener('loadstart', callback),\n onPause: callback => createCldVPEventListener('pause', callback),\n onPlay: callback => createCldVPEventListener('play', callback),\n onPlaying: callback => createCldVPEventListener('playing', callback),\n onProgress: callback => createCldVPEventListener('progress', callback),\n onRateChange: callback => createCldVPEventListener('ratechange', callback),\n onSeeked: callback => createCldVPEventListener('seeked', callback),\n onSeeking: callback => createCldVPEventListener('seeking', callback),\n onStalled: callback => createCldVPEventListener('stalled', callback),\n onSuspend: callback => createCldVPEventListener('suspend', callback),\n onTimeUpdate: callback => createCldVPEventListener('timeupdate', callback),\n onVolumeChange: callback => createCldVPEventListener('volumechange', callback),\n onWaiting: callback => createCldVPEventListener('waiting', callback),\n getCurrentSrc: () => this.player.videoElement.currentSrc,\n getCurrentTime: () => this.player.currentTime(),\n getReadyState: () => this.player.videoElement.readyState,\n getDuration: () => this.player.duration()\n };\n };\n init() {\n this.player.on(_utils_consts__WEBPACK_IMPORTED_MODULE_2__.PLAYER_EVENT.CLD_SOURCE_CHANGED, this.sourceChanged);\n }\n}\n/* harmony default export */ function __WEBPACK_DEFAULT_EXPORT__() {\n let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n new CloudinaryAnalytics(this, opts).init();\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/cloudinary-analytics/index.js?");
/***/ }),
/***/ "./plugins/cloudinary/common.js":
/*!**************************************!*\
!*** ./plugins/cloudinary/common.js ***!
\**************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ERROR_CODE: () => (/* binding */ ERROR_CODE),\n/* harmony export */ VIDEO_CODEC: () => (/* binding */ VIDEO_CODEC),\n/* harmony export */ cloudinaryErrorsConverter: () => (/* binding */ cloudinaryErrorsConverter),\n/* harmony export */ extendCloudinaryConfig: () => (/* binding */ extendCloudinaryConfig),\n/* harmony export */ getCloudinaryUrl: () => (/* binding */ getCloudinaryUrl),\n/* harmony export */ getCloudinaryUrlPrefix: () => (/* binding */ getCloudinaryUrlPrefix),\n/* harmony export */ isRawUrl: () => (/* binding */ isRawUrl),\n/* harmony export */ isSrcEqual: () => (/* binding */ isSrcEqual),\n/* harmony export */ mergeTransformations: () => (/* binding */ mergeTransformations),\n/* harmony export */ normalizeOptions: () => (/* binding */ normalizeOptions),\n/* harmony export */ setupCloudinaryMiddleware: () => (/* binding */ setupCloudinaryMiddleware)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var lodash_omit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lodash/omit */ \"../node_modules/lodash/omit.js\");\n/* harmony import */ var lodash_omit__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(lodash_omit__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var utils_slicing__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! utils/slicing */ \"./utils/slicing.js\");\n/* harmony import */ var lodash_isObject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! lodash/isObject */ \"../node_modules/lodash/isObject.js\");\n/* harmony import */ var lodash_isObject__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(lodash_isObject__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var lodash_isString__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! lodash/isString */ \"../node_modules/lodash/isString.js\");\n/* harmony import */ var lodash_isString__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(lodash_isString__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _models_video_source_video_source_const__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./models/video-source/video-source.const */ \"./plugins/cloudinary/models/video-source/video-source.const.js\");\n/* harmony import */ var _cloudinary_url_gen_backwards_createCloudinaryLegacyURL__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @cloudinary/url-gen/backwards/createCloudinaryLegacyURL */ \"../node_modules/@cloudinary/url-gen/backwards/createCloudinaryLegacyURL.js\");\n/* harmony import */ var _cloudinary_url_gen_backwards_transformation__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @cloudinary/url-gen/backwards/transformation */ \"../node_modules/@cloudinary/url-gen/backwards/transformation.js\");\n/* harmony import */ var _cloudinary_url_gen_backwards_utils_unsigned_url_prefix__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @cloudinary/url-gen/backwards/utils/unsigned_url_prefix */ \"../node_modules/@cloudinary/url-gen/backwards/utils/unsigned_url_prefix.js\");\n\n\n\n\n\n\n\n\n\nconst normalizeOptions = function (publicId, options) {\n let {\n tolerateMissingId = false\n } = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n if (lodash_isObject__WEBPACK_IMPORTED_MODULE_3___default()(publicId)) {\n const _options = Object.assign({}, publicId);\n publicId = (0,utils_slicing__WEBPACK_IMPORTED_MODULE_2__.sliceAndUnsetProperties)(_options, 'publicId').publicId;\n if (!lodash_isString__WEBPACK_IMPORTED_MODULE_4___default()(publicId) && !tolerateMissingId) {\n throw new Error('Source is missing \\'publicId\\'.');\n }\n if (options) {\n options = Object.assign({}, _options, options);\n }\n }\n return {\n publicId,\n options\n };\n};\nconst isRawUrl = publicId => _models_video_source_video_source_const__WEBPACK_IMPORTED_MODULE_5__.URL_PATTERN.test(publicId);\nconst isSrcEqual = (source1, source2) => {\n let src1 = source1;\n let src2 = source2;\n if (typeof source1 === 'object') {\n src1 = source1.src;\n }\n if (typeof source2 === 'object') {\n src2 = source2.src;\n }\n if (/^\\/\\//.test(src1)) {\n src2 = src2.slice(src2.indexOf('//'));\n }\n if (/^\\/\\//.test(src2)) {\n src1 = src1.slice(src1.indexOf('//'));\n }\n return src1 === src2;\n};\nconst extendCloudinaryConfig = (currentConfig, newConfig) => Object.assign(currentConfig, newConfig);\nconst getCloudinaryUrl = (publicId, transformation) => (0,_cloudinary_url_gen_backwards_createCloudinaryLegacyURL__WEBPACK_IMPORTED_MODULE_6__.createCloudinaryLegacyURL)(publicId, lodash_omit__WEBPACK_IMPORTED_MODULE_1___default()(transformation, ['chainTarget']));\nconst getCloudinaryUrlPrefix = cloudinaryConfig => {\n return (0,_cloudinary_url_gen_backwards_utils_unsigned_url_prefix__WEBPACK_IMPORTED_MODULE_7__.unsigned_url_prefix)(null, cloudinaryConfig.cloud_name, cloudinaryConfig.private_cdn, cloudinaryConfig.cdn_subdomain, cloudinaryConfig.secure_cdn_subdomain, cloudinaryConfig.cname, cloudinaryConfig.secure ?? true, cloudinaryConfig.secure_distribution);\n};\nconst isTransformationInstance = transformation => transformation.constructor.name === 'Transformation' && transformation.toOptions;\nconst mergeTransformations = (initTransformation1, transformation2) => {\n const transformation1 = isTransformationInstance(initTransformation1) ? initTransformation1.toOptions() : initTransformation1;\n return new _cloudinary_url_gen_backwards_transformation__WEBPACK_IMPORTED_MODULE_8__[\"default\"](transformation1).fromOptions(transformation2).toOptions();\n};\nconst ERROR_CODE = {\n NO_SUPPORTED_MEDIA: 6,\n CUSTOM: 10,\n UNKNOWN_CUSTOMER: 11,\n RESOURCE_NOT_FOUND: 12,\n PRIVATE_RESOURCE: 13,\n UNAUTHENTICATED: 14\n};\nconst cloudinaryErrorsConverter = _ref => {\n let {\n errorMsg,\n publicId,\n cloudName,\n statusCode\n } = _ref;\n const msg = 'Video cannot be played';\n let error = {\n code: ERROR_CODE.CUSTOM,\n message: `${msg}${errorMsg ? '- ' + errorMsg : ''}`,\n statusCode: statusCode\n };\n let err = errorMsg.toLowerCase();\n if (err.startsWith('unknown customer')) {\n error.code = ERROR_CODE.UNKNOWN_CUSTOMER;\n error.message = `${msg} Unknown cloud-name ${cloudName}`;\n }\n if (err.startsWith('resource not found')) {\n error.code = ERROR_CODE.RESOURCE_NOT_FOUND;\n error.message = `${msg} Public ID ${publicId} not found`;\n }\n if (err.startsWith('private resource')) {\n error.code = ERROR_CODE.PRIVATE_RESOURCE;\n error.message = `${msg} Private video`;\n }\n if (err.startsWith('unauthenticated access')) {\n error.message = `${msg} Requires authentication`;\n error.code = ERROR_CODE.UNAUTHENTICATED;\n }\n return error;\n};\nconst VIDEO_CODEC = {\n AV1: 'av1',\n VP9: 'vp9',\n HEV1: 'hev1',\n H265: 'h265',\n H264: 'h264'\n};\nconst setupCloudinaryMiddleware = () => {\n // Allow 'auto' as a source type\n video_js__WEBPACK_IMPORTED_MODULE_0___default().use('video/auto', () => {\n return {\n async setSource(srcObj, next) {\n const {\n headers\n } = await fetch(srcObj.src, {\n method: 'HEAD',\n credentials: srcObj.withCredentials ? 'include' : 'omit'\n });\n const mimetype = headers.get('content-type').split(';')[0];\n return next(null, {\n src: srcObj.src,\n type: mimetype\n });\n }\n };\n });\n};\n\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/cloudinary/common.js?");
/***/ }),
/***/ "./plugins/cloudinary/event-handler-registry.js":
/*!******************************************************!*\
!*** ./plugins/cloudinary/event-handler-registry.js ***!
\******************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nclass EventHandlerRegistry {\n constructor(emitter) {\n this._emitter = emitter;\n this._eventHandlers = [];\n }\n on(type, handler) {\n this._eventHandlers.push({\n type,\n handler\n });\n this._emitter.on(type, handler);\n }\n one(type, handler) {\n var _this = this;\n const wrapper = function () {\n handler(...arguments);\n _this.off(type, handler);\n };\n this._eventHandlers.push({\n type,\n handler,\n wrapper\n });\n this._emitter.one(type, handler);\n }\n off(type, handler) {\n const index = this._eventHandlers?.findIndex(event => event.type === type && event.handler === handler);\n if (index === -1) {\n return;\n }\n const event = this._eventHandlers[index];\n this._emitter.off(type, event.wrapper || event.handler);\n this._eventHandlers.splice(index, 1);\n }\n removeAllListeners() {\n this._eventHandlers.forEach(event => {\n this.off(event);\n });\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (EventHandlerRegistry);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/cloudinary/event-handler-registry.js?");
/***/ }),
/***/ "./plugins/cloudinary/index.js":
/*!*************************************!*\
!*** ./plugins/cloudinary/index.js ***!
\*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ CONSTRUCTOR_PARAMS: () => (/* binding */ CONSTRUCTOR_PARAMS),\n/* harmony export */ \"default\": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var lodash_isFunction__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lodash/isFunction */ \"../node_modules/lodash/isFunction.js\");\n/* harmony import */ var lodash_isFunction__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(lodash_isFunction__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var utils_apply_with_props__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! utils/apply-with-props */ \"./utils/apply-with-props.js\");\n/* harmony import */ var utils_slicing__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! utils/slicing */ \"./utils/slicing.js\");\n/* harmony import */ var utils_cloudinary__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! utils/cloudinary */ \"./utils/cloudinary.js\");\n/* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./common */ \"./plugins/cloudinary/common.js\");\n/* harmony import */ var _models_video_source_video_source__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./models/video-source/video-source */ \"./plugins/cloudinary/models/video-source/video-source.js\");\n/* harmony import */ var _event_handler_registry__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./event-handler-registry */ \"./plugins/cloudinary/event-handler-registry.js\");\n/* harmony import */ var _models_audio_source_audio_source__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./models/audio-source/audio-source */ \"./plugins/cloudinary/models/audio-source/audio-source.js\");\n/* harmony import */ var components_recommendations_overlay__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! components/recommendations-overlay */ \"./components/recommendations-overlay/index.js\");\n\n\n\n\n\n\n\n\n\nconst DEFAULT_PARAMS = {\n transformation: {},\n sourceTypes: [],\n sourceTransformation: [],\n posterOptions: {}\n};\nconst CONSTRUCTOR_PARAMS = ['cloudinaryConfig', 'transformation', 'sourceTypes', 'sourceTransformation', 'posterOptions', 'autoShowRecommendations'];\nclass CloudinaryContext {\n constructor(player) {\n var _this = this;\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n (0,_common__WEBPACK_IMPORTED_MODULE_4__.setupCloudinaryMiddleware)();\n this.player = player;\n options = Object.assign({}, DEFAULT_PARAMS, options);\n let _source = null;\n let _sources = null;\n let _lastSource = null;\n let _lastPlaylist = null;\n let _posterOptions = null;\n let _cloudinaryConfig = null;\n let _transformation = null;\n let _sourceTypes = null;\n let _sourceTransformation = null;\n let _chainTarget = options.chainTarget;\n let _playerEvents = null;\n let _recommendations = null;\n let _autoShowRecommendations = false;\n this.source = function (source) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n options = Object.assign({}, options);\n if (!source) {\n return _source;\n }\n let src = null;\n if (source instanceof _models_video_source_video_source__WEBPACK_IMPORTED_MODULE_5__[\"default\"]) {\n src = source;\n } else {\n let {\n publicId,\n options: _options\n } = (0,_common__WEBPACK_IMPORTED_MODULE_4__.normalizeOptions)(source, options);\n src = _this.buildSource(publicId, _options);\n }\n const recommendations = src.recommendations();\n if (recommendations && recommendations.length) {\n let itemBuilder = null;\n let disableAutoShow = false;\n if (options.recommendationOptions) {\n ({\n disableAutoShow,\n itemBuilder\n } = (0,utils_slicing__WEBPACK_IMPORTED_MODULE_2__.sliceAndUnsetProperties)(options.recommendationOptions, 'disableAutoShow', 'itemBuilder'));\n }\n (0,components_recommendations_overlay__WEBPACK_IMPORTED_MODULE_8__[\"default\"])(player).then(() => {\n setRecommendations(recommendations, {\n disableAutoShow,\n itemBuilder\n });\n });\n } else {\n unsetRecommendations();\n }\n _source = src;\n _transformation = src.transformation();\n const isDash = options.sourceTypes && options.sourceTypes.some(s => s.includes('dash')) || typeof source === 'string' && source.endsWith('.mpd');\n const isHls = options.sourceTypes && options.sourceTypes.some(s => s.includes('hls')) || typeof source === 'string' && source.endsWith('.m3u8');\n const isAdaptiveStreamingRequired = isDash || isHls;\n if (isAdaptiveStreamingRequired && !_this.player.adaptiveStreamingLoaded) {\n __webpack_require__.e(/*! import() | adaptive-streaming */ \"adaptive-streaming\").then(__webpack_require__.bind(__webpack_require__, /*! ../adaptive-streaming */ \"./plugins/adaptive-streaming/index.js\")).then(() => {\n _this.player.adaptiveStreaming({\n ...options.adaptiveStreaming,\n isDash,\n debug: options.debug\n }).then(() => {\n refresh();\n });\n }).catch(err => {\n console.error('Failed to load adaptive streaming plugin:', err);\n refresh();\n });\n } else if (!options.skipRefresh) {\n refresh();\n }\n _this.player.trigger('cldsourcechanged', {\n source: src,\n sourceOptions: options\n });\n return _chainTarget;\n };\n this.buildSource = function (publicId) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n let builtSrc = null;\n ({\n publicId,\n options\n } = (0,_common__WEBPACK_IMPORTED_MODULE_4__.normalizeOptions)(publicId, options));\n options.cloudinaryConfig = (0,_common__WEBPACK_IMPORTED_MODULE_4__.extendCloudinaryConfig)(_this.cloudinaryConfig(), options.cloudinaryConfig || {});\n options.transformation = (0,_common__WEBPACK_IMPORTED_MODULE_4__.mergeTransformations)(_this.transformation(), options.transformation || {});\n options.sourceTransformation = options.sourceTransformation || _this.sourceTransformation();\n options.sourceTypes = options.sourceTypes || _this.sourceTypes();\n options.poster = options.poster || posterOptionsForCurrent();\n options.queryParams = Object.assign(options.queryParams || {}, options.allowUsageReport ? {\n _s: `vp-${\"3.2.1\"}`\n } : {});\n if (options.sourceTypes.indexOf('audio') > -1) {\n builtSrc = new _models_audio_source_audio_source__WEBPACK_IMPORTED_MODULE_7__[\"default\"](publicId, options);\n } else {\n builtSrc = new _models_video_source_video_source__WEBPACK_IMPORTED_MODULE_5__[\"default\"](publicId, options);\n }\n return builtSrc;\n };\n this.posterOptions = options => {\n if (!options) {\n return _posterOptions;\n }\n _posterOptions = options;\n return _chainTarget;\n };\n this.disablePoster = posterColor => {\n // https://docs.videojs.com/player.js.html#line3816\n this.player.poster(' ');\n this.player.posterImage.el().style.backgroundColor = posterColor;\n };\n this.cloudinaryConfig = config => {\n if (!config) {\n return _cloudinaryConfig;\n }\n _cloudinaryConfig = config;\n return _chainTarget;\n };\n this.transformation = trans => {\n if (!trans) {\n return _transformation;\n }\n _transformation = trans;\n return _chainTarget;\n };\n this.sourceTypes = types => {\n if (!types) {\n return _sourceTypes;\n }\n _sourceTypes = types;\n return _chainTarget;\n };\n this.getCurrentSources = () => _sources;\n this.sourceTransformation = trans => {\n if (!trans) {\n return _sourceTransformation;\n }\n _sourceTransformation = trans;\n return _chainTarget;\n };\n this.on = function () {\n return _playerEvents.on(...arguments);\n };\n this.one = function () {\n return _playerEvents.one(...arguments);\n };\n this.off = function () {\n return _playerEvents.off(...arguments);\n };\n this.autoShowRecommendations = autoShow => {\n if (autoShow === undefined) {\n return _autoShowRecommendations;\n }\n _autoShowRecommendations = autoShow;\n return _chainTarget;\n };\n this.dispose = () => {\n if (this.playlist && this.playlist()) {\n this.disposePlaylist();\n }\n unsetRecommendations();\n _source = undefined;\n _playerEvents.removeAllListeners();\n };\n const setRecommendations = (recommendations, _ref) => {\n let {\n disableAutoShow = false,\n itemBuilder = null\n } = _ref;\n unsetRecommendations();\n if (!Array.isArray(recommendations) && typeof recommendations !== 'function' && !recommendations.then) {\n throw new Error('\"recommendations\" must be either an array or a function');\n }\n _recommendations = {};\n itemBuilder = itemBuilder || (source => ({\n source: source instanceof _models_video_source_video_source__WEBPACK_IMPORTED_MODULE_5__[\"default\"] ? source : this.buildSource(source),\n action: () => this.source(source)\n }));\n _recommendations.sourceChangedHandler = () => {\n const trigger = sources => {\n if (typeof sources !== 'undefined' && sources.length > 0) {\n const items = sources.map(_source => itemBuilder(_source));\n this.player.trigger('recommendationschanged', {\n items\n });\n } else {\n this.player.trigger('recommendationsnoshow');\n }\n _recommendations.sources = sources;\n };\n if (lodash_isFunction__WEBPACK_IMPORTED_MODULE_0___default()(recommendations)) {\n trigger(recommendations());\n } else if (recommendations.then) {\n recommendations.then(trigger);\n } else {\n trigger(recommendations);\n }\n };\n _recommendations.sourceChangedHandler();\n _recommendations.endedHandler = () => {\n if (!disableAutoShow && this.autoShowRecommendations()) {\n this.player.trigger('recommendationsshow');\n }\n };\n this.on('ended', _recommendations.endedHandler);\n };\n const unsetRecommendations = () => {\n if (_recommendations) {\n this.off('cldsourcechanged', _recommendations.sourceChangedHandler);\n this.off('ended', _recommendations.endedHandler);\n delete _recommendations.endedHandler;\n delete _recommendations.sourceChangedHandler;\n }\n _recommendations = null;\n };\n const refresh = () => {\n const src = this.source();\n if (!src) {\n return;\n }\n const posterOptions = Object.assign({}, this.player.cloudinary.posterOptions(), src.getInitOptions().poster);\n if (posterOptions.posterColor) {\n this.disablePoster(posterOptions.posterColor);\n } else if (src.poster()) {\n this.player.poster(src.poster().url());\n }\n _sources = src.generateSources().reduce((srcs, src) => {\n if (src.isAdaptive) {\n let codec = src.type.split('; ')[1] || null;\n if (codec && 'MediaSource' in window) {\n const parts = src.type.split('; ');\n let typeStr = `video/mp4; ${parts[1] || ''}`;\n const canPlay = testCanPlayTypeAndTypeSupported(typeStr);\n if (canPlay) {\n srcs.push(src);\n }\n } else {\n srcs.push(src);\n }\n } else {\n srcs.push(src);\n }\n return srcs;\n }, []);\n this.player.src(_sources);\n _lastSource = src;\n if (this.playlist) {\n _lastPlaylist = this.playlist();\n }\n };\n const testCanPlayTypeAndTypeSupported = codec => {\n const v = document.createElement('video');\n return v.canPlayType(codec) || 'MediaSource' in window && MediaSource.isTypeSupported(codec);\n };\n const posterOptionsForCurrent = () => {\n const opts = Object.assign({}, this.posterOptions());\n opts.transformation = opts.transformation || {};\n if ((opts.transformation.width || opts.transformation.height) && !opts.transformation.crop) {\n opts.transformation.crop = 'scale';\n }\n\n // Set poster dimensions to player actual size.\n // (unless they were explicitly set via `posterOptions`)\n const playerEl = this.player.el();\n if (playerEl && playerEl.clientWidth && playerEl.clientHeight && !(0,utils_cloudinary__WEBPACK_IMPORTED_MODULE_3__.isKeyInTransformation)(opts.transformation, 'width') && !(0,utils_cloudinary__WEBPACK_IMPORTED_MODULE_3__.isKeyInTransformation)(opts.transformation, 'height')) {\n const roundUp100 = val => 100 * Math.ceil(val / 100);\n opts.transformation = (0,_common__WEBPACK_IMPORTED_MODULE_4__.mergeTransformations)(opts.transformation, {\n width: roundUp100(playerEl.clientWidth),\n height: roundUp100(playerEl.clientHeight),\n crop: 'limit'\n });\n }\n return opts;\n };\n\n // Handle external (non-cloudinary plugin) source changes (e.g. by ad plugins)\n const syncState = (_, data) => {\n let src = data.to;\n\n // When source is cloudinary's\n if (_lastSource && _lastSource.contains(src)) {\n // If plugin state doesn't have an active VideoSource\n if (!this.source()) {\n // We might have been running a playlist, reset playlist's state.\n if (this.playlist && _lastPlaylist) {\n this.playlist(_lastPlaylist);\n }\n // Rebuild last source state without calling vjs's 'src' and 'poster'\n this.source(_lastSource, {\n skipRefresh: true\n });\n }\n } else {\n // Used by cloudinary-only components\n this.player.trigger('cldsourcechanged', {});\n\n // When source isn't cloudinary's - reset the plugin's state.\n this.dispose();\n }\n };\n _playerEvents = new _event_handler_registry__WEBPACK_IMPORTED_MODULE_6__[\"default\"](this.player);\n const constructorParams = (0,utils_slicing__WEBPACK_IMPORTED_MODULE_2__.sliceAndUnsetProperties)(options, ...CONSTRUCTOR_PARAMS);\n (0,utils_apply_with_props__WEBPACK_IMPORTED_MODULE_1__.applyWithProps)(this, constructorParams);\n this.on('sourcechanged', syncState);\n }\n currentSourceType() {\n return this.source().getType();\n }\n currentPublicId() {\n return this.source() && this.source().publicId();\n }\n currentPoster() {\n return this.source() && this.source().poster();\n }\n}\n/* harmony default export */ function __WEBPACK_DEFAULT_EXPORT__() {\n let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n options.chainTarget = options.chainTarget || this;\n this.cloudinary = new CloudinaryContext(this, options);\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/cloudinary/index.js?");
/***/ }),
/***/ "./plugins/cloudinary/models/audio-source/audio-source.const.js":
/*!**********************************************************************!*\
!*** ./plugins/cloudinary/models/audio-source/audio-source.const.js ***!
\**********************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ AUDIO_SUFFIX_REMOVAL_PATTERN: () => (/* binding */ AUDIO_SUFFIX_REMOVAL_PATTERN),\n/* harmony export */ COMMON_AUDIO_FORMATS: () => (/* binding */ COMMON_AUDIO_FORMATS),\n/* harmony export */ DEFAULT_AUDIO_PARAMS: () => (/* binding */ DEFAULT_AUDIO_PARAMS),\n/* harmony export */ DEFAULT_POSTER_PARAMS: () => (/* binding */ DEFAULT_POSTER_PARAMS)\n/* harmony export */ });\nconst DEFAULT_POSTER_PARAMS = {\n format: 'jpg',\n resource_type: 'video',\n transformation: {\n flags: 'waveform'\n }\n};\nconst COMMON_AUDIO_FORMATS = ['mp3', 'ogg', 'wav', 'mp4'];\nconst AUDIO_SUFFIX_REMOVAL_PATTERN = RegExp(`\\\\.(${COMMON_AUDIO_FORMATS.join('|')})$$`);\nconst DEFAULT_AUDIO_PARAMS = {\n resource_type: 'video',\n type: 'upload',\n transformation: []\n};\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/cloudinary/models/audio-source/audio-source.const.js?");
/***/ }),
/***/ "./plugins/cloudinary/models/audio-source/audio-source.js":
/*!****************************************************************!*\
!*** ./plugins/cloudinary/models/audio-source/audio-source.js ***!
\****************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _video_source_video_source__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../video-source/video-source */ \"./plugins/cloudinary/models/video-source/video-source.js\");\n/* harmony import */ var _image_source__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../image-source */ \"./plugins/cloudinary/models/image-source.js\");\n/* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../common */ \"./plugins/cloudinary/common.js\");\n/* harmony import */ var utils_slicing__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! utils/slicing */ \"./utils/slicing.js\");\n/* harmony import */ var utils_querystring__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! utils/querystring */ \"./utils/querystring.js\");\n/* harmony import */ var _audio_source_const__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./audio-source.const */ \"./plugins/cloudinary/models/audio-source/audio-source.const.js\");\n/* harmony import */ var _utils_consts__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../../utils/consts */ \"./utils/consts.js\");\n\n\n\n\n\n\n\nclass AudioSource extends _video_source_video_source__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n constructor(publicId) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n ({\n publicId,\n options\n } = (0,_common__WEBPACK_IMPORTED_MODULE_2__.normalizeOptions)(publicId, options));\n publicId = publicId.replace(_audio_source_const__WEBPACK_IMPORTED_MODULE_5__.AUDIO_SUFFIX_REMOVAL_PATTERN, '');\n options = Object.assign({}, _audio_source_const__WEBPACK_IMPORTED_MODULE_5__.DEFAULT_AUDIO_PARAMS, options);\n const {\n poster\n } = (0,utils_slicing__WEBPACK_IMPORTED_MODULE_3__.sliceAndUnsetProperties)(options, 'poster');\n super(publicId, options);\n this._poster = null;\n this._type = _utils_consts__WEBPACK_IMPORTED_MODULE_6__.SOURCE_TYPE.AUDIO;\n this.poster(poster);\n }\n getPoster() {\n return this._poster;\n }\n poster(publicId) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n if (!publicId) {\n return this._poster;\n }\n if (publicId instanceof _image_source__WEBPACK_IMPORTED_MODULE_1__[\"default\"]) {\n this._poster = publicId;\n return this;\n }\n ({\n publicId,\n options\n } = (0,_common__WEBPACK_IMPORTED_MODULE_2__.normalizeOptions)(publicId, options, {\n tolerateMissingId: true\n }));\n if (!publicId) {\n publicId = this.publicId();\n options = Object.assign({}, options, _audio_source_const__WEBPACK_IMPORTED_MODULE_5__.DEFAULT_POSTER_PARAMS);\n }\n options.cloudinaryConfig = options.cloudinaryConfig || this.cloudinaryConfig();\n this._poster = new _image_source__WEBPACK_IMPORTED_MODULE_1__[\"default\"](publicId, options);\n return this;\n }\n generateSources() {\n return this.sourceTypes().map(sourceType => {\n if (sourceType === 'audio') {\n const format = 'mp3';\n const opts = {};\n const srcTransformation = this.sourceTransformation()[sourceType] || [this.transformation()];\n if (srcTransformation) {\n opts.transformation = srcTransformation;\n }\n Object.assign(opts, {\n resource_type: 'video',\n format\n });\n const queryString = this.queryParams() ? (0,utils_querystring__WEBPACK_IMPORTED_MODULE_4__.objectToQuerystring)(this.queryParams()) : '';\n const src = `${this.config().url(this.publicId(), opts)}${queryString}`;\n const type = 'video/mp4';\n return {\n type,\n src,\n cldSrc: this,\n poster: this.getPoster().url()\n };\n } else {\n return null;\n }\n }, this);\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (AudioSource);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/cloudinary/models/audio-source/audio-source.js?");
/***/ }),
/***/ "./plugins/cloudinary/models/base-source.js":
/*!**************************************************!*\
!*** ./plugins/cloudinary/models/base-source.js ***!
\**************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../common */ \"./plugins/cloudinary/common.js\");\n/* harmony import */ var utils_slicing__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! utils/slicing */ \"./utils/slicing.js\");\n/* harmony import */ var utils_querystring__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! utils/querystring */ \"./utils/querystring.js\");\n\n\n\nclass BaseSource {\n _transformation = null;\n constructor(initPublicId) {\n let initOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n const {\n publicId,\n options\n } = (0,_common__WEBPACK_IMPORTED_MODULE_0__.normalizeOptions)(initPublicId, initOptions);\n const {\n cloudinaryConfig\n } = (0,utils_slicing__WEBPACK_IMPORTED_MODULE_1__.sliceAndUnsetProperties)(options, 'cloudinaryConfig');\n const {\n transformation\n } = (0,utils_slicing__WEBPACK_IMPORTED_MODULE_1__.sliceAndUnsetProperties)(options, 'transformation');\n const {\n queryParams\n } = (0,utils_slicing__WEBPACK_IMPORTED_MODULE_1__.sliceAndUnsetProperties)(options, 'queryParams');\n if (!cloudinaryConfig) {\n throw new Error('Source is missing \"cloudinaryConfig\".');\n }\n this.publicId = () => publicId;\n this.cloudinaryConfig = () => cloudinaryConfig;\n this.resourceConfig = () => options;\n this.queryParams = () => queryParams;\n this.getType = () => this._type;\n this.transformation(transformation);\n }\n transformation(transformation) {\n if (transformation) {\n this._transformation = transformation;\n }\n return this._transformation;\n }\n config() {\n const coreConfig = this.cloudinaryConfig();\n return {\n cloud_name: coreConfig.cloudName,\n url: (publicId, initTransformation) => {\n if ((0,_common__WEBPACK_IMPORTED_MODULE_0__.isRawUrl)(publicId)) {\n return publicId;\n }\n const transformation = (0,_common__WEBPACK_IMPORTED_MODULE_0__.mergeTransformations)(this.resourceConfig(), initTransformation);\n return (0,_common__WEBPACK_IMPORTED_MODULE_0__.getCloudinaryUrl)(publicId, {\n ...coreConfig,\n ...transformation\n });\n }\n };\n }\n url() {\n let {\n transformation\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n const url = this.config().url(this.publicId(), {\n transformation: transformation || this.transformation()\n });\n const queryString = this.queryParams() ? (0,utils_querystring__WEBPACK_IMPORTED_MODULE_2__.objectToQuerystring)(this.queryParams()) : '';\n return `${url}${queryString}`;\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (BaseSource);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/cloudinary/models/base-source.js?");
/***/ }),
/***/ "./plugins/cloudinary/models/image-source.js":
/*!***************************************************!*\
!*** ./plugins/cloudinary/models/image-source.js ***!
\***************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _base_source__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./base-source */ \"./plugins/cloudinary/models/base-source.js\");\n/* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../common */ \"./plugins/cloudinary/common.js\");\n\n\nconst COMMON_IMAGE_FORMATS = ['jpg', 'png', 'gif', 'webp'];\nconst IMAGE_SUFFIX_REMOVAL_PATTERN = RegExp(`\\\\.(${COMMON_IMAGE_FORMATS.join('|')})$$`);\nconst DEFAULT_IMAGE_PARAMS = {\n resource_type: 'image',\n type: 'upload',\n transformation: []\n};\nclass ImageSource extends _base_source__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n constructor(publicId) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n ({\n publicId,\n options\n } = (0,_common__WEBPACK_IMPORTED_MODULE_1__.normalizeOptions)(publicId, options));\n publicId = publicId.replace(IMAGE_SUFFIX_REMOVAL_PATTERN, '');\n options = Object.assign({}, DEFAULT_IMAGE_PARAMS, options);\n super(publicId, options);\n this._type = 'ImageSource';\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ImageSource);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/cloudinary/models/image-source.js?");
/***/ }),
/***/ "./plugins/cloudinary/models/video-source/video-source.const.js":
/*!**********************************************************************!*\
!*** ./plugins/cloudinary/models/video-source/video-source.const.js ***!
\**********************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ADAPTIVE_SOURCETYPES: () => (/* binding */ ADAPTIVE_SOURCETYPES),\n/* harmony export */ CONTAINER_MIME_TYPES: () => (/* binding */ CONTAINER_MIME_TYPES),\n/* harmony export */ DEFAULT_POSTER_PARAMS: () => (/* binding */ DEFAULT_POSTER_PARAMS),\n/* harmony export */ DEFAULT_VIDEO_PARAMS: () => (/* binding */ DEFAULT_VIDEO_PARAMS),\n/* harmony export */ FORMAT_MAPPINGS: () => (/* binding */ FORMAT_MAPPINGS),\n/* harmony export */ URL_PATTERN: () => (/* binding */ URL_PATTERN),\n/* harmony export */ VIDEO_SUFFIX_REMOVAL_PATTERN: () => (/* binding */ VIDEO_SUFFIX_REMOVAL_PATTERN)\n/* harmony export */ });\nconst DEFAULT_POSTER_PARAMS = {\n format: 'jpg',\n resource_type: 'video'\n};\nconst DEFAULT_VIDEO_PARAMS = {\n resource_type: 'video',\n type: 'upload',\n transformation: [],\n sourceTransformation: {},\n sourceTypes: ['auto'],\n recommendations: null,\n info: {},\n interactionAreas: {},\n chapters: {}\n};\nconst COMMON_VIDEO_EXTENSIONS = ['3g2', '3gp', 'avi', 'flv', 'm3u8', 'ts', 'm2ts', 'mts', 'mov', 'mkv', 'mp4', 'mpeg', 'mpd', 'mxf', 'ogv', 'webm', 'wmv']; // https://cloudinary.com/documentation/video_manipulation_and_delivery#supported_video_formats\n\nconst VIDEO_SUFFIX_REMOVAL_PATTERN = RegExp(`\\\\.(${COMMON_VIDEO_EXTENSIONS.join('|')})$$`);\n\n// eslint-disable-next-line no-control-regex\nconst URL_PATTERN = RegExp('https?:\\\\/\\\\/(www\\\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\\\.[a-zA-Z0-9()]{1,6}\\\\b([-a-zA-Z0-9()@:%_\\+.~#?&/=]*)');\nconst CONTAINER_MIME_TYPES = {\n hls: 'application/x-mpegURL',\n dash: 'application/dash+xml',\n // See: https://docs.videojs.com/utils_mimetypes.js.html\n opus: 'video/ogg',\n ogv: 'video/ogg',\n mp4: 'video/mp4',\n mov: 'video/mp4',\n m4v: 'video/mp4',\n mkv: 'video/x-matroska',\n m4a: 'audio/mp4',\n mp3: 'audio/mpeg',\n aac: 'audio/aac',\n caf: 'audio/x-caf',\n flac: 'audio/flac',\n oga: 'audio/ogg',\n wav: 'audio/wav',\n m3u8: 'application/x-mpegURL',\n mpd: 'application/dash+xml',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n png: 'image/png',\n svg: 'image/svg+xml',\n webp: 'image/webp'\n};\nconst ADAPTIVE_SOURCETYPES = ['hls', 'dash', 'mpd', 'm3u8'];\nconst FORMAT_MAPPINGS = {\n hls: 'm3u8',\n dash: 'mpd'\n};\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/cloudinary/models/video-source/video-source.const.js?");
/***/ }),
/***/ "./plugins/cloudinary/models/video-source/video-source.js":
/*!****************************************************************!*\
!*** ./plugins/cloudinary/models/video-source/video-source.js ***!
\****************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var utils_querystring__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! utils/querystring */ \"./utils/querystring.js\");\n/* harmony import */ var lodash_castArray__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lodash/castArray */ \"../node_modules/lodash/castArray.js\");\n/* harmony import */ var lodash_castArray__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(lodash_castArray__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var utils_consts__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! utils/consts */ \"./utils/consts.js\");\n/* harmony import */ var video_player_const__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! video-player.const */ \"./video-player.const.js\");\n/* harmony import */ var _video_source_const__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./video-source.const */ \"./plugins/cloudinary/models/video-source/video-source.const.js\");\n/* harmony import */ var _video_source_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./video-source.utils */ \"./plugins/cloudinary/models/video-source/video-source.utils.js\");\n/* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../common */ \"./plugins/cloudinary/common.js\");\n/* harmony import */ var _base_source__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../base-source */ \"./plugins/cloudinary/models/base-source.js\");\n/* harmony import */ var _image_source__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../image-source */ \"./plugins/cloudinary/models/image-source.js\");\n\n\n\n\n\n\n\n\n\nlet objectId = 0;\nconst generateId = () => objectId++;\nclass VideoSource extends _base_source__WEBPACK_IMPORTED_MODULE_7__[\"default\"] {\n constructor(_publicId) {\n let initOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n const _isRawUrl = (0,_common__WEBPACK_IMPORTED_MODULE_6__.isRawUrl)(_publicId);\n let {\n publicId,\n options\n } = (0,_common__WEBPACK_IMPORTED_MODULE_6__.normalizeOptions)(_publicId, initOptions);\n if (!_isRawUrl) {\n publicId = publicId.replace(_video_source_const__WEBPACK_IMPORTED_MODULE_4__.VIDEO_SUFFIX_REMOVAL_PATTERN, '');\n }\n options = Object.assign({}, _video_source_const__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_VIDEO_PARAMS, options);\n if (!options.poster) {\n options.poster = Object.assign({\n publicId\n }, _video_source_const__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_POSTER_PARAMS);\n }\n super(publicId, options);\n this._type = utils_consts__WEBPACK_IMPORTED_MODULE_2__.SOURCE_TYPE.VIDEO;\n this.isRawUrl = _isRawUrl;\n this.isLiveStream = options.type === 'live';\n this.withCredentials = !!options.withCredentials;\n this.getInitOptions = () => initOptions;\n\n // Get properties that need simple getter/setter methods (exclude special cases)\n const EXCLUDED_PROPERTIES = ['poster',\n // Has complex logic\n 'withCredentials',\n // Direct property\n 'publicId',\n // BaseSource method\n 'cloudinaryConfig',\n // BaseSource method\n 'transformation',\n // BaseSource method\n 'queryParams',\n // BaseSource method\n 'type',\n // BaseSource handles getType()\n 'info' // Custom override method\n ];\n const SIMPLE_PROPERTIES = video_player_const__WEBPACK_IMPORTED_MODULE_3__.SOURCE_PARAMS.filter(param => !EXCLUDED_PROPERTIES.includes(param));\n\n // Create simple getter/setter methods\n this._createGetterSetters(SIMPLE_PROPERTIES);\n\n // Set initial values from options\n SIMPLE_PROPERTIES.forEach(prop => {\n if (options[prop] !== undefined) {\n this[prop](options[prop]);\n }\n });\n\n // Initialize poster\n this.poster(options.poster);\n this.objectId = generateId();\n }\n\n // Helper method to create simple getter/setter methods\n _createGetterSetters(properties) {\n properties.forEach(prop => {\n const privateKey = `_${prop}`;\n this[prop] = function (value) {\n if (value === undefined) {\n // Provide sensible defaults for specific properties\n if (prop === 'sourceTypes' && this[privateKey] === undefined) {\n return ['auto'];\n }\n if (prop === 'sourceTransformation' && this[privateKey] === undefined) {\n return {};\n }\n return this[privateKey];\n }\n this[privateKey] = value;\n return this;\n };\n });\n }\n poster(publicId) {\n let options = {\n type: this.getInitOptions().type\n };\n if (!publicId) {\n return this._poster;\n }\n if (publicId instanceof _image_source__WEBPACK_IMPORTED_MODULE_8__[\"default\"]) {\n this._poster = publicId;\n return this;\n }\n ({\n publicId,\n options\n } = (0,_common__WEBPACK_IMPORTED_MODULE_6__.normalizeOptions)(publicId, options, {\n tolerateMissingId: true\n }));\n if (!publicId && this.isRawUrl) {\n return null;\n }\n if (this.isLiveStream) {\n return null;\n }\n if (!publicId) {\n publicId = this.publicId();\n options = Object.assign({}, options, _video_source_const__WEBPACK_IMPORTED_MODULE_4__.DEFAULT_POSTER_PARAMS);\n }\n options.cloudinaryConfig = options.cloudinaryConfig || this.cloudinaryConfig();\n this._poster = new _image_source__WEBPACK_IMPORTED_MODULE_8__[\"default\"](publicId, options);\n return this;\n }\n contains(source) {\n const sources = this.generateSources();\n return sources.some(_source => (0,_common__WEBPACK_IMPORTED_MODULE_6__.isSrcEqual)(_source, source));\n }\n generateSources() {\n if (this.isRawUrl) {\n const type = this.sourceTypes()[0] === 'auto' ? null : this.sourceTypes()[0];\n return [this.generateRawSource(this.publicId(), type)];\n }\n const srcs = this.sourceTypes().map(sourceType => {\n const srcTransformation = this.sourceTransformation()[sourceType] || this.transformation();\n const format = (0,_video_source_utils__WEBPACK_IMPORTED_MODULE_5__.normalizeFormat)(sourceType);\n const isAdaptive = _video_source_const__WEBPACK_IMPORTED_MODULE_4__.ADAPTIVE_SOURCETYPES.includes(format);\n const opts = {};\n if (srcTransformation) {\n opts.transformation = lodash_castArray__WEBPACK_IMPORTED_MODULE_1___default()(srcTransformation);\n }\n Object.assign(opts, {\n resource_type: 'video',\n format\n });\n const [type, codecTrans] = (0,_video_source_utils__WEBPACK_IMPORTED_MODULE_5__.formatToMimeTypeAndTransformation)(sourceType);\n\n // If user's transformation include video_codec then don't add another video codec to transformation\n if (codecTrans && !((0,_video_source_utils__WEBPACK_IMPORTED_MODULE_5__.hasCodec)(opts.transformation) || (0,_video_source_utils__WEBPACK_IMPORTED_MODULE_5__.hasCodec)(this.rawTransformation()))) {\n opts.transformation = (0,_common__WEBPACK_IMPORTED_MODULE_6__.mergeTransformations)(opts.transformation, codecTrans);\n }\n if (opts.format === 'auto') {\n delete opts.format;\n opts.transformation = (0,_common__WEBPACK_IMPORTED_MODULE_6__.mergeTransformations)(opts.transformation, {\n fetch_format: 'auto:video'\n });\n }\n if (isAdaptive) {\n // Search for streaming_profile anywhere in the transformation\n const hasStreamingProfile = JSON.stringify(opts.transformation || {}).includes('\"streaming_profile\":');\n if (!hasStreamingProfile && !this.isLiveStream) {\n opts.transformation = (0,_common__WEBPACK_IMPORTED_MODULE_6__.mergeTransformations)(opts.transformation, {\n streaming_profile: 'auto'\n });\n }\n }\n const queryString = this.queryParams() ? (0,utils_querystring__WEBPACK_IMPORTED_MODULE_0__.objectToQuerystring)(this.queryParams()) : '';\n const src = this.config().url(this.publicId(), opts);\n // if src is a url that already contains query params then replace '?' with '&'\n const params = src.indexOf('?') > -1 ? queryString.replace('?', '&') : queryString;\n return {\n type,\n src: src + params,\n cldSrc: this,\n isAdaptive: isAdaptive,\n withCredentials: this.withCredentials\n };\n });\n return srcs;\n }\n generateRawSource(url, type) {\n type = type || url.split('.').pop();\n const isAdaptive = _video_source_const__WEBPACK_IMPORTED_MODULE_4__.ADAPTIVE_SOURCETYPES.includes(type);\n if (_video_source_const__WEBPACK_IMPORTED_MODULE_4__.CONTAINER_MIME_TYPES[type]) {\n type = _video_source_const__WEBPACK_IMPORTED_MODULE_4__.CONTAINER_MIME_TYPES[type];\n } else {\n type = type ? `video/${type}` : null;\n }\n return {\n type,\n src: url,\n cldSrc: this,\n isAdaptive,\n withCredentials: this.withCredentials\n };\n }\n info(value) {\n if (value !== undefined) {\n this._info = value;\n return this;\n }\n const info = this._info || this.getInitOptions().info;\n return {\n title: this.title() || info?.title || '',\n subtitle: this.description() || info?.subtitle || '',\n description: this.description() || info?.subtitle || ''\n };\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (VideoSource);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/cloudinary/models/video-source/video-source.js?");
/***/ }),
/***/ "./plugins/cloudinary/models/video-source/video-source.utils.js":
/*!**********************************************************************!*\
!*** ./plugins/cloudinary/models/video-source/video-source.utils.js ***!
\**********************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ formatToMimeTypeAndTransformation: () => (/* binding */ formatToMimeTypeAndTransformation),\n/* harmony export */ hasCodec: () => (/* binding */ hasCodec),\n/* harmony export */ normalizeFormat: () => (/* binding */ normalizeFormat)\n/* harmony export */ });\n/* harmony import */ var _video_source_const__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./video-source.const */ \"./plugins/cloudinary/models/video-source/video-source.const.js\");\n/* harmony import */ var _common__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../common */ \"./plugins/cloudinary/common.js\");\n/* harmony import */ var lodash_isString__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! lodash/isString */ \"../node_modules/lodash/isString.js\");\n/* harmony import */ var lodash_isString__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(lodash_isString__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var utils_cloudinary__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! utils/cloudinary */ \"./utils/cloudinary.js\");\n\n\n\n\nfunction formatToMimeTypeAndTransformation(format) {\n const [container, codec] = format.toLowerCase().split('/');\n const mimetype = _video_source_const__WEBPACK_IMPORTED_MODULE_0__.CONTAINER_MIME_TYPES[container] || `video/${container}`;\n let result = [mimetype];\n if (codec) {\n const transformation = {\n video_codec: codec\n };\n result = [mimetype, transformation];\n }\n return result;\n}\nfunction normalizeFormat(format) {\n format = format.toLowerCase().split('/').shift();\n let res = _video_source_const__WEBPACK_IMPORTED_MODULE_0__.FORMAT_MAPPINGS[format];\n if (!res) {\n res = format.split('/').shift();\n }\n return res;\n}\nconst strIncludesCodec = value => value && Object.values(_common__WEBPACK_IMPORTED_MODULE_1__.VIDEO_CODEC).some(codec => value.includes(codec));\nconst hasCodecTrans = transformations => ['video_codec', 'streaming_profile'].some(key => (0,utils_cloudinary__WEBPACK_IMPORTED_MODULE_3__.isKeyInTransformation)(transformations, key));\nconst hasCodec = transformations => {\n if (!transformations) {\n return false;\n }\n if (lodash_isString__WEBPACK_IMPORTED_MODULE_2___default()(transformations)) {\n return strIncludesCodec(transformations);\n }\n if (hasCodecTrans(transformations)) {\n return true;\n }\n return !!transformations.some?.(transformation => {\n return hasCodec(transformation);\n });\n};\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/cloudinary/models/video-source/video-source.utils.js?");
/***/ }),
/***/ "./plugins/colors/index.js":
/*!*********************************!*\
!*** ./plugins/colors/index.js ***!
\*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ lazyColorsPlugin)\n/* harmony export */ });\nasync function lazyColorsPlugin(options) {\n const player = this;\n try {\n const {\n default: colorsPlugin\n } = await Promise.all(/*! import() | colors */[__webpack_require__.e(\"styles\"), __webpack_require__.e(\"colors\")]).then(__webpack_require__.bind(__webpack_require__, /*! ./colors */ \"./plugins/colors/colors.js\"));\n const colors = colorsPlugin(player, options);\n player.cloudinary.colors = colors;\n return colors;\n } catch (error) {\n console.error('Failed to load colors plugin:', error);\n }\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/colors/index.js?");
/***/ }),
/***/ "./plugins/context-menu/components/context-menu-item.js":
/*!**************************************************************!*\
!*** ./plugins/context-menu/components/context-menu-item.js ***!
\**************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var utils_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! utils/dom */ \"./utils/dom.js\");\n\n\nconst MenuItem = video_js__WEBPACK_IMPORTED_MODULE_0___default().getComponent('MenuItem');\nclass ContextMenuItem extends MenuItem {\n handleClick() {\n super.handleClick();\n this.options_.listener();\n }\n createEl() {\n const label = (0,utils_dom__WEBPACK_IMPORTED_MODULE_1__.createElement)('span', {\n class: 'vjs-menu-item-text' + (this.options_.class ? ` ${this.options_.class}` : '')\n });\n label.appendChild(document.createTextNode(this.localize(this.options_.label)));\n const el = (0,utils_dom__WEBPACK_IMPORTED_MODULE_1__.createElement)('li', {\n class: 'vjs-menu-item',\n tabIndex: -1\n }, label);\n return el;\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ContextMenuItem);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/context-menu/components/context-menu-item.js?");
/***/ }),
/***/ "./plugins/context-menu/components/context-menu.js":
/*!*********************************************************!*\
!*** ./plugins/context-menu/components/context-menu.js ***!
\*********************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var lodash_isFunction__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lodash/isFunction */ \"../node_modules/lodash/isFunction.js\");\n/* harmony import */ var lodash_isFunction__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(lodash_isFunction__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _context_menu_item__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./context-menu-item */ \"./plugins/context-menu/components/context-menu-item.js\");\n/* harmony import */ var utils_positioning__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! utils/positioning */ \"./utils/positioning.js\");\n\n\n\n\nconst Menu = video_js__WEBPACK_IMPORTED_MODULE_0___default().getComponent('Menu');\nclass ContextMenu extends Menu {\n constructor(player, options) {\n var _this;\n super(player, options);\n _this = this;\n options.content.forEach(c => {\n let fn = null;\n if (lodash_isFunction__WEBPACK_IMPORTED_MODULE_1___default()(c.listener)) {\n fn = c.listener;\n } else if (typeof c.href === 'string') {\n fn = () => window.open(c.href);\n } else {\n fn = () => true;\n }\n this.addItem(new _context_menu_item__WEBPACK_IMPORTED_MODULE_2__[\"default\"](player, {\n label: c.label,\n class: c.class,\n listener: function () {\n fn(...arguments);\n _this.dispose();\n }\n }));\n });\n }\n setPosition(left, top) {\n (0,utils_positioning__WEBPACK_IMPORTED_MODULE_3__.setPosition)(this.el(), left, top);\n }\n createEl() {\n const el = super.createEl();\n video_js__WEBPACK_IMPORTED_MODULE_0___default().dom.addClass(el, 'vjs-context-menu-ui');\n if (this.options_.position) {\n const {\n left,\n top\n } = this.options_.position;\n this.setPosition(left, top);\n }\n return el;\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ContextMenu);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/context-menu/components/context-menu.js?");
/***/ }),
/***/ "./plugins/context-menu/contextMenuContent.js":
/*!****************************************************!*\
!*** ./plugins/context-menu/contextMenuContent.js ***!
\****************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nconst contextMenuContent = player => {\n const isLooping = player.loop();\n const isPaused = player.paused();\n const isMuted = player.muted();\n const isFullscreen = player.isFullscreen();\n const aboutMenuItem = {\n class: 'player-version',\n label: 'Cloudinary Player v' + \"3.2.1\"\n };\n if (!player.controls()) {\n return [aboutMenuItem];\n }\n return [{\n label: isLooping ? 'Unloop' : 'Loop',\n listener: () => {\n player.loop(!isLooping);\n }\n }, {\n label: isPaused ? 'Play' : 'Pause',\n listener: () => {\n if (isPaused) {\n player.play();\n } else {\n player.pause();\n }\n }\n }, {\n label: isMuted ? 'Unmute' : 'Mute',\n listener: () => {\n player.muted(!isMuted);\n }\n }, {\n label: isFullscreen ? 'Exit Fullscreen' : 'Fullscreen',\n listener: () => {\n if (isFullscreen) {\n player.exitFullscreen();\n } else {\n player.requestFullscreen();\n }\n }\n }, aboutMenuItem];\n};\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (contextMenuContent);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/context-menu/contextMenuContent.js?");
/***/ }),
/***/ "./plugins/context-menu/index.js":
/*!***************************************!*\
!*** ./plugins/context-menu/index.js ***!
\***************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var lodash_isFunction__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lodash/isFunction */ \"../node_modules/lodash/isFunction.js\");\n/* harmony import */ var lodash_isFunction__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(lodash_isFunction__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _components_context_menu__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./components/context-menu */ \"./plugins/context-menu/components/context-menu.js\");\n/* harmony import */ var utils_positioning__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! utils/positioning */ \"./utils/positioning.js\");\n/* harmony import */ var utils_slicing__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! utils/slicing */ \"./utils/slicing.js\");\n/* harmony import */ var _videojs_contextmenu__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./videojs-contextmenu */ \"./plugins/context-menu/videojs-contextmenu.js\");\n/* harmony import */ var _context_menu_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./context-menu.scss */ \"./plugins/context-menu/context-menu.scss\");\n\n\n\n\n\n\n\nconst defaults = {\n showNativeOnRecurringEvent: false\n};\nclass ContextMenuPlugin {\n constructor(player, initOpts) {\n if (!Array.isArray(initOpts.content) && !lodash_isFunction__WEBPACK_IMPORTED_MODULE_1___default()(initOpts.content)) {\n throw new Error('\"content\" required');\n }\n const opts = Object.assign({}, defaults, initOpts);\n this.player = player;\n const _options = (0,utils_slicing__WEBPACK_IMPORTED_MODULE_4__.sliceProperties)(opts, 'content', 'showNativeOnRecurringEvent');\n this.init = () => {\n // If we are not already providing \"vjs-contextmenu\" events, do so.\n this.player.contextmenu();\n this.player.on('vjs-contextmenu', onContextMenu);\n this.player.ready(() => this.player.addClass('vjs-context-menu'));\n };\n const getMenuPosition = e => {\n // Calc menu size\n const menuEl = this.menu.el();\n\n // Must append to element to get bounding rect\n menuEl.style.visibility = 'hidden';\n this.player.el().appendChild(menuEl);\n const menuSize = menuEl.getBoundingClientRect();\n this.player.el().removeChild(menuEl);\n menuEl.style.visibility = 'visible';\n const ptrPosition = (0,utils_positioning__WEBPACK_IMPORTED_MODULE_3__.getPointerPosition)(this.player.el(), e);\n const playerSize = this.player.el().getBoundingClientRect();\n let ptrTop = playerSize.height - playerSize.height * ptrPosition.y + 1;\n let ptrLeft = Math.round(playerSize.width * ptrPosition.x) + 1;\n let top = ptrTop;\n let left = ptrLeft;\n\n // Correct top when menu can't fit fully height-wise when pointer is at it's top left corner\n if (ptrTop + menuSize.height > playerSize.height) {\n let difference = ptrTop + menuSize.height - playerSize.height;\n top = difference > menuSize.height / 2 ? ptrTop - menuSize.height - 1 : playerSize.height - menuSize.height;\n }\n\n // Correct left where menu can't fit fully width-wise when pointer is at it's top left corner\n if (ptrLeft + menuSize.width > playerSize.width) {\n let difference = ptrLeft + menuSize.width - playerSize.width;\n left = difference > menuSize.width / 2 ? ptrLeft - menuSize.width - 1 : playerSize.width - menuSize.width;\n }\n\n // Correct top and left in cases that menu is positioned on the pointer\n if (top < ptrTop && left < ptrLeft) {\n top = ptrTop - menuSize.height - 1;\n left = ptrLeft - menuSize.width - 1;\n }\n\n // Make sure that we're still in bounds after the corrections.\n top = Math.max(0, top);\n left = Math.max(0, left);\n return {\n left,\n top\n };\n };\n const onContextMenu = e => {\n if (this.menu) {\n this.menu.dispose();\n if (_options.showNativeOnRecurringEvent) {\n // If this event happens while the custom menu is open, close it and do\n // nothing else. This will cause native contextmenu events to be intercepted\n // once again; so, the next time a contextmenu event is encountered, we'll\n // open the custom menu.\n return;\n }\n }\n\n // Stop canceling the native contextmenu event until further notice.\n if (_options.showNativeOnRecurringEvent) {\n this.player.contextmenu.options.cancel = false;\n }\n e.preventDefault();\n\n // Allow dynamically setting the menu labels based on player\n let content = _options.content;\n if (lodash_isFunction__WEBPACK_IMPORTED_MODULE_1___default()(content)) {\n content = content(this.player);\n }\n this.menu = new _components_context_menu__WEBPACK_IMPORTED_MODULE_2__[\"default\"](this.player, {\n content\n });\n const {\n left,\n top\n } = getMenuPosition(e);\n this.menu.setPosition(left, top);\n\n // This is to handle a bug where firefox triggers both 'contextmenu' and 'click'\n // events on rightclick, causing menu to open and then immediately close.\n const clickHandler = _e => {\n if (!(_e.type === 'click' && (_e.which === 3 || _e.button === 2))) {\n this.menu.dispose();\n }\n };\n this.menu.on('dispose', () => {\n // Begin canceling contextmenu events again, so subsequent events will\n // cause the custom menu to be displayed again.\n this.player.contextmenu.options.cancel = true;\n this.player.removeChild(this.menu);\n video_js__WEBPACK_IMPORTED_MODULE_0___default().off(document, ['click', 'tap'], clickHandler);\n delete this.menu;\n });\n this.player.addChild(this.menu);\n video_js__WEBPACK_IMPORTED_MODULE_0___default().on(document, ['click', 'tap'], clickHandler);\n };\n }\n}\n/* harmony default export */ function __WEBPACK_DEFAULT_EXPORT__() {\n let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n new ContextMenuPlugin(this, opts).init();\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/context-menu/index.js?");
/***/ }),
/***/ "./plugins/context-menu/videojs-contextmenu.js":
/*!*****************************************************!*\
!*** ./plugins/context-menu/videojs-contextmenu.js ***!
\*****************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/**\n * @module plugin\n */\n\nconst defaults = {\n cancel: true,\n sensitivity: 10,\n wait: 500,\n disabled: false\n};\nconst EVENT_NAME = 'vjs-contextmenu';\n\n/**\n * Abstracts a DOM standard event into a vjs-contextmenu event.\n *\n * @private\n * @param {Player} player\n * @param {Event} event\n * A triggering, native event.\n * @return {Player}\n */\nfunction sendAbstractedEvent(player, event) {\n if (player.contextmenu.options.disabled) {\n // videojs-contextmenu is disabled\n return player;\n }\n const abstracted = {\n target: player,\n type: EVENT_NAME\n };\n ['clientX', 'clientY', 'pageX', 'pageY', 'screenX', 'screenY'].forEach(k => {\n abstracted[k] = event[k];\n });\n return player.trigger(abstracted);\n}\n\n/**\n * Handles both touchcancel and touchend events.\n *\n * @private\n * @param {Event} e\n */\nfunction handleTouchEnd(e) {\n const current = this.contextmenu.current;\n if (!current) {\n return;\n }\n const wait = this.contextmenu.options.wait;\n if (e.type === 'touchend' && new Date().getTime() - current.time >= wait) {\n sendAbstractedEvent(this, e);\n }\n this.contextmenu.current = null;\n}\n\n/**\n * Handles touchmove events.\n *\n * @private\n * @param {Event} e\n */\nfunction handleTouchMove(e) {\n const current = this.contextmenu.current;\n if (!current) {\n return;\n }\n const touch = e.touches[0];\n const sensitivity = this.contextmenu.options.sensitivity;\n\n // Cancel the current touch if the pointer has moved in either direction\n // more than the sensitivity number of pixels.\n if (touch.screenX - current.screenX > sensitivity || touch.screenY - current.screenY > sensitivity) {\n this.contextmenu.current = null;\n }\n}\n\n/**\n * Handles touchstart events.\n *\n * @private\n * @param {Event} e\n */\nfunction handleTouchStart(e) {\n // We only care about the first touch point.\n if (this.contextmenu.current) {\n return;\n }\n const touch = e.touches[0];\n this.contextmenu.current = {\n screenX: touch.screenX,\n screenY: touch.screenY,\n time: new Date().getTime()\n };\n}\n\n/**\n * Handles contextmenu events.\n *\n * @private\n * @param {Event} e\n */\nfunction handleContextMenu(e) {\n if (this.contextmenu.options.cancel && !this.contextmenu.options.disabled) {\n e.preventDefault();\n }\n sendAbstractedEvent(this, e);\n\n // If we get a \"contextmenu\" event, we can rely on that going forward\n // because this client supports it; so, we can stop listening for\n // touch events.\n this.off(['touchcancel', 'touchend'], handleTouchEnd);\n this.off('touchmove', handleTouchMove);\n this.off('touchstart', handleTouchStart);\n}\n\n/**\n * A cross-device context menu implementation for video.js players.\n *\n * @param {Object} [options={}]\n * @param {Boolean} [cancel=true]\n * Whether or not to cancel the native \"contextmenu\" event when\n * it is seen.\n *\n * @param {Number} [sensitivity=10]\n * The maximum number of pixels a finger can move because a touch\n * is no longer considered to be \"held\".\n *\n * @param {Number} [wait=500]\n * The minimum number of milliseconds a touch must be \"held\" before\n * it registers.\n */\nfunction contextmenu(options) {\n this.contextmenu.options = video_js__WEBPACK_IMPORTED_MODULE_0___default().obj.merge(defaults, options);\n this.on('contextmenu', handleContextMenu);\n this.on(['touchcancel', 'touchend'], handleTouchEnd);\n this.on('touchmove', handleTouchMove);\n this.on('touchstart', handleTouchStart);\n this.ready(() => this.addClass(EVENT_NAME));\n}\nvideo_js__WEBPACK_IMPORTED_MODULE_0___default().registerPlugin('contextmenu', contextmenu);\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (contextmenu);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/context-menu/videojs-contextmenu.js?");
/***/ }),
/***/ "./plugins/floating-player/index.js":
/*!******************************************!*\
!*** ./plugins/floating-player/index.js ***!
\******************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var utils_positioning__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! utils/positioning */ \"./utils/positioning.js\");\n/* harmony import */ var utils_slicing__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! utils/slicing */ \"./utils/slicing.js\");\n/* harmony import */ var _floating_player_scss__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./floating-player.scss */ \"./plugins/floating-player/floating-player.scss\");\n/* harmony import */ var _video_player_const__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../video-player.const */ \"./video-player.const.js\");\n\n\n\n\nconst defaults = {\n fraction: 0.5,\n collapsedWidth: 300,\n floatTo: 'right'\n};\nclass FloatingPlayer {\n constructor(player) {\n let opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n opts = Object.assign({}, defaults, opts);\n // Handle non left-right values.\n if (opts.floatTo && opts.floatTo !== _video_player_const__WEBPACK_IMPORTED_MODULE_3__.FLOATING_TO.LEFT && opts.floatTo !== _video_player_const__WEBPACK_IMPORTED_MODULE_3__.FLOATING_TO.RIGHT) {\n opts.floatTo = defaults.floatTo;\n }\n this.player = player;\n const el = this.player.el();\n let _options = (0,utils_slicing__WEBPACK_IMPORTED_MODULE_1__.sliceProperties)(opts, 'fraction');\n let _floater = null;\n let _isFloated = false;\n let _isFloaterPositioned = false;\n this.init = () => {\n registerEventHandlers();\n if (typeof this.player.ima === 'object') {\n creatFloaterElement();\n }\n };\n const wrapInner = parent => {\n const wrapper = document.createElement('div');\n parent.appendChild(wrapper);\n while (parent.firstChild !== wrapper) {\n wrapper.appendChild(parent.firstChild);\n }\n return wrapper;\n };\n const removeWindowEventHandlers = () => {\n window.removeEventListener('DOMContentLoaded', checkViewportState, false);\n window.removeEventListener('load', checkViewportState, false);\n window.removeEventListener('scroll', checkViewportState, false);\n window.removeEventListener('resize', checkViewportState, false);\n };\n const addWindowEventHandlers = () => {\n window.addEventListener('DOMContentLoaded', checkViewportState, false);\n window.addEventListener('load', checkViewportState, false);\n window.addEventListener('scroll', checkViewportState, false);\n window.addEventListener('resize', checkViewportState, false);\n };\n const registerEventHandlers = () => {\n this.player.on('play', checkViewportState);\n this.player.on('play', addWindowEventHandlers);\n this.player.on('dispose', removeWindowEventHandlers);\n };\n const positionFloater = () => {\n const elRect = el.getBoundingClientRect();\n _floater.setAttribute('class', `cld-video-player-floater cld-video-player-floater-bottom-${opts.floatTo}`);\n _floater.setAttribute('style', ['width: ' + opts.collapsedWidth + 'px;', 'top: ' + elRect.top + 'px;', 'left: ' + elRect.left + 'px;', 'right: ' + (document.documentElement.clientWidth - elRect.right) + 'px;', 'bottom: ' + (document.documentElement.clientHeight - elRect.bottom) + 'px;'].join(''));\n _isFloaterPositioned = true;\n };\n const creatFloaterElement = () => {\n const elRect = el.getBoundingClientRect();\n _floater = wrapInner(el);\n const inner = wrapInner(_floater);\n inner.setAttribute('class', 'cld-video-player-floater-inner');\n inner.setAttribute('style', 'padding-bottom: ' + 100 * elRect.height / elRect.width + '%;');\n const close = document.createElement('button');\n close.setAttribute('class', 'cld-video-player-floater-close');\n close.innerHTML = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"12\" viewBox=\"0 0 12 12\"><polygon fill-rule=\"evenodd\" points=\"370 7.41 368.59 6 364 10.59 359.41 6 358 7.41 362.59 12 358 16.59 359.41 18 364 13.41 368.59 18 370 16.59 365.41 12\" transform=\"translate(-358 -6)\"/></svg>';\n close.onclick = () => {\n unFloat();\n disable();\n };\n _floater.appendChild(close);\n };\n const setAdSize = () => {\n const {\n ima\n } = this.player;\n if (ima && ima.adsActive) {\n const adsManager = ima.getAdsManager();\n adsManager.resize(_isFloated ? _floater.clientWidth : el.clientWidth, _isFloated ? _floater.clientHeight : el.clientHeight);\n }\n };\n const float = () => {\n if (!_floater) {\n creatFloaterElement();\n }\n if (!_isFloaterPositioned) {\n positionFloater();\n }\n _isFloated = true;\n setTimeout(() => {\n _floater.classList.add('cld-video-player-floating');\n setAdSize();\n });\n };\n const unFloat = () => {\n _floater.classList.remove('cld-video-player-floating');\n _isFloated = false;\n setAdSize();\n };\n const disable = () => {\n removeWindowEventHandlers();\n this.player.off('play', checkViewportState);\n this.player.off('play', addWindowEventHandlers);\n };\n const checkViewportState = () => {\n const visible = (0,utils_positioning__WEBPACK_IMPORTED_MODULE_0__.isElementInViewport)(this.player.el(), {\n fraction: _options.fraction\n });\n if (visible) {\n if (_isFloated) {\n unFloat();\n }\n } else if (!_isFloated) {\n float();\n }\n };\n }\n}\n/* harmony default export */ function __WEBPACK_DEFAULT_EXPORT__() {\n let opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n new FloatingPlayer(this, opts).init();\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/floating-player/index.js?");
/***/ }),
/***/ "./plugins/ima/index.js":
/*!******************************!*\
!*** ./plugins/ima/index.js ***!
\******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ imaPlugin)\n/* harmony export */ });\n/* harmony import */ var lodash_isFunction__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lodash/isFunction */ \"../node_modules/lodash/isFunction.js\");\n/* harmony import */ var lodash_isFunction__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(lodash_isFunction__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var utils_consts__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! utils/consts */ \"./utils/consts.js\");\n/* global google */\n\n\nasync function imaPlugin(player, playerOptions) {\n await Promise.all(/*! import() | ima */[__webpack_require__.e(\"styles\"), __webpack_require__.e(\"ima\")]).then(__webpack_require__.bind(__webpack_require__, /*! ./ima */ \"./plugins/ima/ima.js\"));\n const loaded = {\n contribAdsLoaded: lodash_isFunction__WEBPACK_IMPORTED_MODULE_0___default()(player.ads),\n imaAdsLoaded: typeof google === 'object' && typeof google.ima === 'object'\n };\n if (playerOptions.ads && (!loaded.contribAdsLoaded || !loaded.imaAdsLoaded)) {\n if (!loaded.contribAdsLoaded) {\n console.warn('contribAds is not loaded');\n }\n if (!loaded.imaAdsLoaded) {\n console.warn('imaSdk is not loaded');\n }\n return false;\n }\n player.ima({\n id: player.el().id,\n adTagUrl: playerOptions.ads.adTagUrl,\n disableFlashAds: true,\n prerollTimeout: playerOptions.ads.prerollTimeout || 5000,\n postrollTimeout: playerOptions.ads.postrollTimeout || 5000,\n showCountdown: playerOptions.ads.showCountdown !== false,\n adLabel: playerOptions.ads.adLabel || 'Advertisement',\n locale: playerOptions.ads.locale || 'en',\n autoPlayAdBreaks: playerOptions.ads.autoPlayAdBreaks !== false,\n debug: playerOptions.ads.denug\n });\n if (Object.keys(playerOptions.ads).length > 0 && typeof player.ima === 'object') {\n if (playerOptions.ads.adsInPlaylist === 'first-video') {\n player.one(utils_consts__WEBPACK_IMPORTED_MODULE_1__.PLAYER_EVENT.SOURCE_CHANGED, () => {\n player.ima.playAdBreak();\n });\n } else {\n player.on(utils_consts__WEBPACK_IMPORTED_MODULE_1__.PLAYER_EVENT.SOURCE_CHANGED, () => {\n player.ima.playAdBreak();\n });\n }\n }\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/ima/index.js?");
/***/ }),
/***/ "./plugins/index.js":
/*!**************************!*\
!*** ./plugins/index.js ***!
\**************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var videojs_per_source_behaviors__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! videojs-per-source-behaviors */ \"../node_modules/videojs-per-source-behaviors/dist/videojs-per-source-behaviors.es.js\");\n/* harmony import */ var _ai_highlights_graph__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./ai-highlights-graph */ \"./plugins/ai-highlights-graph/index.js\");\n/* harmony import */ var _analytics__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./analytics */ \"./plugins/analytics/index.js\");\n/* harmony import */ var _autoplay_on_scroll__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./autoplay-on-scroll */ \"./plugins/autoplay-on-scroll/index.js\");\n/* harmony import */ var _cloudinary__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./cloudinary */ \"./plugins/cloudinary/index.js\");\n/* harmony import */ var _cloudinary_analytics__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./cloudinary-analytics */ \"./plugins/cloudinary-analytics/index.js\");\n/* harmony import */ var _context_menu__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./context-menu */ \"./plugins/context-menu/index.js\");\n/* harmony import */ var _floating_player__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./floating-player */ \"./plugins/floating-player/index.js\");\n/* harmony import */ var _paced_transcript__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./paced-transcript */ \"./plugins/paced-transcript/index.js\");\n/* harmony import */ var _styled_text_tracks__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./styled-text-tracks */ \"./plugins/styled-text-tracks/index.js\");\n/* harmony import */ var _vtt_thumbnails__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./vtt-thumbnails */ \"./plugins/vtt-thumbnails/index.js\");\n/* harmony import */ var _chapters__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./chapters */ \"./plugins/chapters/index.js\");\n/* harmony import */ var _colors__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./colors */ \"./plugins/colors/index.js\");\n/* harmony import */ var _ima__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./ima */ \"./plugins/ima/index.js\");\n/* harmony import */ var _interaction_areas__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./interaction-areas */ \"./plugins/interaction-areas/index.js\");\n/* harmony import */ var _playlist__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./playlist */ \"./plugins/playlist/index.js\");\n/* harmony import */ var _shoppable_plugin__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./shoppable-plugin */ \"./plugins/shoppable-plugin/index.js\");\n/* harmony import */ var _srt_text_tracks__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./srt-text-tracks */ \"./plugins/srt-text-tracks/index.js\");\n/* harmony import */ var _visual_search__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./visual-search */ \"./plugins/visual-search/index.js\");\n/* harmony import */ var _share__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./share */ \"./plugins/share/index.js\");\n/* harmony import */ var _adaptive_streaming__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./adaptive-streaming */ \"./plugins/adaptive-streaming/index.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n// Lazy loaded plugins\n\n\n\n\n\n\n\n\n\n\nconst plugins = {\n aiHighlightsGraph: _ai_highlights_graph__WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n analytics: _analytics__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n autoplayOnScroll: _autoplay_on_scroll__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n cloudinary: _cloudinary__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n cloudinaryAnalytics: _cloudinary_analytics__WEBPACK_IMPORTED_MODULE_5__[\"default\"],\n contextMenu: _context_menu__WEBPACK_IMPORTED_MODULE_6__[\"default\"],\n floatingPlayer: _floating_player__WEBPACK_IMPORTED_MODULE_7__[\"default\"],\n pacedTranscript: _paced_transcript__WEBPACK_IMPORTED_MODULE_8__[\"default\"],\n styledTextTracks: _styled_text_tracks__WEBPACK_IMPORTED_MODULE_9__[\"default\"],\n vttThumbnails: _vtt_thumbnails__WEBPACK_IMPORTED_MODULE_10__[\"default\"],\n // Lazy loaded plugins\n chapters: _chapters__WEBPACK_IMPORTED_MODULE_11__[\"default\"],\n colors: _colors__WEBPACK_IMPORTED_MODULE_12__[\"default\"],\n imaPlugin: _ima__WEBPACK_IMPORTED_MODULE_13__[\"default\"],\n playlist: _playlist__WEBPACK_IMPORTED_MODULE_15__[\"default\"],\n shoppable: _shoppable_plugin__WEBPACK_IMPORTED_MODULE_16__[\"default\"],\n srtTextTracks: _srt_text_tracks__WEBPACK_IMPORTED_MODULE_17__[\"default\"],\n interactionAreas: _interaction_areas__WEBPACK_IMPORTED_MODULE_14__[\"default\"],\n visualSearch: _visual_search__WEBPACK_IMPORTED_MODULE_18__[\"default\"],\n share: _share__WEBPACK_IMPORTED_MODULE_19__[\"default\"],\n adaptiveStreaming: _adaptive_streaming__WEBPACK_IMPORTED_MODULE_20__[\"default\"]\n};\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (plugins);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/index.js?");
/***/ }),
/***/ "./plugins/interaction-areas/index.js":
/*!********************************************!*\
!*** ./plugins/interaction-areas/index.js ***!
\********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ lazyInteractionAreasPlugin)\n/* harmony export */ });\nasync function lazyInteractionAreasPlugin(player, playerOptions, videojsOptions) {\n try {\n const {\n interactionAreasService\n } = await Promise.all(/*! import() | interaction-areas */[__webpack_require__.e(\"styles\"), __webpack_require__.e(\"node_modules_lodash_throttle_js\"), __webpack_require__.e(\"interaction-areas\")]).then(__webpack_require__.bind(__webpack_require__, /*! ./interaction-areas.service */ \"./plugins/interaction-areas/interaction-areas.service.js\"));\n interactionAreasService(player, playerOptions, videojsOptions);\n } catch (error) {\n console.error('Failed to load plugin:', error);\n }\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/interaction-areas/index.js?");
/***/ }),
/***/ "./plugins/paced-transcript/index.js":
/*!*******************************************!*\
!*** ./plugins/paced-transcript/index.js ***!
\*******************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _cloudinary_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../cloudinary/common */ \"./plugins/cloudinary/common.js\");\n/* harmony import */ var _utils_utf8Base64__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../utils/utf8Base64 */ \"./utils/utf8Base64.js\");\n\n\nconst fallbackFetch = async (url, fallback) => {\n try {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed fetching from ${url} with status code ${response.status}`);\n }\n return response;\n } catch (error) {\n console.error(error);\n if (fallback) {\n return fallbackFetch(fallback);\n }\n }\n};\nfunction pacedTranscript(config) {\n const player = this;\n const options = {\n kind: config.kind || 'captions',\n label: config.label || 'Captions',\n default: config.default,\n srclang: config.srclang,\n src: config.src,\n maxWords: config.maxWords,\n wordHighlight: config.wordHighlight,\n timeOffset: config.timeOffset || 0\n };\n const classNames = player.textTrackDisplay.el().classList;\n classNames.add('cld-paced-text-tracks');\n const getTranscriptionFileUrl = function (urlPrefix, deliveryType, publicId) {\n let languageCode = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;\n return `${urlPrefix}/_applet_/video_service/transcription/${deliveryType}/${languageCode ? `${languageCode}/` : ''}${(0,_utils_utf8Base64__WEBPACK_IMPORTED_MODULE_1__.utf8ToBase64)(publicId)}.transcript`;\n };\n\n // Load the transcription file\n const initTranscript = async () => {\n let transcriptResponse;\n if (options.src) {\n // Fetch from src, if explicitly provided\n transcriptResponse = await fallbackFetch(options.src);\n } else {\n // If not, and provided language, try fetching translated transcript, fallback to base transcript\n const source = player.cloudinary.source();\n const sourcePublicId = source.publicId();\n const sourceDeliveryType = source.resourceConfig().type;\n const urlPrefix = (0,_cloudinary_common__WEBPACK_IMPORTED_MODULE_0__.getCloudinaryUrlPrefix)(player.cloudinary.cloudinaryConfig());\n const transcriptionFileUrl = getTranscriptionFileUrl(urlPrefix, sourceDeliveryType, sourcePublicId);\n if (options.srclang) {\n const transcriptionTranslationFileUrl = getTranscriptionFileUrl(urlPrefix, sourceDeliveryType, sourcePublicId, options.srclang);\n transcriptResponse = await fallbackFetch(transcriptionTranslationFileUrl, transcriptionFileUrl);\n } else {\n transcriptResponse = await fallbackFetch(transcriptionFileUrl);\n }\n }\n if (!transcriptResponse?.ok) return;\n const transcriptData = await transcriptResponse.json();\n const captions = parseTranscript(transcriptData);\n const captionsTrack = player.addRemoteTextTrack({\n kind: options.kind,\n label: options.label,\n srclang: options.srclang,\n default: options.default,\n mode: options.default ? 'showing' : 'disabled'\n });\n captions.forEach(caption => {\n captionsTrack.track.addCue(new VTTCue(caption.startTime, caption.endTime, caption.text));\n });\n };\n\n // Generate captions from the transcription data\n const parseTranscript = transcriptionData => {\n const captions = [];\n const addCaption = _ref => {\n let {\n startTime,\n endTime,\n text\n } = _ref;\n captions.push({\n startTime: startTime + options.timeOffset,\n endTime: endTime + options.timeOffset,\n text\n });\n };\n transcriptionData.forEach(segment => {\n const words = segment.words;\n if (words) {\n const maxWords = options.maxWords || words.length;\n for (let i = 0; i < words.length; i += maxWords) {\n if (options.wordHighlight) {\n // Create a caption for every word, in which the current word is highlighted\n words.slice(i, Math.min(i + maxWords, words.length)).forEach((word, idx) => {\n addCaption({\n startTime: word.start_time,\n endTime: word.end_time,\n text: words.slice(i, i + maxWords).map(w => w === word ? `<b>${w.word}</b>` : w.word).join(' ')\n });\n\n // if we haven't reached the end of the words array, and there's a gap between the current word end_time and the next word start_time, add a non-highlighted caption to fill the gap\n if (words[idx + 1] && word.end_time < words[idx + 1].start_time) {\n addCaption({\n startTime: word.end_time,\n endTime: words[idx + 1].start_time,\n text: words.slice(i, i + maxWords).map(word => word.word).join(' ')\n });\n }\n });\n } else {\n captions.push({\n startTime: words[i].start_time,\n endTime: words[Math.min(i + maxWords - 1, words.length - 1)].end_time,\n text: words.slice(i, i + maxWords).map(word => word.word).join(' ')\n });\n }\n }\n } else {\n addCaption({\n startTime: segment.start_time,\n endTime: segment.end_time,\n text: segment.transcript\n });\n }\n });\n return captions;\n };\n player.one('loadedmetadata', () => {\n initTranscript();\n });\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (pacedTranscript);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/paced-transcript/index.js?");
/***/ }),
/***/ "./plugins/playlist/index.js":
/*!***********************************!*\
!*** ./plugins/playlist/index.js ***!
\***********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ lazyPlugin)\n/* harmony export */ });\nasync function lazyPlugin(options) {\n const player = this;\n try {\n const {\n default: playlistPlugin\n } = await Promise.all(/*! import() | playlist */[__webpack_require__.e(\"styles\"), __webpack_require__.e(\"playlist\")]).then(__webpack_require__.bind(__webpack_require__, /*! ./playlist */ \"./plugins/playlist/playlist.js\"));\n const playlist = playlistPlugin(player, options);\n player.cloudinary.playlist = playlist;\n return playlist;\n } catch (error) {\n console.error('Failed to load plugin:', error);\n }\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/playlist/index.js?");
/***/ }),
/***/ "./plugins/share/index.js":
/*!********************************!*\
!*** ./plugins/share/index.js ***!
\********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ lazySharePlugin)\n/* harmony export */ });\nasync function lazySharePlugin(options) {\n const player = this;\n try {\n const {\n default: initPlugin\n } = await Promise.all(/*! import() | share */[__webpack_require__.e(\"styles\"), __webpack_require__.e(\"share\")]).then(__webpack_require__.bind(__webpack_require__, /*! ./share */ \"./plugins/share/share.js\"));\n player.ready(() => initPlugin(options, player));\n } catch (error) {\n console.error('Failed to load share plugin:', error);\n }\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/share/index.js?");
/***/ }),
/***/ "./plugins/shoppable-plugin/index.js":
/*!*******************************************!*\
!*** ./plugins/shoppable-plugin/index.js ***!
\*******************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ lazyShoppablePlugin)\n/* harmony export */ });\nasync function lazyShoppablePlugin(player, options) {\n const {\n default: ShoppableWidget\n } = await Promise.all(/*! import() | shoppable */[__webpack_require__.e(\"styles\"), __webpack_require__.e(\"node_modules_lodash_throttle_js\"), __webpack_require__.e(\"shoppable\")]).then(__webpack_require__.bind(__webpack_require__, /*! ../../components/shoppable-bar/shoppable-widget */ \"./components/shoppable-bar/shoppable-widget.js\"));\n new ShoppableWidget(player, options.shoppable).init();\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/shoppable-plugin/index.js?");
/***/ }),
/***/ "./plugins/srt-text-tracks/index.js":
/*!******************************************!*\
!*** ./plugins/srt-text-tracks/index.js ***!
\******************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ lazySrtTextTracksPlugin)\n/* harmony export */ });\nasync function lazySrtTextTracksPlugin(config) {\n const player = this;\n try {\n const {\n default: srtTextTracks\n } = await __webpack_require__.e(/*! import() | srt-text-tracks */ \"srt-text-tracks\").then(__webpack_require__.bind(__webpack_require__, /*! ./srt-text-tracks */ \"./plugins/srt-text-tracks/srt-text-tracks.js\"));\n player.ready(() => srtTextTracks(config, player));\n } catch (error) {\n console.error('Failed to load srt-text-tracks plugin:', error);\n }\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/srt-text-tracks/index.js?");
/***/ }),
/***/ "./plugins/styled-text-tracks/index.js":
/*!*********************************************!*\
!*** ./plugins/styled-text-tracks/index.js ***!
\*********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ styledTextTracksPlugin)\n/* harmony export */ });\n/* harmony import */ var _styled_text_tracks__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./styled-text-tracks */ \"./plugins/styled-text-tracks/styled-text-tracks.js\");\n\nasync function styledTextTracksPlugin(config) {\n const player = this;\n try {\n player.ready(() => (0,_styled_text_tracks__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(config, player));\n } catch (error) {\n console.error('Failed to load plugin:', error);\n }\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/styled-text-tracks/index.js?");
/***/ }),
/***/ "./plugins/styled-text-tracks/styled-text-tracks.js":
/*!**********************************************************!*\
!*** ./plugins/styled-text-tracks/styled-text-tracks.js ***!
\**********************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var utils_fontFace__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! utils/fontFace */ \"./utils/fontFace.js\");\n/* harmony import */ var utils_css_prefix__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! utils/css-prefix */ \"./utils/css-prefix.js\");\n/* harmony import */ var _styled_text_tracks_scss__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./styled-text-tracks.scss */ \"./plugins/styled-text-tracks/styled-text-tracks.scss\");\n\n\n\nconst styledTextTracks = (config, player) => {\n const options = {\n theme: config.theme || 'default',\n fontFace: config.fontFace,\n fontSize: config.fontSize,\n gravity: config.gravity || 'bottom',\n box: config.box,\n style: config.style,\n wordHighlightStyle: config.wordHighlightStyle\n };\n const styleEl = document.createElement('style');\n player.el_.appendChild(styleEl);\n\n // Class Names - Theme/Gravity\n const classNames = player.textTrackDisplay.el().classList;\n classNames.forEach(className => {\n // Remove previously added theme/gravity classes\n if (className.startsWith('cld-styled-text-tracks')) {\n classNames.remove(className);\n }\n });\n classNames.add('cld-styled-text-tracks');\n classNames.add(`cld-styled-text-tracks-theme-${options.theme}`);\n options.gravity.split('-').forEach(gravity => {\n classNames.add(`cld-styled-text-tracks-gravity-${gravity}`);\n });\n const applyStyle = (style, selector) => {\n if (Object.entries(style)) {\n const css = Object.entries(style).reduce((acc, _ref) => {\n let [key, value] = _ref;\n return acc + `${key}: ${value} !important; `;\n }, '');\n styleEl.innerHTML += `${selector} { ${css} } `;\n }\n };\n const applyWrapperStyle = style => {\n const selector = `\n .${(0,utils_css_prefix__WEBPACK_IMPORTED_MODULE_1__.playerClassPrefix)(player)} .vjs-text-track-display.cld-styled-text-tracks,\n .${(0,utils_css_prefix__WEBPACK_IMPORTED_MODULE_1__.playerClassPrefix)(player)} ::-webkit-media-text-track-display\n `;\n applyStyle(style, selector);\n };\n const applyCueStyle = style => {\n const selector = `\n .${(0,utils_css_prefix__WEBPACK_IMPORTED_MODULE_1__.playerClassPrefix)(player)} .vjs-text-track-cue > div,\n .${(0,utils_css_prefix__WEBPACK_IMPORTED_MODULE_1__.playerClassPrefix)(player)} ::cue\n `;\n applyStyle(style, selector);\n };\n\n // Font\n if (options.fontFace) {\n (0,utils_fontFace__WEBPACK_IMPORTED_MODULE_0__.fontFace)(player.textTrackDisplay.el(), options.fontFace);\n applyCueStyle({\n 'font-family': options.fontFace\n });\n }\n\n // Custom bounding box\n if (options.box) {\n const {\n x,\n y,\n width,\n height\n } = options.box;\n applyWrapperStyle({\n translate: `${x ? x : 0} ${y ? y : 0}`,\n ...(width ? {\n width\n } : undefined),\n ...(height ? {\n height\n } : undefined)\n });\n }\n\n // Custom font-size\n if (options.fontSize) {\n applyCueStyle({\n 'font-size': options.fontSize\n });\n }\n\n // Custom styles\n if (options.style) {\n applyCueStyle(options.style);\n }\n\n // Word highlight styles\n if (options.wordHighlightStyle) {\n applyStyle(options.wordHighlightStyle, `.${(0,utils_css_prefix__WEBPACK_IMPORTED_MODULE_1__.playerClassPrefix)(player)} .cld-paced-text-tracks .vjs-text-track-cue b`);\n applyStyle(options.wordHighlightStyle, 'video::cue(b)');\n }\n};\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (styledTextTracks);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/styled-text-tracks/styled-text-tracks.js?");
/***/ }),
/***/ "./plugins/visual-search/index.js":
/*!****************************************!*\
!*** ./plugins/visual-search/index.js ***!
\****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ lazyVisualSearchPlugin)\n/* harmony export */ });\nasync function lazyVisualSearchPlugin(options) {\n const player = this;\n try {\n const {\n default: initPlugin\n } = await Promise.all(/*! import() | visual-search */[__webpack_require__.e(\"styles\"), __webpack_require__.e(\"visual-search\")]).then(__webpack_require__.bind(__webpack_require__, /*! ./visual-search */ \"./plugins/visual-search/visual-search.js\"));\n player.ready(() => initPlugin(options, player));\n } catch (error) {\n console.error('Failed to load plugin:', error);\n }\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/visual-search/index.js?");
/***/ }),
/***/ "./plugins/vtt-thumbnails/index.js":
/*!*****************************************!*\
!*** ./plugins/vtt-thumbnails/index.js ***!
\*****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _vtt_thumbnails_scss__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./vtt-thumbnails.scss */ \"./plugins/vtt-thumbnails/vtt-thumbnails.scss\");\n\n\n\n// Default options for the plugin.\nlet defaults = {};\n\n// Cache for image elements\nlet cache = {};\n\n/**\n * Function to invoke when the player is ready.\n *\n * This is a great place for your plugin to initialize itself. When this\n * function is called, the player will have its DOM and child components\n * in place.\n *\n * @function onPlayerReady\n * @param {Player} player\n * A Video.js player object.\n *\n * @param {Object} [options={}]\n * A plain object containing options for the plugin.\n */\nconst onPlayerReady = function onPlayerReady(player, options) {\n player.addClass('vjs-vtt-thumbnails');\n player.vttThumbnails = new VttThumbnailsPlugin(player, options);\n};\n\n/**\n * A video.js plugin.\n *\n * In the plugin function, the value of `this` is a video.js `Player`\n * instance. You cannot rely on the player being in a \"ready\" state here,\n * depending on how the plugin is invoked. This may or may not be important\n * to you; if not, remove the wait for \"ready\"!\n *\n * @function vttThumbnails\n * @param {Object} [options={}]\n * An object of options left to the plugin author to define.\n */\nconst vttThumbnails = function vttThumbnails(options) {\n this.ready(() => {\n onPlayerReady(this, video_js__WEBPACK_IMPORTED_MODULE_0___default().obj.merge(defaults, options));\n });\n};\n\n/**\n * VTT Thumbnails class.\n *\n * This class performs all functions related to displaying the vtt\n * thumbnails.\n */\nconst VttThumbnailsPlugin = function () {\n /**\n * Plugin class constructor, called by videojs on\n * ready event.\n *\n * @function constructor\n * @param {Player} player\n * A Video.js player object.\n *\n * @param {Object} [options={}]\n * A plain object containing options for the plugin.\n */\n function VttThumbnailsPlugin(player, options) {\n this.player = player;\n this.options = options;\n this.initializeThumbnails();\n return this;\n }\n VttThumbnailsPlugin.prototype.src = function src(source) {\n this.resetPlugin();\n this.options.src = source;\n this.initializeThumbnails();\n };\n VttThumbnailsPlugin.prototype.detach = function detach() {\n this.resetPlugin();\n };\n VttThumbnailsPlugin.prototype.resetPlugin = function resetPlugin() {\n if (this.thumbnailHolder) {\n this.thumbnailHolder.parentNode.removeChild(this.thumbnailHolder);\n }\n delete this.vttData;\n delete this.thumbnailHolder;\n delete this.lastStyle;\n };\n\n /**\n * Bootstrap the plugin.\n */\n VttThumbnailsPlugin.prototype.initializeThumbnails = function initializeThumbnails() {\n if (!this.options.src) {\n return;\n }\n fetch(this.options.src, {\n credentials: this.player.cloudinary.source?.().withCredentials ? 'include' : 'omit'\n }).then(res => {\n return res.text();\n }).then(data => {\n this.vttData = this.processVtt(data);\n this.setupThumbnailElement();\n });\n };\n VttThumbnailsPlugin.prototype.setupThumbnailElement = function setupThumbnailElement() {\n if (!this.vttData[0]) {\n return;\n }\n const mouseDisplay = this.player.$('.vjs-progress-holder .vjs-mouse-display');\n this.thumbnailHolder = this.player.$('.vjs-vtt-thumbnail-display') || video_js__WEBPACK_IMPORTED_MODULE_0___default().dom.createEl('div', undefined, {\n class: 'vjs-vtt-thumbnail-display',\n style: `width: ${this.vttData[0].css.width}`\n });\n this.thumbnailHolder.innerHTML = '';\n this.thumbnailHolder.setAttribute('class', 'vjs-vtt-thumbnail-display');\n mouseDisplay.appendChild(this.thumbnailHolder);\n const halfThumbnailWidth = parseInt(this.vttData[0].css.width, 10) / 2;\n const updateThumbnailStyle = this.updateThumbnailStyle.bind(this);\n const mouseTimeDisplay = this.player.getDescendant(['controlBar', 'progressControl', 'seekBar', 'mouseTimeDisplay']);\n mouseTimeDisplay.update = function (seekBarRect, seekBarPoint) {\n const time = seekBarPoint * this.player_.duration();\n const width = seekBarRect.width;\n updateThumbnailStyle(time);\n this.getChild('timeTooltip').updateTime(seekBarRect, seekBarPoint, time, () => {\n // Make sure the thumbnail doesn't exit the player\n if (seekBarRect.width * seekBarPoint < halfThumbnailWidth) {\n this.el_.style.left = `${halfThumbnailWidth}px`;\n } else if (seekBarRect.width * seekBarPoint + halfThumbnailWidth > width) {\n this.el_.style.left = `${seekBarRect.width - halfThumbnailWidth}px`;\n } else {\n this.el_.style.left = `${seekBarRect.width * seekBarPoint}px`;\n }\n });\n this.getChild('timeTooltip').write(video_js__WEBPACK_IMPORTED_MODULE_0___default().time.formatTime(time));\n };\n };\n VttThumbnailsPlugin.prototype.getStyleForTime = function getStyleForTime(time) {\n for (let i = 0; i < this.vttData.length; ++i) {\n let item = this.vttData[i];\n if (time >= item.start && time < item.end) {\n // Cache miss\n if (item.css.url && !cache[item.css.url]) {\n let image = new Image();\n image.src = item.css.url;\n cache[item.css.url] = image;\n }\n return item.css;\n }\n }\n };\n VttThumbnailsPlugin.prototype.updateThumbnailStyle = function updateThumbnailStyle(time) {\n let currentStyle = this.getStyleForTime(time);\n if (!currentStyle) {\n this.thumbnailHolder.style.opacity = '0';\n return;\n } else {\n this.thumbnailHolder.style.opacity = '1';\n }\n if (this.lastStyle && this.lastStyle === currentStyle) {\n return;\n }\n this.lastStyle = currentStyle;\n for (let style in currentStyle) {\n if (Object.prototype.hasOwnProperty.call(currentStyle, style)) {\n this.thumbnailHolder.style[style] = currentStyle[style];\n }\n }\n };\n VttThumbnailsPlugin.prototype.processVtt = function processVtt(data) {\n let thumbnailsData = [];\n let vttDefinitions = data.split(/[\\r\\n][\\r\\n]/i);\n vttDefinitions.forEach(vttDef => {\n if (vttDef.match(/([0-9]{2}:)?([0-9]{2}:)?[0-9]{2}(.[0-9]{3})?( ?--> ?)([0-9]{2}:)?([0-9]{2}:)?[0-9]{2}(.[0-9]{3})?[\\r\\n]{1}.*/gi)) {\n let vttDefSplit = vttDef.split(/[\\r\\n]/i);\n let vttTiming = vttDefSplit[0];\n let vttTimingSplit = vttTiming.split(/ ?--> ?/i);\n let vttTimeStart = vttTimingSplit[0];\n let vttTimeEnd = vttTimingSplit[1];\n let vttImageFullPath = vttDefSplit[1];\n let vttImageDef = vttImageFullPath.split('\\/').pop();\n let vttCssDef = this.getVttCss(vttImageDef);\n thumbnailsData.push({\n start: this.getSecondsFromTimestamp(vttTimeStart),\n end: this.getSecondsFromTimestamp(vttTimeEnd),\n css: vttCssDef\n });\n }\n });\n return thumbnailsData;\n };\n VttThumbnailsPlugin.prototype.getPropsFromDef = function getPropsFromDef(def) {\n let imageDefSplit = def.split(/#xywh=/i);\n let imageUrl = imageDefSplit[0];\n let imageCoords = imageDefSplit[1];\n let splitCoords = imageCoords.match(/[0-9]+/gi);\n return {\n x: splitCoords[0],\n y: splitCoords[1],\n w: splitCoords[2],\n h: splitCoords[3],\n image: imageUrl\n };\n };\n VttThumbnailsPlugin.prototype.getVttCss = function getVttCss(vttImageDef) {\n let cssObj = {};\n\n // If there isn't a protocol, use the VTT source URL.\n let baseSplit = this.options.src.split(/([^\\/]*)$/gi).shift();\n vttImageDef = [baseSplit.trim(), vttImageDef.trim()].join('/');\n let imageProps = this.getPropsFromDef(vttImageDef);\n cssObj.background = 'url(\"' + imageProps.image + '\") no-repeat -' + imageProps.x + 'px -' + imageProps.y + 'px';\n cssObj.width = imageProps.w + 'px';\n cssObj.height = imageProps.h + 'px';\n cssObj.url = imageProps.image;\n return cssObj;\n };\n VttThumbnailsPlugin.prototype.getSecondsFromTimestamp = function getSecondsFromTimestamp(timestamp) {\n const [hours, minutes, seconds] = timestamp.split(':').map(parseFloat);\n return hours * 60 * 60 + minutes * 60 + seconds;\n };\n return VttThumbnailsPlugin;\n}();\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (vttThumbnails);\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/vtt-thumbnails/index.js?");
/***/ }),
/***/ "./utils/apply-with-props.js":
/*!***********************************!*\
!*** ./utils/apply-with-props.js ***!
\***********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ applyWithProps: () => (/* binding */ applyWithProps)\n/* harmony export */ });\nfunction applyWithProps(context, obj) {\n Object.entries(obj).forEach(_ref => {\n let [key, value] = _ref;\n if (context[key] && typeof context[key] === 'function') {\n context[key](value);\n }\n });\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/apply-with-props.js?");
/***/ }),
/***/ "./utils/attributes-normalizer.js":
/*!****************************************!*\
!*** ./utils/attributes-normalizer.js ***!
\****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ normalizeAttributes: () => (/* binding */ normalizeAttributes)\n/* harmony export */ });\n/* harmony import */ var lodash_camelCase__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lodash/camelCase */ \"../node_modules/lodash/camelCase.js\");\n/* harmony import */ var lodash_camelCase__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(lodash_camelCase__WEBPACK_IMPORTED_MODULE_0__);\n\nconst CLD_ATTR_REGEX = /^(data-cld-)(\\w+)/;\nconst normalizers = {};\nfunction coerce(string) {\n let val = null;\n\n // Boolean\n if (string === '') {\n return true;\n }\n\n // Complex object\n try {\n val = JSON.parse(string);\n } catch (err) {// eslint-disable-line no-unused-vars\n // Continue execution in case str is not parsable\n }\n if (val) {\n return val;\n }\n\n // Number\n val = Number(string);\n if (val) {\n return val;\n }\n\n // TODO: Parse date?\n //\n return string;\n}\nconst normalizeDefault = value => coerce(value);\nconst normalizeAttributes = elem => {\n const obj = {};\n if (elem && elem.attributes && elem.attributes.length > 0) {\n const attrs = elem.attributes;\n for (let i = attrs.length - 1; i >= 0; i--) {\n let attrName = attrs[i].name;\n let attrVal = attrs[i].value;\n if (attrName.match(CLD_ATTR_REGEX)) {\n attrName = lodash_camelCase__WEBPACK_IMPORTED_MODULE_0___default()(attrName.replace(CLD_ATTR_REGEX, '$2'));\n }\n\n // check for known booleans\n // the matching element property will return a value for typeof\n // if (typeof elem[attrName] === 'boolean' || KNOWN_BOOLEANS[attrName]) {\n if (typeof elem[attrName] === 'boolean') {\n // the value of an included boolean attribute is typically an empty\n // string ('') which would equal false if we just check for a false value.\n // we also don't want support bad code like autoplay='false'\n attrVal = attrVal !== null;\n } else {\n const normalizer = normalizers[attrName] || normalizeDefault;\n attrVal = normalizer(attrVal);\n }\n obj[attrName] = attrVal;\n }\n }\n return obj;\n};\n\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/attributes-normalizer.js?");
/***/ }),
/***/ "./utils/cloudinary.js":
/*!*****************************!*\
!*** ./utils/cloudinary.js ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ addTextTracks: () => (/* binding */ addTextTracks),\n/* harmony export */ handleCldError: () => (/* binding */ handleCldError),\n/* harmony export */ isKeyInTransformation: () => (/* binding */ isKeyInTransformation)\n/* harmony export */ });\n/* harmony import */ var _plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../plugins/cloudinary/common */ \"./plugins/cloudinary/common.js\");\n/* harmony import */ var utils_find__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! utils/find */ \"./utils/find.js\");\n\n\nconst GET_ERROR_DEFAULT_REQUEST = {\n method: 'head'\n};\nconst ERROR_WITH_GET_REQUEST = {\n method: 'get',\n credentials: 'include',\n headers: {\n 'Content-Range': 'bytes=0-0'\n }\n};\nconst getGoodSrcs = (srcs, parsedUris) => {\n return srcs.filter(s => {\n const origUrl = new URL(s.src);\n return parsedUris.indexOf(origUrl.host + origUrl.pathname) !== -1 && s.try !== true;\n });\n};\nconst getParsedUris = res => {\n return res.reduce((acc, r) => {\n if (r.status >= 200 && r.status < 399 && r.url !== '') {\n const parsedUri = new URL(r.url);\n acc.push(parsedUri.host + parsedUri.pathname);\n }\n return acc;\n }, []);\n};\nconst setError = (that, res) => {\n that.videojs.error((0,_plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_0__.cloudinaryErrorsConverter)({\n errorMsg: res.headers.get('x-cld-error') || '',\n publicId: that.currentPublicId(),\n cloudName: that.cloudinaryConfig().cloud_name,\n error: res,\n statusCode: res.status\n }));\n};\nconst setVideoSrc = (that, srcs) => {\n if (that.options.playerOptions.debug) {\n console.log('Trying sources: ', srcs);\n }\n srcs.forEach(s => {\n s.try = true;\n });\n that.videojs.autoplay(that.videojs.autoplay() || that.playWasCalled);\n that.videojs.src(srcs);\n};\nconst handleCldError = (that, options) => {\n const srcs = that.videojs.cloudinary.getCurrentSources();\n const opts = options.fetchErrorUsingGet ? ERROR_WITH_GET_REQUEST : GET_ERROR_DEFAULT_REQUEST;\n opts.credentials = options.withCredentials ? 'include' : 'omit';\n if (srcs.length > 0) {\n Promise.all(srcs.map(s => fetch(s.src, opts))).then(res => {\n const parsedUris = getParsedUris(res);\n const firstRes = res[0];\n if (!parsedUris.length) {\n setError(that, firstRes);\n } else {\n const goodSrcs = getGoodSrcs(srcs, parsedUris);\n if (goodSrcs && goodSrcs.length) {\n setVideoSrc(that, goodSrcs);\n } else {\n that.videojs.error({\n code: _plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_0__.ERROR_CODE.NO_SUPPORTED_MEDIA,\n message: 'No supported media sources',\n statusCode: res.status\n });\n }\n }\n }).catch(error => {\n that.videojs.error({\n code: 7,\n message: error && error.message ? error.message : 'Failed to test sources'\n });\n });\n } else {\n that.videojs.error({\n code: _plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_0__.ERROR_CODE.NO_SUPPORTED_MEDIA,\n message: 'No supported media sources'\n });\n }\n};\n\n/**\n * Check if key exist in transformation\n * @param transformation\n * @param key\n * @returns true if key exists in transformation, false otherwise\n */\nconst isKeyInTransformation = (transformation, key) => {\n if (!transformation || !key) {\n return false;\n }\n\n // transformation is an array so run this function for each item\n if (Array.isArray(transformation)) {\n return !!(0,utils_find__WEBPACK_IMPORTED_MODULE_1__.find)(transformation, t => isKeyInTransformation(t, key));\n }\n\n // transformation is a Transformation object so use getValue() to check key\n if (transformation.getValue) {\n return !!transformation.getValue(key);\n }\n\n // transformation is an Object so just check for key existence in object\n return !!transformation[key];\n};\nconst addTextTracks = (tracks, videojs) => {\n tracks.forEach(track => {\n if (track.src && track.src.endsWith('.vtt')) {\n fetch(track.src, GET_ERROR_DEFAULT_REQUEST).then(r => {\n if (r.status >= 200 && r.status <= 399) {\n videojs.addRemoteTextTrack(track, true);\n }\n });\n } else if (track.src && track.src.endsWith('.srt')) {\n videojs.srtTextTracks(track);\n } else if (videojs.pacedTranscript && (!track.src || track.src.endsWith('.transcript'))) {\n videojs.pacedTranscript(track);\n }\n });\n};\n\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/cloudinary.js?");
/***/ }),
/***/ "./utils/consts.js":
/*!*************************!*\
!*** ./utils/consts.js ***!
\*************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ PLAYER_EVENT: () => (/* binding */ PLAYER_EVENT),\n/* harmony export */ SOURCE_TYPE: () => (/* binding */ SOURCE_TYPE)\n/* harmony export */ });\nconst PLAYER_EVENT = {\n READY: 'ready',\n PLAY: 'play',\n PLAYING: 'playing',\n PAUSE: 'pause',\n SEEK: 'seek',\n SEEKING: 'seeking',\n MUTE: 'mute',\n UNMUTE: 'unmute',\n PAUSE_NO_SEEK: 'pausenoseek',\n ERROR: 'error',\n TIME_UPDATE: 'timeupdate',\n EMPTIED: 'emptied',\n RETRY_PLAYLIST: 'retryplaylist',\n CAN_PLAY_THROUGH: 'canplaythrough',\n CLD_SOURCE_CHANGED: 'cldsourcechanged',\n SOURCE_CHANGED: 'sourcechanged',\n LOADED_METADATA: 'loadedmetadata',\n LOADED_DATA: 'loadeddata',\n REFRESH_TEXT_TRACKS: 'refreshTextTracks',\n PLAYLIST_CREATED: 'playlistcreated',\n UP_COMING_VIDEO_SHOW: 'upcomingvideoshow',\n UP_COMING_VIDEO_HIDE: 'upcomingvideohide',\n PLAYLIST_ITEM_CHANGED: 'playlistitemchanged',\n VOLUME_CHANGE: 'volumechange',\n FLUID: 'fluid',\n PLAYLIST_PANEL: 'PlaylistPanel',\n ENDED: 'ended',\n RESIZE: 'resize',\n START: 'start',\n VIDEO_LOAD: 'videoload',\n PRODUCT_BAR_MIN: 'productBarMin',\n SHOW_PRODUCTS_OVERLAY: 'showProductsOverlay',\n SHOPPABLE_ITEM_CHANGED: 'shoppableitemchanged',\n FULL_SCREEN_CHANGE: 'fullscreenchange',\n PERCENTS_PLAYED: 'percentsplayed',\n TIME_PLAYED: 'timeplayed',\n PLAYER_LOAD: 'playerload',\n DISPOSE: 'dispose',\n QUALITY_CHANGED: 'qualitychanged'\n};\nconst SOURCE_TYPE = {\n AUDIO: 'AudioSource',\n VIDEO: 'VideoSource'\n};\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/consts.js?");
/***/ }),
/***/ "./utils/css-prefix.js":
/*!*****************************!*\
!*** ./utils/css-prefix.js ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ CLASS_PREFIX: () => (/* binding */ CLASS_PREFIX),\n/* harmony export */ playerClassPrefix: () => (/* binding */ playerClassPrefix),\n/* harmony export */ setSkinClassPrefix: () => (/* binding */ setSkinClassPrefix),\n/* harmony export */ skinClass: () => (/* binding */ skinClass),\n/* harmony export */ skinClassPrefix: () => (/* binding */ skinClassPrefix)\n/* harmony export */ });\n/* harmony import */ var _config_defaults__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../config/defaults */ \"./config/defaults.js\");\n/* harmony import */ var _find__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./find */ \"./utils/find.js\");\n\n\nconst CLASS_PREFIX = 'cld-video-player';\nconst SKIN_CLASS_PREFIX = `${CLASS_PREFIX}-skin-`;\nconst playerClassPrefix = componentInstance => `${CLASS_PREFIX}-${componentInstance.id_}`;\nconst skinClass = skin => `${SKIN_CLASS_PREFIX}${skin}`;\nconst skinClassPrefix = componentInstance => (0,_find__WEBPACK_IMPORTED_MODULE_1__.find)(componentInstance.el().classList, cls => cls.startsWith(SKIN_CLASS_PREFIX));\nconst setSkinClassPrefix = (componentInstance, name) => {\n const currentSkinPrefix = skinClassPrefix(componentInstance);\n const skinName = name ? name.replace(SKIN_CLASS_PREFIX, '') : false;\n let newSkinPrefix = '';\n if (skinName) {\n // From html class\n newSkinPrefix = skinClass(skinName);\n } else if (componentInstance.options_.skin) {\n // From JS config\n newSkinPrefix = skinClass(componentInstance.options_.skin);\n } else {\n // Defult\n newSkinPrefix = skinClass(_config_defaults__WEBPACK_IMPORTED_MODULE_0__[\"default\"].skin);\n }\n if (newSkinPrefix !== currentSkinPrefix) {\n if (currentSkinPrefix) {\n componentInstance.removeClass(currentSkinPrefix);\n }\n componentInstance.addClass(newSkinPrefix);\n }\n if (skinName && componentInstance.options_.skin !== skinName) {\n componentInstance.options_.skin = skinName;\n }\n};\n\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/css-prefix.js?");
/***/ }),
/***/ "./utils/dom.js":
/*!**********************!*\
!*** ./utils/dom.js ***!
\**********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ addEventListener: () => (/* binding */ addEventListener),\n/* harmony export */ createElement: () => (/* binding */ createElement),\n/* harmony export */ elementsCreator: () => (/* binding */ elementsCreator),\n/* harmony export */ styleElement: () => (/* binding */ styleElement)\n/* harmony export */ });\n/* harmony import */ var lodash_castArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lodash/castArray */ \"../node_modules/lodash/castArray.js\");\n/* harmony import */ var lodash_castArray__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(lodash_castArray__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var lodash_isElement__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lodash/isElement */ \"../node_modules/lodash/isElement.js\");\n/* harmony import */ var lodash_isElement__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(lodash_isElement__WEBPACK_IMPORTED_MODULE_1__);\n\n\nconst createElement = function (elementName) {\n let attributes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n let children = arguments.length > 2 ? arguments[2] : undefined;\n const element = document.createElement(elementName);\n for (let key in attributes) {\n if (Object.prototype.hasOwnProperty.call(attributes, key)) {\n element.setAttribute(key, attributes[key]);\n }\n }\n lodash_castArray__WEBPACK_IMPORTED_MODULE_0___default()(children).forEach(child => appendChild(child, element));\n return element;\n};\nconst appendChild = (child, element) => {\n if (lodash_isElement__WEBPACK_IMPORTED_MODULE_1___default()(child)) {\n element.appendChild(child);\n } else if (child && typeof child !== 'object') {\n const text = document.createTextNode(child);\n element.appendChild(text);\n }\n};\nconst styleElement = (element, style) => {\n for (let key in style) {\n if (Object.prototype.hasOwnProperty.call(style, key)) {\n element.style[key] = style[key];\n }\n }\n return element;\n};\nconst elementsCreator = item => {\n const children = Array.isArray(item.children) ? item.children.map(elementsCreator) : item.children;\n const element = lodash_isElement__WEBPACK_IMPORTED_MODULE_1___default()(item) ? item : createElement(item.tag, item.attr, children);\n if (item.onClick) {\n item.event = {\n name: 'click',\n callback: item.onClick\n };\n }\n if (item.event) {\n element.addEventListener(item.event.name, item.event.callback, false);\n }\n if (item.style) {\n styleElement(element, item.style);\n }\n return element;\n};\nconst addEventListener = (element, name, cb) => {\n element.addEventListener(name, cb, false);\n return () => {\n element.removeEventListener(name, cb, false);\n };\n};\n\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/dom.js?");
/***/ }),
/***/ "./utils/find.js":
/*!***********************!*\
!*** ./utils/find.js ***!
\***********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ find: () => (/* binding */ find)\n/* harmony export */ });\nfunction find(list, callback) {\n if (Array.prototype.find && Array.isArray(list)) {\n return list.find(callback);\n }\n return findElementAndIndex(list, callback)[0];\n}\nfunction findElementAndIndex(list, callback) {\n for (let i = 0; i < list.length; i++) {\n const element = list[i];\n if (callback(element, i, list)) {\n return [element, i];\n }\n }\n return [undefined, -1];\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/find.js?");
/***/ }),
/***/ "./utils/fontFace.js":
/*!***************************!*\
!*** ./utils/fontFace.js ***!
\***************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ fontFace: () => (/* binding */ fontFace)\n/* harmony export */ });\n/* harmony import */ var webfontloader__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! webfontloader */ \"../node_modules/webfontloader/webfontloader.js\");\n/* harmony import */ var webfontloader__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(webfontloader__WEBPACK_IMPORTED_MODULE_0__);\n\nconst FONT_FAMILY = 'Inter';\nconst fontFace = (elem, fontFace) => {\n // Default font-face is \"Inter\"\n if (typeof fontFace === 'undefined') {\n fontFace = FONT_FAMILY;\n }\n if (fontFace && fontFace !== 'inherit') {\n webfontloader__WEBPACK_IMPORTED_MODULE_0___default().load({\n google: {\n families: [fontFace]\n }\n });\n elem.style.fontFamily = fontFace;\n } else if (fontFace === 'inherit') {\n elem.style.fontFamily = 'inherit';\n }\n};\n\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/fontFace.js?");
/***/ }),
/***/ "./utils/get-analytics-player-options.js":
/*!***********************************************!*\
!*** ./utils/get-analytics-player-options.js ***!
\***********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ getAnalyticsFromPlayerOptions: () => (/* binding */ getAnalyticsFromPlayerOptions)\n/* harmony export */ });\n/* harmony import */ var config_defaults__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! config/defaults */ \"./config/defaults.js\");\n/* harmony import */ var lodash_isEmpty__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lodash/isEmpty */ \"../node_modules/lodash/isEmpty.js\");\n/* harmony import */ var lodash_isEmpty__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(lodash_isEmpty__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var lodash_isObject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! lodash/isObject */ \"../node_modules/lodash/isObject.js\");\n/* harmony import */ var lodash_isObject__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(lodash_isObject__WEBPACK_IMPORTED_MODULE_2__);\n\n\n\nconst hasConfig = obj => lodash_isEmpty__WEBPACK_IMPORTED_MODULE_1___default()(obj) ? null : true;\nconst filterDefaultsAndNulls = obj => Object.entries(obj).reduce((filtered, _ref) => {\n let [key, value] = _ref;\n if (value !== config_defaults__WEBPACK_IMPORTED_MODULE_0__[\"default\"][key] && value !== undefined && value !== null) {\n filtered[key] = value;\n }\n return filtered;\n}, {});\nconst getSourceOptions = function () {\n let sourceOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return {\n posterOptions: hasConfig(sourceOptions.posterOptions),\n posterOptionsPublicId: sourceOptions.posterOptions && hasConfig(sourceOptions.posterOptions.publicId),\n autoShowRecommendations: sourceOptions.autoShowRecommendations,\n fontFace: sourceOptions.fontFace,\n sourceTypes: sourceOptions.sourceTypes,\n chapters: (() => {\n if (sourceOptions.chapters === true) return 'auto';\n if (sourceOptions.chapters && sourceOptions.chapters.url) return 'url';\n if (sourceOptions.chapters) return 'inline-chapters';\n return undefined;\n })(),\n visualSearch: sourceOptions.visualSearch,\n download: hasConfig(sourceOptions.download),\n recommendations: sourceOptions.recommendations && sourceOptions.recommendations.length,\n ...(hasConfig(sourceOptions.adaptiveStreaming) ? {\n abrStrategy: sourceOptions?.adaptiveStreaming?.strategy === config_defaults__WEBPACK_IMPORTED_MODULE_0__[\"default\"].adaptiveStreaming.strategy ? undefined : sourceOptions?.adaptiveStreaming?.strategy\n } : {}),\n shoppable: hasConfig(sourceOptions.shoppable),\n shoppableProductsLength: sourceOptions.shoppable && sourceOptions.shoppable.products && sourceOptions.shoppable.products.length,\n ...(sourceOptions.title || sourceOptions.description || sourceOptions.info ? {\n sourceInfo: hasConfig(sourceOptions.info),\n sourceTitle: typeof sourceOptions.title === 'string' ? sourceOptions.title : sourceOptions.info?.title,\n sourceDescription: typeof sourceOptions.description === 'string' ? sourceOptions.description : sourceOptions.info?.subtitle || sourceOptions.info?.description\n } : {}),\n ...(hasConfig(sourceOptions.textTracks) ? getTextTracksOptions(sourceOptions.textTracks) : {})\n };\n};\nconst getTextTracksOptions = function () {\n let textTracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n const tracksArr = [textTracks.captions, ...(textTracks.subtitles || [])];\n return {\n textTracks: hasConfig(textTracks),\n textTracksLength: tracksArr.length,\n textTracksOptions: hasConfig(textTracks.options) && Object.keys(textTracks.options).join(','),\n pacedTextTracks: hasConfig(textTracks) && JSON.stringify(textTracks || {}).includes('\"maxWords\":') || null,\n wordHighlight: hasConfig(textTracks) && JSON.stringify(textTracks || {}).includes('\"wordHighlight\":') || null,\n transcriptLanguages: tracksArr.filter(track => !track.url).map(track => track.language || '').join(',') || null,\n transcriptAutoLoaded: tracksArr.some(track => !track.url) || null,\n transcriptFromURl: tracksArr.some(track => track.url?.endsWith('.transcript')) || null,\n vttFromUrl: tracksArr.some(track => track.url?.endsWith('.vtt')) || null,\n srtFromUrl: tracksArr.some(track => track.url?.endsWith('.srt')) || null,\n ...(textTracks.options ? {\n styledTextTracksTheme: textTracks.options.theme,\n styledTextTracksFont: textTracks.options.fontFace,\n styledTextTracksFontSize: textTracks.options.fontSize,\n styledTextTracksGravity: textTracks.options.gravity,\n styledTextTracksBox: hasConfig(textTracks.options.box),\n styledTextTracksStyle: hasConfig(textTracks.options.style),\n styledTextTracksWordHighlightStyle: hasConfig(textTracks.options.wordHighlightStyle)\n } : {})\n };\n};\nconst getAdsOptions = function () {\n let adsOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return {\n adsAdTagUrl: adsOptions.adTagUrl,\n adsShowCountdown: adsOptions.showCountdown,\n adsAdLabel: adsOptions.adLabel,\n adsLocale: adsOptions.locale,\n adsPrerollTimeout: adsOptions.prerollTimeout,\n adsPostrollTimeout: adsOptions.postrollTimeout,\n adsAdsInPlaylist: adsOptions.adsInPlaylist\n };\n};\nconst getPlaylistOptions = function () {\n let playlistWidgetOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n return {\n playlist: playlistWidgetOptions.playlist,\n playlistByTag: playlistWidgetOptions.playlistByTag,\n playlistWidgetDirection: playlistWidgetOptions.direction,\n playlistWidgetTotal: playlistWidgetOptions.total\n };\n};\nconst getAnalyticsFromPlayerOptions = playerOptions => filterDefaultsAndNulls({\n aiHighlightsGraph: playerOptions.aiHighlightsGraph,\n analytics: hasConfig(playerOptions.analytics),\n autoplay: playerOptions.autoplay,\n autoplayMode: playerOptions.autoplayMode,\n bigPlayButton: playerOptions.bigPlayButton,\n className: playerOptions.class,\n cloudinaryAnalytics: !!playerOptions.cloudinaryAnalytics,\n cloudinaryAnalyticsOptions: lodash_isObject__WEBPACK_IMPORTED_MODULE_2___default()(playerOptions.cloudinaryAnalytics),\n controls: playerOptions.controls,\n floatingWhenNotVisible: playerOptions.floatingWhenNotVisible,\n fluid: playerOptions.fluid,\n height: playerOptions.height,\n hideContextMenu: playerOptions.hideContextMenu,\n logoImageUrl: playerOptions.logoImageUrl,\n logoOnclickUrl: playerOptions.logoOnclickUrl,\n loop: playerOptions.loop,\n maxTries: playerOptions.maxTries,\n muted: playerOptions.muted,\n playbackRates: playerOptions.playbackRates,\n playedEventPercents: playerOptions.playedEventPercents,\n playedEventTimes: playerOptions.playedEventTimes,\n playsinline: playerOptions.playsinline,\n preload: playerOptions.preload,\n videoTimeout: playerOptions.videoTimeout,\n seekThumbnails: playerOptions.seekThumbnails,\n showJumpControls: playerOptions.showJumpControls,\n chaptersButton: playerOptions.chaptersButton,\n pictureInPictureToggle: playerOptions.pictureInPictureToggle,\n showLogo: playerOptions.showLogo,\n skin: playerOptions.skin,\n videoJS: hasConfig(playerOptions.videoJS),\n width: playerOptions.width,\n withCredentials: playerOptions.withCredentials,\n debug: playerOptions.debug,\n type: playerOptions.type,\n colors: playerOptions.colors && JSON.stringify(playerOptions.colors),\n controlBar: JSON.stringify(playerOptions.controlBar) !== JSON.stringify(config_defaults__WEBPACK_IMPORTED_MODULE_0__[\"default\"].controlBar) && JSON.stringify(playerOptions.controlBar),\n ...getSourceOptions(playerOptions.sourceOptions || {}),\n ...getAdsOptions(playerOptions.ads),\n ...getPlaylistOptions(playerOptions.playlistWidget)\n});\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/get-analytics-player-options.js?");
/***/ }),
/***/ "./utils/index.js":
/*!************************!*\
!*** ./utils/index.js ***!
\************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _slicing__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./slicing */ \"./utils/slicing.js\");\n/* harmony import */ var _positioning__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./positioning */ \"./utils/positioning.js\");\n/* harmony import */ var _cloudinary__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./cloudinary */ \"./utils/cloudinary.js\");\n/* harmony import */ var _mixin__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./mixin */ \"./utils/mixin.js\");\n/* harmony import */ var _fontFace__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./fontFace */ \"./utils/fontFace.js\");\n/* harmony import */ var _css_prefix__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./css-prefix */ \"./utils/css-prefix.js\");\n/* harmony import */ var _attributes_normalizer__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./attributes-normalizer */ \"./utils/attributes-normalizer.js\");\n\n\n\n\n\n\n\nconst Utils = Object.assign({}, _slicing__WEBPACK_IMPORTED_MODULE_0__, _positioning__WEBPACK_IMPORTED_MODULE_1__, _cloudinary__WEBPACK_IMPORTED_MODULE_2__, _fontFace__WEBPACK_IMPORTED_MODULE_4__, _mixin__WEBPACK_IMPORTED_MODULE_3__, _css_prefix__WEBPACK_IMPORTED_MODULE_5__, _attributes_normalizer__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Utils);\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/index.js?");
/***/ }),
/***/ "./utils/mixin.js":
/*!************************!*\
!*** ./utils/mixin.js ***!
\************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ mixin: () => (/* binding */ mixin)\n/* harmony export */ });\nfunction mixin() {\n for (var _len = arguments.length, mixins = new Array(_len), _key = 0; _key < _len; _key++) {\n mixins[_key] = arguments[_key];\n }\n return mixins.reduce((c, mixin) => mixin(c), class Blank {});\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/mixin.js?");
/***/ }),
/***/ "./utils/object.js":
/*!*************************!*\
!*** ./utils/object.js ***!
\*************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ convertKeysToSnakeCase: () => (/* binding */ convertKeysToSnakeCase)\n/* harmony export */ });\n/* harmony import */ var lodash_snakeCase__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lodash/snakeCase */ \"../node_modules/lodash/snakeCase.js\");\n/* harmony import */ var lodash_snakeCase__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(lodash_snakeCase__WEBPACK_IMPORTED_MODULE_0__);\n\nconst convertKeysToSnakeCase = obj => {\n let snakeCaseObj = {};\n for (const key of Object.keys(obj)) {\n const snakeCaseKey = lodash_snakeCase__WEBPACK_IMPORTED_MODULE_0___default()(key);\n snakeCaseObj[snakeCaseKey] = obj[key];\n }\n return snakeCaseObj;\n};\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/object.js?");
/***/ }),
/***/ "./utils/positioning.js":
/*!******************************!*\
!*** ./utils/positioning.js ***!
\******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ getPointerPosition: () => (/* binding */ getPointerPosition),\n/* harmony export */ isElementInViewport: () => (/* binding */ isElementInViewport),\n/* harmony export */ setPosition: () => (/* binding */ setPosition)\n/* harmony export */ });\nfunction getElementPosition(el) {\n const box = el.getBoundingClientRect();\n const body = document.body;\n const docEl = document.documentElement;\n const scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;\n const scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;\n const clientTop = docEl.clientTop || body.clientTop || 0;\n const clientLeft = docEl.clientLeft || body.clientLeft || 0;\n const top = box.top + scrollTop - clientTop;\n const left = box.left + scrollLeft - clientLeft;\n return {\n top: Math.round(top),\n left: Math.round(left)\n };\n}\n\n/**\n * Get pointer position in element\n * Returns an object with x and y coordinates.\n * The base on the coordinates are the bottom left of the element.\n *\n * @function getPointerPosition\n * @param {Element} el Element on which to get the pointer position on\n * @param {Event} event Event object\n * @return {Object}\n * This object will have x and y coordinates corresponding to the\n * mouse position\n */\nfunction getPointerPosition(el, event) {\n const position = {};\n const box = getElementPosition(el);\n const boxW = el.offsetWidth;\n const boxH = el.offsetHeight;\n const boxY = box.top;\n const boxX = box.left;\n let pageY = event.pageY;\n let pageX = event.pageX;\n if (event.changedTouches) {\n pageX = event.changedTouches[0].pageX;\n pageY = event.changedTouches[0].pageY;\n }\n position.y = Math.max(0, Math.min(1, (boxY - pageY + boxH) / boxH));\n position.x = Math.max(0, Math.min(1, (pageX - boxX) / boxW));\n return position;\n}\nfunction isElementInViewport(el, _ref) {\n let {\n fraction\n } = _ref;\n const topLeft = getElementPosition(el);\n const x = topLeft.left;\n const y = topLeft.top;\n const h = el.offsetHeight;\n const w = el.offsetWidth;\n const r = x + w;\n const b = y + h;\n const visibleX = Math.max(0, Math.min(w, window.pageXOffset + window.innerWidth - x, r - window.pageXOffset));\n const visibleY = Math.max(0, Math.min(w, window.pageYOffset + window.innerHeight - y, b - window.pageYOffset));\n const visible = visibleX * visibleY / (w * h);\n return visible > fraction;\n}\nfunction setPosition(el, left, top) {\n el.style.left = `${left}px`;\n el.style.top = `${top}px`;\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/positioning.js?");
/***/ }),
/***/ "./utils/querystring.js":
/*!******************************!*\
!*** ./utils/querystring.js ***!
\******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ objectToQuerystring: () => (/* binding */ objectToQuerystring)\n/* harmony export */ });\nconst objectToQuerystring = obj => {\n const keys = Object.keys(obj);\n if (!keys.length) {\n return '';\n }\n const query = keys.map(key => `${key}=${obj[key]}`).join('&');\n return `?${query}`;\n};\n\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/querystring.js?");
/***/ }),
/***/ "./utils/slicing.js":
/*!**************************!*\
!*** ./utils/slicing.js ***!
\**************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ sliceAndUnsetProperties: () => (/* binding */ sliceAndUnsetProperties),\n/* harmony export */ sliceProperties: () => (/* binding */ sliceProperties)\n/* harmony export */ });\nfunction _sliceProperties(obj, isUnset) {\n for (var _len = arguments.length, props = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {\n props[_key - 2] = arguments[_key];\n }\n return props.reduce((acc, prop) => {\n if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n acc[prop] = obj[prop];\n if (isUnset) {\n delete obj[prop];\n }\n }\n return acc;\n }, {});\n}\nfunction sliceProperties(obj) {\n for (var _len2 = arguments.length, props = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {\n props[_key2 - 1] = arguments[_key2];\n }\n return _sliceProperties(obj, false, ...props);\n}\nfunction sliceAndUnsetProperties(obj) {\n for (var _len3 = arguments.length, props = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {\n props[_key3 - 1] = arguments[_key3];\n }\n return _sliceProperties(obj, true, ...props);\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/slicing.js?");
/***/ }),
/***/ "./utils/utf8Base64.js":
/*!*****************************!*\
!*** ./utils/utf8Base64.js ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ utf8ToBase64: () => (/* binding */ utf8ToBase64)\n/* harmony export */ });\nfunction utf8ToBase64(str) {\n const utf8Bytes = new TextEncoder().encode(str);\n const binaryStr = String.fromCharCode(...utf8Bytes);\n return btoa(binaryStr);\n}\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/utf8Base64.js?");
/***/ }),
/***/ "./utils/video-retry.js":
/*!******************************!*\
!*** ./utils/video-retry.js ***!
\******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ checkIfVideoIsAvailable: () => (/* binding */ checkIfVideoIsAvailable),\n/* harmony export */ isVideoInReadyState: () => (/* binding */ isVideoInReadyState)\n/* harmony export */ });\nconst checkIfVideoIsAvailable = function (videoUrl) {\n let videoType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'default';\n return new Promise((resolve, reject) => {\n const tempVideo = document.createElement('video');\n tempVideo.setAttribute('crossorigin', 'anonymous');\n const targetEvent = videoType === 'live' ? 'onprogress' : 'canplay';\n tempVideo[targetEvent] = () => {\n tempVideo.onerror = null;\n tempVideo[targetEvent] = null;\n resolve();\n };\n tempVideo.onerror = () => reject();\n tempVideo.src = videoUrl;\n tempVideo.load();\n });\n};\nconst isVideoInReadyState = readyState => {\n return readyState >= (/iPad|iPhone|iPod/.test(navigator.userAgent) ? 1 : 4);\n};\n\n\n//# sourceURL=webpack://cloudinary-video-player/./utils/video-retry.js?");
/***/ }),
/***/ "./validators/validators-functions.js":
/*!********************************************!*\
!*** ./validators/validators-functions.js ***!
\********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ getValidatorItem: () => (/* binding */ getValidatorItem),\n/* harmony export */ isValidConfig: () => (/* binding */ isValidConfig),\n/* harmony export */ isValidPlayerConfig: () => (/* binding */ isValidPlayerConfig),\n/* harmony export */ isValidSourceConfig: () => (/* binding */ isValidSourceConfig),\n/* harmony export */ isValueValid: () => (/* binding */ isValueValid)\n/* harmony export */ });\n/* harmony import */ var lodash_isFunction__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lodash/isFunction */ \"../node_modules/lodash/isFunction.js\");\n/* harmony import */ var lodash_isFunction__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(lodash_isFunction__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var lodash_isObject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lodash/isObject */ \"../node_modules/lodash/isObject.js\");\n/* harmony import */ var lodash_isObject__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(lodash_isObject__WEBPACK_IMPORTED_MODULE_1__);\n\n\nconst getValidatorItem = validator => lodash_isFunction__WEBPACK_IMPORTED_MODULE_0___default()(validator) ? validator() : validator;\n\n/**\n * check if a value is valid or not\n * @param {object | function} validator - a config object\n * @param {any} value\n * @param {key} string\n * @returns boolean - using the validators to check if the value is a valid value or not\n */\nconst isValueValid = (validator, value, configPropertyName) => {\n const validatorItem = getValidatorItem(validator);\n const isValid = validatorItem.value(value);\n if (!isValid) {\n console.error(`cloudinary video player: ${validatorItem.message(configPropertyName)}`);\n }\n return isValid;\n};\n\n/**\n * check if a configuration object is valid or not\n * @param {object} config - a config object\n * @param {object} validators\n * @returns boolean - true is the configuration object is valid and false if it is not\n */\nconst isValidConfig = (config, validators) => {\n if (lodash_isObject__WEBPACK_IMPORTED_MODULE_1___default()(validators)) {\n for (let key in config) {\n if (Object.prototype.hasOwnProperty.call(validators, key)) {\n const configValue = config[key];\n const validatorValue = validators[key];\n const isConfigObject = lodash_isObject__WEBPACK_IMPORTED_MODULE_1___default()(configValue);\n if (isConfigObject && !isValidConfig(configValue, validatorValue)) {\n return false;\n } else if (!isConfigObject && !isValueValid(validatorValue, configValue, key)) {\n return false;\n }\n }\n }\n }\n return true;\n};\n\n/**\n * check if a configuration object is valid or not\n * @param {object} config - a config object\n * @returns boolean - true is the configuration object is valid and false if it is not\n */\nconst isValidPlayerConfig = async config => {\n return __webpack_require__.e(/*! import() | debug */ \"debug\").then(__webpack_require__.bind(__webpack_require__, /*! ./validators */ \"./validators/validators.js\")).then(_ref => {\n let {\n playerValidators\n } = _ref;\n return isValidConfig(config, playerValidators);\n });\n};\n\n/**\n * check if a configuration object is valid or not\n * @param {object} config - a config object\n * @returns boolean - true is the configuration object is valid and false if it is not\n */\nconst isValidSourceConfig = config => {\n return __webpack_require__.e(/*! import() | debug */ \"debug\").then(__webpack_require__.bind(__webpack_require__, /*! ./validators */ \"./validators/validators.js\")).then(_ref2 => {\n let {\n sourceValidators\n } = _ref2;\n return isValidConfig(config, sourceValidators);\n });\n};\n\n//# sourceURL=webpack://cloudinary-video-player/./validators/validators-functions.js?");
/***/ }),
/***/ "./video-player.const.js":
/*!*******************************!*\
!*** ./video-player.const.js ***!
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ADS_IN_PLAYLIST: () => (/* binding */ ADS_IN_PLAYLIST),\n/* harmony export */ AUTO_PLAY_MODE: () => (/* binding */ AUTO_PLAY_MODE),\n/* harmony export */ CLOUDINARY_CONFIG_PARAM: () => (/* binding */ CLOUDINARY_CONFIG_PARAM),\n/* harmony export */ FLOATING_TO: () => (/* binding */ FLOATING_TO),\n/* harmony export */ FLUID_CLASS_NAME: () => (/* binding */ FLUID_CLASS_NAME),\n/* harmony export */ PLAYER_PARAMS: () => (/* binding */ PLAYER_PARAMS),\n/* harmony export */ PRELOAD: () => (/* binding */ PRELOAD),\n/* harmony export */ SOURCE_PARAMS: () => (/* binding */ SOURCE_PARAMS)\n/* harmony export */ });\n// Parameters that can be passed to source configuration (inherited by source method)\nconst SOURCE_PARAMS = ['adaptiveStreaming', 'autoShowRecommendations', 'chapters', 'cloudinaryConfig', 'description', 'download', 'info', 'interactionAreas', 'poster', 'posterOptions', 'publicId', 'rawTransformation', 'recommendations', 'shoppable', 'source', 'sourceTransformation', 'sourceTypes', 'textTracks', 'title', 'transformation', 'type', 'visualSearch', 'withCredentials'];\n\n// All parameters that can be passed to player constructor\nconst PLAYER_PARAMS = SOURCE_PARAMS.concat(['_internalAnalyticsMetadata', 'ads', 'aiHighlightsGraph', 'allowUsageReport', 'analytics', 'autoplayMode', 'chaptersButton', 'cloudinaryAnalytics', 'colors', 'debug', 'fetchErrorUsingGet', 'floatingWhenNotVisible', 'fluid', 'fontFace', 'hideContextMenu', 'ima', 'pictureInPictureToggle', 'playedEventPercents', 'playedEventTimes', 'playlistWidget', 'qualitySelector', 'queryParams', 'seekThumbnails', 'showJumpControls']);\n\n// We support both camelCase and snake_case for cloudinary SDK params\nconst CLOUDINARY_CONFIG_PARAM = ['api_secret', 'auth_token', 'cdn_subdomain', 'cloud_name', 'cname', 'private_cdn', 'secure', 'secure_cdn_subdomain', 'secure_distribution', 'shorten', 'sign_url', 'url_suffix', 'use_root_path'];\nconst FLUID_CLASS_NAME = 'cld-fluid';\nconst AUTO_PLAY_MODE = {\n ALWAYS: 'always',\n ON_SCROLL: 'on-scroll',\n NEVER: 'never'\n};\nconst FLOATING_TO = {\n LEFT: 'left',\n RIGHT: 'right',\n NONE: 'none'\n};\nconst ADS_IN_PLAYLIST = {\n FIRST_VIDEO: 'first-video',\n EVERY_VIDEO: 'every-video'\n};\nconst PRELOAD = {\n AUTO: 'auto',\n METADATA: 'metadata',\n NONE: 'none'\n};\n\n//# sourceURL=webpack://cloudinary-video-player/./video-player.const.js?");
/***/ }),
/***/ "./video-player.js":
/*!*************************!*\
!*** ./video-player.js ***!
\*************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var uuid__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! uuid */ \"../node_modules/uuid/dist/esm-browser/v4.js\");\n/* harmony import */ var lodash_isEmpty__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! lodash/isEmpty */ \"../node_modules/lodash/isEmpty.js\");\n/* harmony import */ var lodash_isEmpty__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(lodash_isEmpty__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var lodash_get__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! lodash/get */ \"../node_modules/lodash/get.js\");\n/* harmony import */ var lodash_get__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(lodash_get__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var lodash_pick__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! lodash/pick */ \"../node_modules/lodash/pick.js\");\n/* harmony import */ var lodash_pick__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(lodash_pick__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var lodash_isFunction__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! lodash/isFunction */ \"../node_modules/lodash/isFunction.js\");\n/* harmony import */ var lodash_isFunction__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(lodash_isFunction__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var lodash_isObject__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! lodash/isObject */ \"../node_modules/lodash/isObject.js\");\n/* harmony import */ var lodash_isObject__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(lodash_isObject__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var lodash_isString__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! lodash/isString */ \"../node_modules/lodash/isString.js\");\n/* harmony import */ var lodash_isString__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(lodash_isString__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _components__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./components */ \"./components/index.js\");\n/* harmony import */ var _plugins__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./plugins */ \"./plugins/index.js\");\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./utils */ \"./utils/index.js\");\n/* harmony import */ var _config_defaults__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./config/defaults */ \"./config/defaults.js\");\n/* harmony import */ var _mixins_eventable__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./mixins/eventable */ \"./mixins/eventable.js\");\n/* harmony import */ var _extended_events__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./extended-events */ \"./extended-events.js\");\n/* harmony import */ var _plugins_cloudinary_models_video_source_video_source__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./plugins/cloudinary/models/video-source/video-source */ \"./plugins/cloudinary/models/video-source/video-source.js\");\n/* harmony import */ var _video_player_utils__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./video-player.utils */ \"./video-player.utils.js\");\n/* harmony import */ var _video_player_const__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./video-player.const */ \"./video-player.const.js\");\n/* harmony import */ var _validators_validators_functions__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./validators/validators-functions */ \"./validators/validators-functions.js\");\n/* harmony import */ var _utils_consts__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./utils/consts */ \"./utils/consts.js\");\n/* harmony import */ var _utils_get_analytics_player_options__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./utils/get-analytics-player-options */ \"./utils/get-analytics-player-options.js\");\n/* harmony import */ var _plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./plugins/cloudinary/common */ \"./plugins/cloudinary/common.js\");\n/* harmony import */ var _utils_video_retry__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./utils/video-retry */ \"./utils/video-retry.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst INTERNAL_ANALYTICS_URL = 'https://analytics-api-s.cloudinary.com';\nconst RETRY_DEFAULT_TIMEOUT = 5 * 1000;\n\n// Register all plugins\nObject.keys(_plugins__WEBPACK_IMPORTED_MODULE_8__[\"default\"]).forEach(key => {\n video_js__WEBPACK_IMPORTED_MODULE_0___default().registerPlugin(key, _plugins__WEBPACK_IMPORTED_MODULE_8__[\"default\"][key]);\n});\n(0,_video_player_utils__WEBPACK_IMPORTED_MODULE_14__.overrideDefaultVideojsComponents)();\nclass VideoPlayer extends _utils__WEBPACK_IMPORTED_MODULE_9__[\"default\"].mixin(_mixins_eventable__WEBPACK_IMPORTED_MODULE_11__[\"default\"]) {\n static all(selector) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n const nodeList = document.querySelectorAll(selector);\n return [...nodeList].map(node => new VideoPlayer(node, ...args));\n }\n get playerOptions() {\n return this.options.playerOptions;\n }\n constructor(elem, initOptions, ready) {\n super();\n this.videoElement = (0,_video_player_utils__WEBPACK_IMPORTED_MODULE_14__.getResolveVideoElement)(elem);\n this.options = (0,_video_player_utils__WEBPACK_IMPORTED_MODULE_14__.extractOptions)(this.videoElement, initOptions);\n this._videojsOptions = this.options.videojsOptions;\n\n // Make sure to add 'video-js' class before creating videojs instance\n this.videoElement.classList.add('video-js');\n\n // Handle WebFont loading\n _utils__WEBPACK_IMPORTED_MODULE_9__[\"default\"].fontFace(this.videoElement, this.playerOptions.fontFace);\n\n // Handle play button options\n if (this._videojsOptions.bigPlayButton === 'init') {\n this.videoElement.classList.add('vjs-big-play-button-init-only');\n this._videojsOptions.bigPlayButton = true;\n }\n this.videojs = video_js__WEBPACK_IMPORTED_MODULE_0___default()(this.videoElement, this._videojsOptions);\n this._isPlayerConfigValid = true;\n if (this.playerOptions.debug) {\n (0,_validators_validators_functions__WEBPACK_IMPORTED_MODULE_16__.isValidPlayerConfig)(this.options).then(valid => {\n if (!valid) {\n this._isPlayerConfigValid = false;\n this.videojs.error('invalid player configuration');\n return;\n }\n });\n }\n if (this._videojsOptions.muted) {\n this.videojs.volume(0.4);\n }\n if (this.playerOptions.fluid) {\n this.fluid(this.playerOptions.fluid);\n }\n this._setCssClasses();\n this._initPlugins();\n this._initJumpButtons();\n this._initPictureInPicture();\n this._setVideoJsListeners(ready);\n }\n getVPInstanceId() {\n if (!this.vpInstanceId) {\n this.vpInstanceId = (0,uuid__WEBPACK_IMPORTED_MODULE_21__[\"default\"])();\n }\n return this.vpInstanceId;\n }\n _sendInternalAnalytics() {\n let additionalOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n const options = Object.assign({}, this.playerOptions, this.options.videojsOptions, additionalOptions);\n if (!options.allowUsageReport) {\n return;\n }\n try {\n const internalAnalyticsMetadata = options._internalAnalyticsMetadata ?? {};\n const analyticsData = (0,_utils_get_analytics_player_options__WEBPACK_IMPORTED_MODULE_18__.getAnalyticsFromPlayerOptions)(options);\n const analyticsParams = new URLSearchParams(analyticsData).toString();\n const baseParams = new URLSearchParams({\n vpVersion: \"3.2.1\",\n vpInstanceId: this.getVPInstanceId(),\n cloudName: options.cloudinary.cloud_name,\n ...internalAnalyticsMetadata\n }).toString();\n fetch(`${INTERNAL_ANALYTICS_URL}/video_player_source?${analyticsParams}&${baseParams}`);\n } catch (err) {\n console.warn(err);\n }\n }\n _resetReTryVideoState = () => {\n this.reTryVideoStateRetriesCount = 0;\n this.videojs.clearTimeout(this.reTryVideoStateTimeoutId);\n };\n _setVideoJsListeners(ready) {\n this.videojs.on(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.ERROR, () => {\n const error = this.videojs.error();\n if (error) {\n const type = this._isPlayerConfigValid && this.videojs.cloudinary.currentSourceType();\n\n /*\n error codes :\n 3 - media playback was aborted due to a corruption problem\n 4 - media error, media source not supported\n */\n const isCorrupted = error.code === 3 && (video_js__WEBPACK_IMPORTED_MODULE_0___default().browser).IS_SAFARI;\n if ([isCorrupted, error.code === 4].includes(true) && [_utils_consts__WEBPACK_IMPORTED_MODULE_17__.SOURCE_TYPE.AUDIO, _utils_consts__WEBPACK_IMPORTED_MODULE_17__.SOURCE_TYPE.VIDEO].includes(type)) {\n if (this.isLiveStream) {\n this.videojs.error({\n code: _plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_19__.ERROR_CODE.CUSTOM,\n message: 'Live Stream not started'\n });\n this.reloadVideoUntilAvailable();\n } else {\n this.videojs.error(null);\n _utils__WEBPACK_IMPORTED_MODULE_9__[\"default\"].handleCldError(this, this.playerOptions);\n }\n } else {\n this._resetReTryVideoState();\n }\n }\n });\n this.videojs.tech_.on(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.RETRY_PLAYLIST, () => {\n const mediaRequestsErrored = lodash_get__WEBPACK_IMPORTED_MODULE_2___default()(this.videojs, 'hls.stats.mediaRequestsErrored', 0);\n if (mediaRequestsErrored > 0) {\n this._resetReTryVideoState();\n _utils__WEBPACK_IMPORTED_MODULE_9__[\"default\"].handleCldError(this, this.playerOptions);\n }\n });\n this.videojs.on(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.PLAY, this._resetReTryVideoState);\n this.videojs.on(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.CAN_PLAY_THROUGH, this._resetReTryVideoState);\n this.videojs.on(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.CLD_SOURCE_CHANGED, this._onSourceChange.bind(this));\n this.videojs.ready(() => {\n this._onReady();\n if (ready) {\n ready(this);\n }\n });\n }\n _initPlugins() {\n this._initIma();\n this._initAutoplay();\n this._initContextMenu();\n this._initPerSrcBehaviors();\n this._initCloudinary();\n this._initAnalytics();\n this._initCloudinaryAnalytics();\n this._initFloatingPlayer();\n this._initVisualSearch();\n this._initShare();\n this._initColors();\n this._initTextTracks();\n this._initHighlightsGraph();\n this._initSeekThumbs();\n this._initChapters();\n this._initInteractionAreas();\n }\n _isFullScreen() {\n return this.videojs.player().isFullscreen();\n }\n _initIma() {\n if (this.playerOptions.ads && Object.keys(this.playerOptions.ads).length !== 0) {\n _plugins__WEBPACK_IMPORTED_MODULE_8__[\"default\"].imaPlugin(this.videojs, this.playerOptions);\n }\n }\n setTextTracks(conf) {\n // remove current text tracks\n const currentTracks = this.videojs.remoteTextTracks();\n if (currentTracks) {\n for (let i = currentTracks.tracks_.length - 1; i >= 0; i--) {\n this.videojs.removeRemoteTextTrack(currentTracks.tracks_[i]);\n }\n }\n if (conf) {\n const kinds = Object.keys(conf);\n const allTracks = [];\n for (const kind of kinds) {\n if (kind !== 'options') {\n const tracks = Array.isArray(conf[kind]) ? conf[kind] : [conf[kind]];\n for (const track of tracks) {\n allTracks.push({\n ...track,\n kind: kind,\n label: track.label,\n srclang: track.language,\n default: !!track.default,\n src: track.url\n });\n }\n }\n }\n _utils__WEBPACK_IMPORTED_MODULE_9__[\"default\"].addTextTracks(allTracks, this.videojs);\n if (conf.options && this.videojs.styledTextTracks) {\n this.videojs.styledTextTracks(conf.options);\n }\n }\n }\n _initSeekThumbs() {\n if (this.playerOptions.seekThumbnails) {\n this.videojs.on(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.CLD_SOURCE_CHANGED, (e, _ref) => {\n let {\n source\n } = _ref;\n if (!source || source.getType() === _utils_consts__WEBPACK_IMPORTED_MODULE_17__.SOURCE_TYPE.AUDIO ||\n // Is Audio\n source.resourceConfig().type === 'live' ||\n // Is live stream\n (0,_plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_19__.isRawUrl)(source.publicId()) ||\n // Is a raw url\n this.videojs.activePlugins_ && this.videojs.activePlugins_.vr // It's a VR (i.e. 360)\n ) {\n return;\n }\n const publicId = source.publicId();\n const transformation = Object.assign({}, source.transformation());\n if (transformation) {\n delete transformation.streaming_profile;\n delete transformation.video_codec;\n }\n transformation.flags = transformation.flags || [];\n transformation.flags.push('sprite');\n const vttSrc = source.config().url(`${publicId}.vtt`, {\n transformation\n }).replace(/\\.json$/, ''); // Handle playlist by tag\n\n // vttThumbnails must be called differently on init and on source update.\n lodash_isFunction__WEBPACK_IMPORTED_MODULE_4___default()(this.videojs.vttThumbnails) ? this.videojs.vttThumbnails({\n src: vttSrc\n }) : this.videojs.vttThumbnails.src(vttSrc);\n });\n }\n }\n _initHighlightsGraph() {\n if (this.playerOptions.aiHighlightsGraph) {\n this.videojs.on(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.CLD_SOURCE_CHANGED, (e, _ref2) => {\n let {\n source\n } = _ref2;\n if (!source || source.getType() === _utils_consts__WEBPACK_IMPORTED_MODULE_17__.SOURCE_TYPE.AUDIO ||\n // Is Audio\n (0,_plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_19__.isRawUrl)(source.publicId()) // Is a raw url\n ) {\n return;\n }\n const publicId = source.publicId();\n\n // Keep video-length related transformations and remove the rest\n const inputTransformations = lodash_pick__WEBPACK_IMPORTED_MODULE_3___default()(source.transformation(), ['start_offset', 'end_offset', 'duration']);\n const transformation = Object.assign({}, inputTransformations);\n transformation.effect = 'preview';\n transformation.flags = transformation.flags || [];\n transformation.flags.push('getinfo');\n const aiHighlightsGraphSrc = source.config().url(`${publicId}`, {\n transformation\n }).replace(/\\.json$/, ''); // Handle playlist by tag\n\n // Plugin is called differently on init and on source update.\n lodash_isFunction__WEBPACK_IMPORTED_MODULE_4___default()(this.videojs.aiHighlightsGraph) ? this.videojs.aiHighlightsGraph({\n src: aiHighlightsGraphSrc\n }) : this.videojs.aiHighlightsGraph.src(aiHighlightsGraphSrc);\n });\n }\n }\n _initChapters() {\n if (!this.playerOptions.chaptersButton && this.videojs.controlBar) {\n this.videojs.controlBar.removeChild('chaptersButton');\n }\n this.videojs.on(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.CLD_SOURCE_CHANGED, (e, _ref3) => {\n let {\n source\n } = _ref3;\n if ((!lodash_isEmpty__WEBPACK_IMPORTED_MODULE_1___default()(source?._chapters) || source?._chapters === true) && this.videojs.chapters) {\n lodash_isFunction__WEBPACK_IMPORTED_MODULE_4___default()(this.videojs.chapters) ? this.videojs.chapters(source._chapters) : this.videojs.chapters.src(source._chapters);\n } else if (this.videojs.chapters?.resetPlugin) {\n this.videojs.chapters.resetPlugin();\n }\n });\n }\n _initInteractionAreas() {\n this.videojs.on(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.READY, async () => {\n if (this.options.videojsOptions.interactionDisplay && this.videojs.interactionAreas) {\n this.videojs.interactionAreas(this, this.playerOptions, this._videojsOptions);\n }\n });\n }\n _initVisualSearch() {\n // Listen for source changes to apply visual search based on source config\n this.videojs.on(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.CLD_SOURCE_CHANGED, (e, _ref4) => {\n let {\n source\n } = _ref4;\n if (source?._visualSearch && this.videojs.visualSearch) {\n lodash_isFunction__WEBPACK_IMPORTED_MODULE_4___default()(this.videojs.visualSearch) ? this.videojs.visualSearch(source._visualSearch) : this.videojs.visualSearch.createSearchUI(source._visualSearch);\n } else if (!source?._visualSearch && this.videojs.visualSearch?.clearUI) {\n this.videojs.visualSearch.clearUI();\n }\n });\n }\n _initShare() {\n // Listen for source changes to apply Share plugin based on source config\n this.videojs.on(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.CLD_SOURCE_CHANGED, (e, _ref5) => {\n let {\n source\n } = _ref5;\n if (!this.videojs.share) {\n return;\n }\n\n // First time: initialise plugin if necessary\n if (source?._download && lodash_isFunction__WEBPACK_IMPORTED_MODULE_4___default()(this.videojs.share)) {\n this.videojs.share({\n download: true\n });\n }\n if (!lodash_isFunction__WEBPACK_IMPORTED_MODULE_4___default()(this.videojs.share)) {\n // Plugin already initialised – update UI accordingly\n if (source?._download) {\n this.videojs.share.addDownloadButton?.();\n } else {\n this.videojs.share.removeDownloadButton?.();\n }\n }\n });\n }\n _initColors() {\n if (this.playerOptions.colors) {\n this.videojs.colors({\n colors: this.playerOptions.colors\n });\n }\n }\n _initTextTracks() {\n this.videojs.on(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.CLD_SOURCE_CHANGED, (e, _ref6) => {\n let {\n source\n } = _ref6;\n if (source?._textTracks) {\n this.setTextTracks(source._textTracks);\n }\n });\n }\n _initPerSrcBehaviors() {\n if (this.videojs.perSourceBehaviors) {\n this.videojs.perSourceBehaviors();\n }\n }\n _initJumpButtons() {\n if (!this.playerOptions.showJumpControls && this.videojs.controlBar) {\n this.videojs.controlBar.removeChild('JumpForwardButton');\n this.videojs.controlBar.removeChild('JumpBackButton');\n }\n }\n _initPictureInPicture() {\n if (!this.playerOptions.pictureInPictureToggle && this.videojs.controlBar) {\n this.videojs.controlBar.removeChild('pictureInPictureToggle');\n }\n }\n _initCloudinary() {\n const cloudinaryConfig = this.playerOptions.cloudinary;\n cloudinaryConfig.chainTarget = this;\n if (cloudinaryConfig.secure !== false) {\n (0,_plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_19__.extendCloudinaryConfig)(cloudinaryConfig, {\n secure: true\n });\n }\n\n // Merge cloudinary config with source config for the plugin\n const cloudinaryOptions = {\n cloudinaryConfig,\n ...this.playerOptions.sourceOptions\n };\n this.videojs.cloudinary(cloudinaryOptions);\n }\n _initAnalytics() {\n const analyticsOpts = this.playerOptions.analytics;\n if (!window.gtag && analyticsOpts) {\n console.error('Google Analytics script (gtag) is missing.');\n return;\n }\n if (analyticsOpts) {\n const opts = typeof analyticsOpts === 'object' ? analyticsOpts : {};\n this.videojs.analytics(opts);\n }\n }\n _initCloudinaryAnalytics() {\n const cloudinaryAnalyticsOptionEnabled = !!this.playerOptions.cloudinaryAnalytics;\n if (cloudinaryAnalyticsOptionEnabled) {\n this.videojs.videoElement = this.videoElement;\n const options = lodash_isObject__WEBPACK_IMPORTED_MODULE_5___default()(this.playerOptions.cloudinaryAnalytics) ? this.playerOptions.cloudinaryAnalytics : {};\n this.videojs.cloudinaryAnalytics(options);\n }\n }\n reTryVideoStateUntilAvailable() {\n let maxNumberOfCalls = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Number.POSITIVE_INFINITY;\n let timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : RETRY_DEFAULT_TIMEOUT;\n if (typeof this.reTryVideoStateRetriesCount !== 'number') {\n this.reTryVideoStateRetriesCount = 0;\n }\n if (!(0,_utils_video_retry__WEBPACK_IMPORTED_MODULE_20__.isVideoInReadyState)(this.videojs.readyState())) {\n if (this.reTryVideoStateRetriesCount < maxNumberOfCalls) {\n this.reTryVideoStateRetriesCount++;\n this.reTryVideoStateTimeoutId = this.videojs.setTimeout(() => this.reTryVideoStateUntilAvailable(maxNumberOfCalls, timeout), timeout);\n } else {\n let e = new Error('Video is not ready please try later');\n this.videojs.trigger('error', e);\n }\n } else {\n this.reTryVideoStateRetriesCount = 0;\n }\n }\n _resetReloadVideo = () => {\n this.reloadVideoRetriesCount = 0;\n this.videojs.clearTimeout(this.reloadVideoTimeoutId);\n };\n reloadVideoUntilAvailable() {\n let maxNumberOfCalls = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Number.POSITIVE_INFINITY;\n let timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : RETRY_DEFAULT_TIMEOUT;\n if (typeof this.reloadVideoRetriesCount !== 'number') {\n this.reloadVideoRetriesCount = 0;\n }\n if (this.reloadVideoRetriesCount < maxNumberOfCalls) {\n this.reloadVideoRetriesCount++;\n this.reloadVideoTimeoutId = this.videojs.setTimeout(() => {\n const videoUrl = this.currentSourceUrl();\n (0,_utils_video_retry__WEBPACK_IMPORTED_MODULE_20__.checkIfVideoIsAvailable)(videoUrl, this.isLiveStream ? 'live' : 'default').then(() => this.source(videoUrl)).catch(() => this.reloadVideoUntilAvailable(maxNumberOfCalls, timeout));\n }, timeout);\n } else {\n this.videojs.trigger('error', new Error('Sorry, we could not load your video'));\n }\n }\n _initAutoplay() {\n const autoplayMode = this.playerOptions.autoplayMode;\n if (autoplayMode === 'on-scroll') {\n this.videojs.autoplayOnScroll();\n }\n }\n _initContextMenu() {\n if (!this.playerOptions.hideContextMenu) {\n this.videojs.contextMenu(_config_defaults__WEBPACK_IMPORTED_MODULE_10__[\"default\"].contextMenu);\n }\n }\n _initFloatingPlayer() {\n if (this.playerOptions.floatingWhenNotVisible !== _video_player_const__WEBPACK_IMPORTED_MODULE_15__.FLOATING_TO.NONE) {\n this.videojs.floatingPlayer({\n floatTo: this.playerOptions.floatingWhenNotVisible\n });\n }\n }\n _setCssClasses() {\n this.videojs.addClass(_utils__WEBPACK_IMPORTED_MODULE_9__[\"default\"].CLASS_PREFIX);\n this.videojs.addClass(_utils__WEBPACK_IMPORTED_MODULE_9__[\"default\"].playerClassPrefix(this.videojs));\n _utils__WEBPACK_IMPORTED_MODULE_9__[\"default\"].setSkinClassPrefix(this.videojs, _utils__WEBPACK_IMPORTED_MODULE_9__[\"default\"].skinClassPrefix(this.videojs));\n }\n _onReady() {\n this._setExtendedEvents();\n\n // Load first video (mainly to support video tag 'source' and 'public-id' attributes)\n // Source parameters are set to playerOptions.sourceOptions\n const source = this.playerOptions.sourceOptions.source || this.playerOptions.sourceOptions.publicId;\n if (source) {\n const sourceOptions = Object.assign({}, this.playerOptions.sourceOptions);\n this.source(source, sourceOptions);\n }\n }\n _onSourceChange(e, _ref7) {\n let {\n source,\n sourceOptions\n } = _ref7;\n this._sendInternalAnalytics({\n ...(sourceOptions && {\n sourceOptions\n })\n });\n this.isLiveStream = source?.resourceConfig()?.type === 'live';\n }\n _setExtendedEvents() {\n const events = [];\n if (this.playerOptions.playedEventPercents) {\n events.push({\n type: _utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.PERCENTS_PLAYED,\n percents: this.playerOptions.playedEventPercents\n });\n }\n if (this.playerOptions.playedEventTimes) {\n events.push({\n type: _utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.TIME_PLAYED,\n times: this.playerOptions.playedEventTimes\n });\n }\n events.push(...[_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.SEEK, _utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.MUTE, _utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.UNMUTE, _utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.QUALITY_CHANGED]);\n const extendedEvents = new _extended_events__WEBPACK_IMPORTED_MODULE_12__[\"default\"](this.videojs, {\n events\n });\n Object.keys(extendedEvents.events).forEach(_event => {\n const handler = (event, data) => {\n this.videojs.trigger({\n type: _event,\n eventData: data\n });\n };\n extendedEvents.on(_event, handler);\n });\n }\n cloudinaryConfig(config) {\n return this.videojs.cloudinary.cloudinaryConfig(config);\n }\n currentPublicId() {\n return this.videojs.cloudinary.currentPublicId();\n }\n currentSourceUrl() {\n return this.videojs.currentSource().src;\n }\n currentPoster() {\n return this.videojs.cloudinary.currentPoster();\n }\n source(publicId) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n ({\n publicId,\n options\n } = (0,_plugins_cloudinary_common__WEBPACK_IMPORTED_MODULE_19__.normalizeOptions)(publicId, options));\n if (!this._isPlayerConfigValid) {\n return;\n }\n if (this.playerOptions.debug) {\n options.debug = true;\n (0,_validators_validators_functions__WEBPACK_IMPORTED_MODULE_16__.isValidSourceConfig)(options).then(valid => {\n if (!valid) {\n this.videojs.error('invalid source configuration');\n }\n });\n }\n if (publicId instanceof _plugins_cloudinary_models_video_source_video_source__WEBPACK_IMPORTED_MODULE_13__[\"default\"]) {\n return this.videojs.cloudinary.source(publicId, options);\n }\n\n // Inherit source parameters from player options (source options take precedence)\n const inherited = this.playerOptions.sourceOptions || {};\n options = {\n ...inherited,\n ...options\n };\n if (options.shoppable && this.videojs.shoppable) {\n this.videojs.shoppable(this.videojs, options);\n }\n this._resetReloadVideo();\n this._resetReTryVideoState();\n const maxTries = this.videojs.options_.maxTries || 3;\n const videoReadyTimeout = this.videojs.options_.videoTimeout || 55000;\n this.reTryVideoStateUntilAvailable(maxTries, videoReadyTimeout);\n return this.videojs.cloudinary.source(publicId, options);\n }\n posterOptions(options) {\n return this.videojs.cloudinary.posterOptions(options);\n }\n skin(name) {\n if (name !== undefined && lodash_isString__WEBPACK_IMPORTED_MODULE_6___default()(name)) {\n _utils__WEBPACK_IMPORTED_MODULE_9__[\"default\"].setSkinClassPrefix(this.videojs, name);\n }\n return _utils__WEBPACK_IMPORTED_MODULE_9__[\"default\"].skinClassPrefix(this.videojs);\n }\n playlist(sources) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n this.playerOptions.playlistWidget = {\n ...(this.playerOptions.playlistWidget || {\n show: false\n }),\n playlist: true\n };\n options = Object.assign({}, options, {\n playlistWidget: this.playerOptions.playlistWidget\n });\n this.videojs.one(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.READY, async () => {\n const playlistPlugin = await this.videojs.playlist(options);\n playlistPlugin(sources, options);\n });\n return this.videojs.cloudinary.playlist ? this.videojs.cloudinary.playlist(sources, options) : this;\n }\n playlistByTag(tag) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n this.playerOptions.playlistWidget = {\n ...(this.playerOptions.playlistWidget || {\n show: false\n }),\n playlistByTag: true\n };\n options = Object.assign({}, options, {\n playlistWidget: this.playerOptions.playlistWidget\n });\n return new Promise(resolve => {\n this.videojs.one(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.READY, async () => {\n const playlistPlugin = await this.videojs.playlist(options);\n playlistPlugin(await this.sourcesByTag(tag, options), options);\n resolve(this);\n });\n });\n }\n sourcesByTag(tag) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n return this.videojs.cloudinary.sourcesByTag(tag, options);\n }\n fluid(bool) {\n if (bool === undefined) {\n return this.videojs.fluid();\n }\n if (bool) {\n this.videojs.addClass(_video_player_const__WEBPACK_IMPORTED_MODULE_15__.FLUID_CLASS_NAME);\n } else {\n this.videojs.removeClass(_video_player_const__WEBPACK_IMPORTED_MODULE_15__.FLUID_CLASS_NAME);\n }\n this.videojs.fluid(bool);\n this.videojs.trigger(_utils_consts__WEBPACK_IMPORTED_MODULE_17__.PLAYER_EVENT.FLUID, bool);\n return this;\n }\n play() {\n this.playWasCalled = true;\n this.videojs.play();\n return this;\n }\n stop() {\n this.pause();\n this.currentTime(0);\n return this;\n }\n playPrevious() {\n this.playlist().playPrevious();\n return this;\n }\n playNext() {\n this.playlist().playNext();\n return this;\n }\n transformation(trans) {\n return this.videojs.cloudinary.transformation(trans);\n }\n sourceTypes(types) {\n return this.videojs.cloudinary.sourceTypes(types);\n }\n sourceTransformation(trans) {\n return this.videojs.cloudinary.sourceTransformation(trans);\n }\n autoShowRecommendations(autoShow) {\n return this.videojs.cloudinary.autoShowRecommendations(autoShow);\n }\n duration() {\n return this.videojs.duration();\n }\n height(dimension) {\n if (!dimension) {\n return this.videojs.height();\n }\n this.videojs.height(dimension);\n return this;\n }\n width(dimension) {\n if (!dimension) {\n return this.videojs.width();\n }\n this.videojs.width(dimension);\n return this;\n }\n volume(volume) {\n if (!volume) {\n return this.videojs.volume();\n }\n this.videojs.volume(volume);\n return this;\n }\n mute() {\n if (!this.isMuted()) {\n this.videojs.muted(true);\n }\n return this;\n }\n unmute() {\n if (this.isMuted()) {\n this.videojs.muted(false);\n }\n return this;\n }\n isMuted() {\n return this.videojs.muted();\n }\n pause() {\n this.videojs.pause();\n return this;\n }\n currentTime(offsetSeconds) {\n if (!offsetSeconds && offsetSeconds !== 0) {\n return this.videojs.currentTime();\n }\n this.videojs.currentTime(offsetSeconds);\n return this;\n }\n maximize() {\n if (!this.isMaximized()) {\n this.videojs.requestFullscreen();\n }\n return this;\n }\n exitMaximize() {\n if (this.isMaximized()) {\n this.videojs.exitFullscreen();\n }\n return this;\n }\n isMaximized() {\n return this.videojs.isFullscreen();\n }\n dispose() {\n this.videojs.dispose();\n }\n controls(bool) {\n if (bool === undefined) {\n return this.videojs.controls();\n }\n this.videojs.controls(bool);\n return this;\n }\n ima() {\n return {\n playAd: this.videojs.ima.playAd\n };\n }\n loop(bool) {\n if (bool === undefined) {\n return this.videojs.loop();\n }\n this.videojs.loop(bool);\n return this;\n }\n el() {\n return this.videojs.el();\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (VideoPlayer);\n\n//# sourceURL=webpack://cloudinary-video-player/./video-player.js?");
/***/ }),
/***/ "./video-player.utils.js":
/*!*******************************!*\
!*** ./video-player.utils.js ***!
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ addMetadataTrack: () => (/* binding */ addMetadataTrack),\n/* harmony export */ extractOptions: () => (/* binding */ extractOptions),\n/* harmony export */ getResolveVideoElement: () => (/* binding */ getResolveVideoElement),\n/* harmony export */ isLight: () => (/* binding */ isLight),\n/* harmony export */ normalizeAutoplay: () => (/* binding */ normalizeAutoplay),\n/* harmony export */ overrideDefaultVideojsComponents: () => (/* binding */ overrideDefaultVideojsComponents)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils */ \"./utils/index.js\");\n/* harmony import */ var _config_defaults__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./config/defaults */ \"./config/defaults.js\");\n/* harmony import */ var _video_player_const__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./video-player.const */ \"./video-player.const.js\");\n/* harmony import */ var lodash_isString__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! lodash/isString */ \"../node_modules/lodash/isString.js\");\n/* harmony import */ var lodash_isString__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(lodash_isString__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var css_escape__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! css.escape */ \"../node_modules/css.escape/css.escape.js\");\n/* harmony import */ var css_escape__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(css_escape__WEBPACK_IMPORTED_MODULE_5__);\n\n\n\n\n\n\n/*\n* Used to escape element identifiers that begin with certain\n* characters such as digits.\n* https://www.w3.org/International/questions/qa-escapes#css_identifiers\n*/\n\nconst addMetadataTrack = (videoJs, vttSource) => {\n return videoJs.addRemoteTextTrack({\n kind: 'metadata',\n srclang: 'en',\n src: vttSource,\n default: true\n }, true).track;\n};\nconst isLight = opts => {\n return opts.class.indexOf('cld-video-player-skin-light') > -1 || opts.skin === 'light';\n};\nconst getResolveVideoElement = elem => {\n if (lodash_isString__WEBPACK_IMPORTED_MODULE_4___default()(elem)) {\n let id = elem;\n\n // Adjust for jQuery ID syntax\n if (id.indexOf('#') === 0) {\n id = id.slice(1);\n }\n try {\n elem = document.querySelector(`#${css_escape__WEBPACK_IMPORTED_MODULE_5___default()(id)}`) || video_js__WEBPACK_IMPORTED_MODULE_0___default().getPlayer(id);\n } catch (err) {\n // eslint-disable-line no-unused-vars\n elem = null;\n }\n if (!elem) {\n throw new Error(`Could not find element with id ${id}`);\n }\n }\n if (!elem.tagName) {\n throw new Error('Must specify either an element or an element id.');\n } else if (elem.tagName !== 'VIDEO') {\n throw new Error('Element is not a video tag.');\n }\n return elem;\n};\nconst normalizeAutoplay = options => {\n const autoplayMode = options.autoplayMode;\n if (autoplayMode) {\n switch (autoplayMode) {\n case _video_player_const__WEBPACK_IMPORTED_MODULE_3__.AUTO_PLAY_MODE.ALWAYS:\n options.autoplay = true;\n break;\n case _video_player_const__WEBPACK_IMPORTED_MODULE_3__.AUTO_PLAY_MODE.ON_SCROLL:\n case _video_player_const__WEBPACK_IMPORTED_MODULE_3__.AUTO_PLAY_MODE.NEVER:\n default:\n options.autoplay = false;\n }\n }\n};\nconst extractOptions = (elem, options) => {\n const elemOptions = _utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].normalizeAttributes(elem);\n if (video_js__WEBPACK_IMPORTED_MODULE_0___default().dom.hasClass(elem, _video_player_const__WEBPACK_IMPORTED_MODULE_3__.FLUID_CLASS_NAME) || video_js__WEBPACK_IMPORTED_MODULE_0___default().dom.hasClass(elem, 'vjs-fluid')) {\n options.fluid = true;\n }\n // Default options < Markup options < Player options\n options = video_js__WEBPACK_IMPORTED_MODULE_0___default().obj.merge({}, _config_defaults__WEBPACK_IMPORTED_MODULE_2__[\"default\"], elemOptions, options);\n\n // In case of 'autoplay on scroll', we need to make sure normal HTML5 autoplay is off\n normalizeAutoplay(options);\n\n // VideoPlayer specific options\n const playerOptions = _utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].sliceAndUnsetProperties(options, ..._video_player_const__WEBPACK_IMPORTED_MODULE_3__.PLAYER_PARAMS);\n\n // Cloudinary SDK config (cloud_name, secure, etc.)\n playerOptions.cloudinary = _utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].sliceAndUnsetProperties(playerOptions, ..._video_player_const__WEBPACK_IMPORTED_MODULE_3__.CLOUDINARY_CONFIG_PARAM);\n\n // Merge with cloudinaryConfig from src/index.js (e.g., secureDistribution -> secure_distribution)\n if (playerOptions.cloudinaryConfig) {\n Object.assign(playerOptions.cloudinary, playerOptions.cloudinaryConfig);\n delete playerOptions.cloudinaryConfig;\n }\n\n // Source-level config (visualSearch, chapters, etc.)\n playerOptions.sourceOptions = _utils__WEBPACK_IMPORTED_MODULE_1__[\"default\"].sliceAndUnsetProperties(playerOptions, ..._video_player_const__WEBPACK_IMPORTED_MODULE_3__.SOURCE_PARAMS);\n\n // Allow explicitly passing options to videojs using the `videojs` namespace, in order\n // to avoid param name conflicts:\n // VideoPlayer.new({ controls: true, videojs: { controls: false })\n if (options.videojs) {\n Object.assign(options, options.videojs);\n delete options.videojs;\n }\n return {\n playerOptions,\n videojsOptions: options\n };\n};\nconst overrideDefaultVideojsComponents = () => {\n const Player = video_js__WEBPACK_IMPORTED_MODULE_0___default().getComponent('Player');\n let children = Player.prototype.options_.children;\n if (children.indexOf('titleBar') === -1) {\n children.push('titleBar');\n }\n const ControlBar = video_js__WEBPACK_IMPORTED_MODULE_0___default().getComponent('ControlBar');\n if (ControlBar) {\n children = ControlBar.prototype.options_.children;\n // Add space instead of the progress control (which we detached from the controlBar, and absolutely positioned it above it)\n // Also add a blank div underneath the progress control to stop bubbling up pointer events.\n children.splice(children.indexOf('progressControl'), 0, 'spacer', 'progressControlEventsBlocker');\n\n // Add skip buttons around the 'play-toggle'\n children.splice(children.indexOf('playToggle'), 1, 'playToggle', 'JumpBackButton', 'JumpForwardButton');\n\n // Position the 'logo-button' button last\n children.push('logoButton');\n\n // Remove these button\n children.splice(children.indexOf('skipForward'), 1);\n children.splice(children.indexOf('skipBackward'), 1);\n }\n};\n\n//# sourceURL=webpack://cloudinary-video-player/./video-player.utils.js?");
/***/ }),
/***/ "../node_modules/cloudinary-video-analytics/dist/main.js":
/*!***************************************************************!*\
!*** ../node_modules/cloudinary-video-analytics/dist/main.js ***!
\***************************************************************/
/***/ ((module) => {
eval("!function(e,t){if(true)module.exports=t();else { var r, n; }}(self,(()=>(()=>{\"use strict\";var e={805:e=>{e.exports=o,e.exports.isMobile=o,e.exports.default=o;const t=/(android|bb\\d+|meego).+mobile|armv7l|avantgo|bada\\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\\/|plucker|pocket|psp|series[46]0|samsungbrowser.*mobile|symbian|treo|up\\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i,n=/CrOS/,r=/android|ipad|playbook|silk/i;function o(e){e||(e={});let o=e.ua;if(o||\"undefined\"==typeof navigator||(o=navigator.userAgent),o&&o.headers&&\"string\"==typeof o.headers[\"user-agent\"]&&(o=o.headers[\"user-agent\"]),\"string\"!=typeof o)return!1;let i=t.test(o)&&!n.test(o)||!!e.tablet&&r.test(o);return!i&&e.tablet&&e.featureDetect&&navigator&&navigator.maxTouchPoints>1&&-1!==o.indexOf(\"Macintosh\")&&-1!==o.indexOf(\"Safari\")&&(i=!0),i}}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var i=t[r]={exports:{}};return e[r](i,i.exports,n),i.exports}n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})};var r={};return(()=>{n.r(r),n.d(r,{connectCloudinaryAnalytics:()=>W});var e=n(805),t=\"play\",o=\"pause\",i=\"loadMetadata\",a=\"viewStart\",u=\"viewEnd\";function l(e){return l=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},l(e)}var c=function(e){var t=\"function\"==typeof e?e():e;if(\"object\"===l(t)&&null!==t&&!Array.isArray(t)){var n=function(e){return Array.from({length:5}).reduce((function(t,n,r){var o=\"customData\".concat(r+1);return\"string\"==typeof e[o]&&(t[o]=e[o]),t}),{})}(t);return Object.keys(n).length>0?n:null}return null},d=function(e){return null!==e&&\"object\"===l(e)&&\"string\"==typeof e.cloudName&&e.cloudName&&\"string\"==typeof e.publicId&&e.publicId?{cloudName:e.cloudName,publicId:e.publicId}:null},s=/^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$/,f=\"native\",y=[f,\"cloudinary video player\"],p=function(e){return y.includes(e)?e:f},v=function(e){return\"string\"==typeof e&&s.test(e)?e:null};function m(e){return m=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},m(e)}function g(e){return function(e){if(Array.isArray(e))return b(e)}(e)||function(e){if(\"undefined\"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e[\"@@iterator\"])return Array.from(e)}(e)||function(e,t){if(e){if(\"string\"==typeof e)return b(e,t);var n={}.toString.call(e).slice(8,-1);return\"Object\"===n&&e.constructor&&(n=e.constructor.name),\"Map\"===n||\"Set\"===n?Array.from(e):\"Arguments\"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?b(e,t):void 0}}(e)||function(){throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\")}()}function b(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}function h(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function w(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?h(Object(n),!0).forEach((function(t){S(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):h(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function S(e,t,n){return(t=function(e){var t=function(e,t){if(\"object\"!=m(e)||!e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||\"default\");if(\"object\"!=m(r))return r;throw new TypeError(\"@@toPrimitive must return a primitive value.\")}return(\"string\"===t?String:Number)(e)}(e,\"string\");return\"symbol\"==m(t)?t:t+\"\"}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var E=function(e,t){var n=c(null==t?void 0:t.customData),r=function(e){return null!==e&&JSON.stringify(e).length<=1e3}(n),o=null!=t&&t.customVideoUrlFallback?function(e,t){try{var n=t(e);return{cloudName:n.cloudName,publicId:n.publicId}}catch(e){return null}}(e.videoUrl,t.customVideoUrlFallback):null,i=d(o);return P(a,w(w({},e),{},{analyticsModuleVersion:\"1.8.2\",videoPlayer:{type:p(null==t?void 0:t.videoPlayerType),version:v(null==t?void 0:t.videoPlayerVersion)},customerData:w(w({},r?{providedData:n}:{}),i?{videoData:i}:{})}))},V=function(){return P(u,w({},arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}))},P=function(e,t){return{eventName:e,eventTime:Date.now(),eventDetails:t}},I=function(e){var t=g(e);return JSON.stringify(t)};function j(e){return function(e){if(Array.isArray(e))return A(e)}(e)||function(e){if(\"undefined\"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e[\"@@iterator\"])return Array.from(e)}(e)||function(e,t){if(e){if(\"string\"==typeof e)return A(e,t);var n={}.toString.call(e).slice(8,-1);return\"Object\"===n&&e.constructor&&(n=e.constructor.name),\"Map\"===n||\"Set\"===n?Array.from(e):\"Arguments\"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?A(e,t):void 0}}(e)||function(){throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\")}()}function A(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}var O=function(e){var n={},r={};return function(){var a=null,u=[],l=function(e,t){if(!a)throw new Error(\"Events collector session not started\");r[a].push(P(e,t))};return{flushEvents:function(){var e;if(!a)throw new Error(\"Events collector session not started\");var t=r[a].splice(0,r[a].length);return(e=n[a]).splice.apply(e,[n[a].length,0].concat(j(t))),t},getCollectedEventsCount:function(){var e;return a&&(null===(e=r[a])||void 0===e?void 0:e.length)||0},addEvent:function(e){var t=e.eventName,n=e.eventDetails;return l(t,n)},start:function(c){if(a)throw new Error(\"Events collector session already started\");n[a=c]=[],r[a]=[],u.push(function(e,n){var r=e.onPlay((function(){n(t,{})}));return function(){r()}}(e,l),function(e,t){var n=e.onPause((function(){t(o,{})})),r=e.onEmptied((function(){t(o,{})}));return function(){n(),r()}}(e,l),function(e,t){var n=function(){var n,r;t(i,{videoDuration:(n=e.getDuration(),r=Number.isNaN(n)?null:n,Number.POSITIVE_INFINITY===r?\"Infinity\":r),videoUrl:e.getCurrentSrc()})},r=e.onLoadedMetadata((function(){return n()}));return e.getReadyState()>0&&setTimeout((function(){return n()}),0),function(){r()}}(e,l))},destroy:function(){if(!a)throw new Error(\"Events collector session not started\");u.forEach((function(e){return e()})),a=null}}}};const k={randomUUID:\"undefined\"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};let C;const D=new Uint8Array(16);function M(){if(!C&&(C=\"undefined\"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!C))throw new Error(\"crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported\");return C(D)}const T=[];for(let e=0;e<256;++e)T.push((e+256).toString(16).slice(1));function U(e,t=0){return(T[e[t+0]]+T[e[t+1]]+T[e[t+2]]+T[e[t+3]]+\"-\"+T[e[t+4]]+T[e[t+5]]+\"-\"+T[e[t+6]]+T[e[t+7]]+\"-\"+T[e[t+8]]+T[e[t+9]]+\"-\"+T[e[t+10]]+T[e[t+11]]+T[e[t+12]]+T[e[t+13]]+T[e[t+14]]+T[e[t+15]]).toLowerCase()}const N=function(e,t,n){if(k.randomUUID&&!t&&!e)return k.randomUUID();const r=(e=e||{}).random||(e.rng||M)();if(r[6]=15&r[6]|64,r[8]=63&r[8]|128,t){n=n||0;for(let e=0;e<16;++e)t[n+e]=r[e];return t}return U(r)};var x=\"cld-analytics-user-id\",L=function(){return N().replace(/-/g,\"\")},_=function(e,t){var n=Object.keys(t).reduce((function(e,n){return e.append(n,t[n]),e}),new FormData);return\"function\"!=typeof window.navigator.sendBeacon?window.fetch(e,{method:\"POST\",mode:\"no-cors\",body:n,keepalive:!0}):window.navigator.sendBeacon(e,n)};function z(e){return z=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},z(e)}var F=function(e,t){if(!e.isValid)throw t?\"\".concat(t,\":\")+\"\\n\\n\"+e.errorMessage:e.errorMessage},R=function(e){return e&&\"object\"!==z(e)?{isValid:!1,errorMessage:\"Options property must be an object\"}:{isValid:!0}},Z=function(e,t,n){return e.addEventListener(t,n),function(){e.removeEventListener(t,n)}},Y=function(e,t){return t?$(e):B(e)},$=function(e){var t=e.onPageViewStart,n=e.onPageViewEnd,r=function(){\"visible\"===document.visibilityState?null==t||t():\"hidden\"===document.visibilityState&&(null==n||n())};return document.addEventListener(\"visibilitychange\",r),\"visible\"===document.visibilityState&&(null==t||t()),function(){document.removeEventListener(\"visibilitychange\",r)}},B=function(e){var t=e.onPageViewStart,n=e.onPageViewEnd,r=function(){return null==t?void 0:t()},o=function(){return null==n?void 0:n()};return\"complete\"===document.readyState?r():window.addEventListener(\"load\",r),window.addEventListener(\"beforeunload\",o),function(){window.removeEventListener(\"load\",r),window.removeEventListener(\"beforeunload\",o)}};function H(e){return function(e){if(Array.isArray(e))return J(e)}(e)||function(e){if(\"undefined\"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e[\"@@iterator\"])return Array.from(e)}(e)||function(e,t){if(e){if(\"string\"==typeof e)return J(e,t);var n={}.toString.call(e).slice(8,-1);return\"Object\"===n&&e.constructor&&(n=e.constructor.name),\"Map\"===n||\"Set\"===n?Array.from(e):\"Arguments\"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?J(e,t):void 0}}(e)||function(){throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\")}()}function J(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}var q={default:\"https://video-analytics-api.cloudinary.com/v1/video-analytics\",liveStreams:\"https://video-analytics-api.cloudinary.com/v1/live-streams\"},W=function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};F(function(e){return e&&\"object\"!==z(e)?{isValid:!1,errorMessage:\"Options property must be an object\"}:{isValid:!0}}(n),\"Cloudinary video analytics requires proper options object\"),n.playerAdapter||(n.playerAdapter=function(e){return{onCanPlay:function(t){return Z(e,\"canplay\",t)},onCanPlayThrough:function(t){return Z(e,\"canplaythrough\",t)},onComplete:function(t){return Z(e,\"complete\",t)},onDurationChange:function(t){return Z(e,\"durationchange\",t)},onEmptied:function(t){return Z(e,\"emptied\",t)},onEnded:function(t){return Z(e,\"ended\",t)},onError:function(t){return Z(e,\"error\",t)},onLoadedData:function(t){return Z(e,\"loadeddata\",t)},onLoadedMetadata:function(t){return Z(e,\"loadedmetadata\",t)},onLoadStart:function(t){return Z(e,\"loadstart\",t)},onPause:function(t){return Z(e,\"pause\",t)},onPlay:function(t){return Z(e,\"play\",t)},onPlaying:function(t){return Z(e,\"playing\",t)},onProgress:function(t){return Z(e,\"progress\",t)},onRateChange:function(t){return Z(e,\"ratechange\",t)},onSeeked:function(t){return Z(e,\"seeked\",t)},onSeeking:function(t){return Z(e,\"seeking\",t)},onStalled:function(t){return Z(e,\"stalled\",t)},onSuspend:function(t){return Z(e,\"suspend\",t)},onTimeUpdate:function(t){return Z(e,\"timeupdate\",t)},onVolumeChange:function(t){return Z(e,\"volumechange\",t)},onWaiting:function(t){return Z(e,\"waiting\",t)},getCurrentSrc:function(){return e.currentSrc},getCurrentTime:function(){return e.currentTime},getReadyState:function(){return e.readyState},getDuration:function(){return e.duration}}}(t));var r=null,o=function(){var e=window.localStorage.getItem(x);if(e)return e;var t=N().replace(/-/g,\"\");return window.localStorage.setItem(x,t),t}(),i=n.playerAdapter,l=(0,e.isMobile)({tablet:!0,featureDetect:!0}),c=O(i),s=function(){r&&(r.clear(),r=null)},f={_value:L(),getValue:function(){return f._value},regenerateValue:function(){return f._value=L(),r&&(r.viewId=f._value),f._value}},y=function(e,t){var n=c(),a=function(){if(n.getCollectedEventsCount()>0){n.addEvent(V());var e=I(H(n.flushEvents()));t={userId:o,viewId:f.getValue(),events:e},_(q.default,t)}var t},u=Y({onPageViewStart:function(){f.regenerateValue(),n.start(f.getValue()),n.addEvent(E({videoUrl:i.getCurrentSrc(),trackingType:\"manual\"},t))},onPageViewEnd:function(){a(),n.destroy()}},l);r={viewId:f,type:\"manual\",subtype:\"default\",clear:function(){a(),n.destroy(),u()}}},m=function(e,t){var n=d(e),i=function(e){_(q.liveStreams,{userId:o,viewId:f.getValue(),events:I([e])})},c=Y({onPageViewStart:function(){var e;f.regenerateValue(),i((e=t,P(a,w(w({},{liveStreamData:n}),{},{analyticsModuleVersion:\"1.8.2\",videoPlayer:{type:p(null==e?void 0:e.videoPlayerType),version:v(null==e?void 0:e.videoPlayerVersion)}}))))},onPageViewEnd:function(){i(P(u,w({},{liveStreamData:n})))}},l);r={viewId:f.getValue(),type:\"manual\",subtype:\"live-stream\",clear:function(){c()}}};return{startManualTracking:function(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(\"auto\"===(null===(t=r)||void 0===t?void 0:t.type))throw\"Cloudinary video analytics auto tracking is already connected with this HTML Video Element, to start manual tracking you need to stop auto tracking\";F(function(e){return\"object\"!==z(e)?{isValid:!1,errorMessage:\"Metadata param needs to be an object\"}:\"string\"!=typeof e.cloudName?{isValid:!1,errorMessage:\"You need to provide proper cloud name of your Cloudinary account [cloudName: string]\"}:\"string\"==typeof e.type&&\"live\"!==e.type?{isValid:!1,errorMessage:'Property \"type\" can be either undefined or \"live\" value'}:\"string\"!=typeof e.publicId?\"live\"===e.type?{isValid:!1,errorMessage:\"You need to provide proper public ID of your Live Stream output\"}:{isValid:!1,errorMessage:\"You need to provide proper video public ID of your video on your Cloudinary cloud [videoPublicId: string]\"}:{isValid:!0}}(e),\"Cloudinary video analytics manual tracking called without necessary data\"),F(R(n),\"Cloudinary video analytics manual tracking called with invalid options\"),s(),\"live\"===e.type?m(e,n):(n.customVideoUrlFallback=n.customVideoUrlFallback||function(){return e},y(e,n))},stopManualTracking:s,startAutoTracking:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(r)throw\"Cloudinary video analytics tracking is already connected with this HTML Video Element\";F(R(e),\"Cloudinary video analytics auto tracking called with invalid options\");var t=c(),n=function(){if(t.getCollectedEventsCount()>0){t.addEvent(V());var e=I(H(t.flushEvents()));n={userId:o,viewId:f.getValue(),events:e},_(q.default,n)}var n},a=function(){var o=i.getCurrentSrc();if(o===window.location.href||!o)return null;f.regenerateValue(),t.start(f.getValue()),t.addEvent(E({videoUrl:o,trackingType:\"auto\"},e)),r={viewId:f,type:\"auto\",clear:function(){n(),t.destroy()}}};Y({onPageViewStart:function(){return a()},onPageViewEnd:function(){n(),t.destroy()}},l),i.onLoadStart((function(){return!r&&a()})),i.onEmptied((function(){return s()}))}}}})(),r})()));\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/cloudinary-video-analytics/dist/main.js?");
/***/ }),
/***/ "../node_modules/css.escape/css.escape.js":
/*!************************************************!*\
!*** ../node_modules/css.escape/css.escape.js ***!
\************************************************/
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
eval("/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */\n;(function(root, factory) {\n\t// https://github.com/umdjs/umd/blob/master/returnExports.js\n\tif (true) {\n\t\t// For Node.js.\n\t\tmodule.exports = factory(root);\n\t} else {}\n}(typeof __webpack_require__.g != 'undefined' ? __webpack_require__.g : this, function(root) {\n\n\tif (root.CSS && root.CSS.escape) {\n\t\treturn root.CSS.escape;\n\t}\n\n\t// https://drafts.csswg.org/cssom/#serialize-an-identifier\n\tvar cssEscape = function(value) {\n\t\tif (arguments.length == 0) {\n\t\t\tthrow new TypeError('`CSS.escape` requires an argument.');\n\t\t}\n\t\tvar string = String(value);\n\t\tvar length = string.length;\n\t\tvar index = -1;\n\t\tvar codeUnit;\n\t\tvar result = '';\n\t\tvar firstCodeUnit = string.charCodeAt(0);\n\t\twhile (++index < length) {\n\t\t\tcodeUnit = string.charCodeAt(index);\n\t\t\t// Note: there’s no need to special-case astral symbols, surrogate\n\t\t\t// pairs, or lone surrogates.\n\n\t\t\t// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER\n\t\t\t// (U+FFFD).\n\t\t\tif (codeUnit == 0x0000) {\n\t\t\t\tresult += '\\uFFFD';\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t// If the character is in the range [\\1-\\1F] (U+0001 to U+001F) or is\n\t\t\t\t// U+007F, […]\n\t\t\t\t(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||\n\t\t\t\t// If the character is the first character and is in the range [0-9]\n\t\t\t\t// (U+0030 to U+0039), […]\n\t\t\t\t(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||\n\t\t\t\t// If the character is the second character and is in the range [0-9]\n\t\t\t\t// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]\n\t\t\t\t(\n\t\t\t\t\tindex == 1 &&\n\t\t\t\t\tcodeUnit >= 0x0030 && codeUnit <= 0x0039 &&\n\t\t\t\t\tfirstCodeUnit == 0x002D\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\t// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point\n\t\t\t\tresult += '\\\\' + codeUnit.toString(16) + ' ';\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t// If the character is the first character and is a `-` (U+002D), and\n\t\t\t\t// there is no second character, […]\n\t\t\t\tindex == 0 &&\n\t\t\t\tlength == 1 &&\n\t\t\t\tcodeUnit == 0x002D\n\t\t\t) {\n\t\t\t\tresult += '\\\\' + string.charAt(index);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If the character is not handled by one of the above rules and is\n\t\t\t// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or\n\t\t\t// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to\n\t\t\t// U+005A), or [a-z] (U+0061 to U+007A), […]\n\t\t\tif (\n\t\t\t\tcodeUnit >= 0x0080 ||\n\t\t\t\tcodeUnit == 0x002D ||\n\t\t\t\tcodeUnit == 0x005F ||\n\t\t\t\tcodeUnit >= 0x0030 && codeUnit <= 0x0039 ||\n\t\t\t\tcodeUnit >= 0x0041 && codeUnit <= 0x005A ||\n\t\t\t\tcodeUnit >= 0x0061 && codeUnit <= 0x007A\n\t\t\t) {\n\t\t\t\t// the character itself\n\t\t\t\tresult += string.charAt(index);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Otherwise, the escaped character.\n\t\t\t// https://drafts.csswg.org/cssom/#escape-a-character\n\t\t\tresult += '\\\\' + string.charAt(index);\n\n\t\t}\n\t\treturn result;\n\t};\n\n\tif (!root.CSS) {\n\t\troot.CSS = {};\n\t}\n\n\troot.CSS.escape = cssEscape;\n\treturn cssEscape;\n\n}));\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/css.escape/css.escape.js?");
/***/ }),
/***/ "../node_modules/events/events.js":
/*!****************************************!*\
!*** ../node_modules/events/events.js ***!
\****************************************/
/***/ ((module) => {
"use strict";
eval("// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\nvar R = typeof Reflect === 'object' ? Reflect : null\nvar ReflectApply = R && typeof R.apply === 'function'\n ? R.apply\n : function ReflectApply(target, receiver, args) {\n return Function.prototype.apply.call(target, receiver, args);\n }\n\nvar ReflectOwnKeys\nif (R && typeof R.ownKeys === 'function') {\n ReflectOwnKeys = R.ownKeys\n} else if (Object.getOwnPropertySymbols) {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target)\n .concat(Object.getOwnPropertySymbols(target));\n };\n} else {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target);\n };\n}\n\nfunction ProcessEmitWarning(warning) {\n if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n return value !== value;\n}\n\nfunction EventEmitter() {\n EventEmitter.init.call(this);\n}\nmodule.exports = EventEmitter;\nmodule.exports.once = once;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nfunction checkListener(listener) {\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n}\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n enumerable: true,\n get: function() {\n return defaultMaxListeners;\n },\n set: function(arg) {\n if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n }\n defaultMaxListeners = arg;\n }\n});\n\nEventEmitter.init = function() {\n\n if (this._events === undefined ||\n this._events === Object.getPrototypeOf(this)._events) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n }\n\n this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n }\n this._maxListeners = n;\n return this;\n};\n\nfunction _getMaxListeners(that) {\n if (that._maxListeners === undefined)\n return EventEmitter.defaultMaxListeners;\n return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n return _getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n var args = [];\n for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n var doError = (type === 'error');\n\n var events = this._events;\n if (events !== undefined)\n doError = (doError && events.error === undefined);\n else if (!doError)\n return false;\n\n // If there is no 'error' event listener then throw.\n if (doError) {\n var er;\n if (args.length > 0)\n er = args[0];\n if (er instanceof Error) {\n // Note: The comments on the `throw` lines are intentional, they show\n // up in Node's output if this results in an unhandled exception.\n throw er; // Unhandled 'error' event\n }\n // At least give some kind of context to the user\n var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n err.context = er;\n throw err; // Unhandled 'error' event\n }\n\n var handler = events[type];\n\n if (handler === undefined)\n return false;\n\n if (typeof handler === 'function') {\n ReflectApply(handler, this, args);\n } else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n ReflectApply(listeners[i], this, args);\n }\n\n return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n var m;\n var events;\n var existing;\n\n checkListener(listener);\n\n events = target._events;\n if (events === undefined) {\n events = target._events = Object.create(null);\n target._eventsCount = 0;\n } else {\n // To avoid recursion in the case that type === \"newListener\"! Before\n // adding it to the listeners, first emit \"newListener\".\n if (events.newListener !== undefined) {\n target.emit('newListener', type,\n listener.listener ? listener.listener : listener);\n\n // Re-assign `events` because a newListener handler could have caused the\n // this._events to be assigned to a new object\n events = target._events;\n }\n existing = events[type];\n }\n\n if (existing === undefined) {\n // Optimize the case of one listener. Don't need the extra array object.\n existing = events[type] = listener;\n ++target._eventsCount;\n } else {\n if (typeof existing === 'function') {\n // Adding the second element, need to change to array.\n existing = events[type] =\n prepend ? [listener, existing] : [existing, listener];\n // If we've already got an array, just append.\n } else if (prepend) {\n existing.unshift(listener);\n } else {\n existing.push(listener);\n }\n\n // Check for listener leak\n m = _getMaxListeners(target);\n if (m > 0 && existing.length > m && !existing.warned) {\n existing.warned = true;\n // No error code for this since it is a Warning\n // eslint-disable-next-line no-restricted-syntax\n var w = new Error('Possible EventEmitter memory leak detected. ' +\n existing.length + ' ' + String(type) + ' listeners ' +\n 'added. Use emitter.setMaxListeners() to ' +\n 'increase limit');\n w.name = 'MaxListenersExceededWarning';\n w.emitter = target;\n w.type = type;\n w.count = existing.length;\n ProcessEmitWarning(w);\n }\n }\n\n return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n function prependListener(type, listener) {\n return _addListener(this, type, listener, true);\n };\n\nfunction onceWrapper() {\n if (!this.fired) {\n this.target.removeListener(this.type, this.wrapFn);\n this.fired = true;\n if (arguments.length === 0)\n return this.listener.call(this.target);\n return this.listener.apply(this.target, arguments);\n }\n}\n\nfunction _onceWrap(target, type, listener) {\n var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n var wrapped = onceWrapper.bind(state);\n wrapped.listener = listener;\n state.wrapFn = wrapped;\n return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n checkListener(listener);\n this.on(type, _onceWrap(this, type, listener));\n return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n function prependOnceListener(type, listener) {\n checkListener(listener);\n this.prependListener(type, _onceWrap(this, type, listener));\n return this;\n };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n function removeListener(type, listener) {\n var list, events, position, i, originalListener;\n\n checkListener(listener);\n\n events = this._events;\n if (events === undefined)\n return this;\n\n list = events[type];\n if (list === undefined)\n return this;\n\n if (list === listener || list.listener === listener) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else {\n delete events[type];\n if (events.removeListener)\n this.emit('removeListener', type, list.listener || listener);\n }\n } else if (typeof list !== 'function') {\n position = -1;\n\n for (i = list.length - 1; i >= 0; i--) {\n if (list[i] === listener || list[i].listener === listener) {\n originalListener = list[i].listener;\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (position === 0)\n list.shift();\n else {\n spliceOne(list, position);\n }\n\n if (list.length === 1)\n events[type] = list[0];\n\n if (events.removeListener !== undefined)\n this.emit('removeListener', type, originalListener || listener);\n }\n\n return this;\n };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n function removeAllListeners(type) {\n var listeners, events, i;\n\n events = this._events;\n if (events === undefined)\n return this;\n\n // not listening for removeListener, no need to emit\n if (events.removeListener === undefined) {\n if (arguments.length === 0) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n } else if (events[type] !== undefined) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else\n delete events[type];\n }\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n var keys = Object.keys(events);\n var key;\n for (i = 0; i < keys.length; ++i) {\n key = keys[i];\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = Object.create(null);\n this._eventsCount = 0;\n return this;\n }\n\n listeners = events[type];\n\n if (typeof listeners === 'function') {\n this.removeListener(type, listeners);\n } else if (listeners !== undefined) {\n // LIFO order\n for (i = listeners.length - 1; i >= 0; i--) {\n this.removeListener(type, listeners[i]);\n }\n }\n\n return this;\n };\n\nfunction _listeners(target, type, unwrap) {\n var events = target._events;\n\n if (events === undefined)\n return [];\n\n var evlistener = events[type];\n if (evlistener === undefined)\n return [];\n\n if (typeof evlistener === 'function')\n return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n return unwrap ?\n unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n if (typeof emitter.listenerCount === 'function') {\n return emitter.listenerCount(type);\n } else {\n return listenerCount.call(emitter, type);\n }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n var events = this._events;\n\n if (events !== undefined) {\n var evlistener = events[type];\n\n if (typeof evlistener === 'function') {\n return 1;\n } else if (evlistener !== undefined) {\n return evlistener.length;\n }\n }\n\n return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n var copy = new Array(n);\n for (var i = 0; i < n; ++i)\n copy[i] = arr[i];\n return copy;\n}\n\nfunction spliceOne(list, index) {\n for (; index + 1 < list.length; index++)\n list[index] = list[index + 1];\n list.pop();\n}\n\nfunction unwrapListeners(arr) {\n var ret = new Array(arr.length);\n for (var i = 0; i < ret.length; ++i) {\n ret[i] = arr[i].listener || arr[i];\n }\n return ret;\n}\n\nfunction once(emitter, name) {\n return new Promise(function (resolve, reject) {\n function errorListener(err) {\n emitter.removeListener(name, resolver);\n reject(err);\n }\n\n function resolver() {\n if (typeof emitter.removeListener === 'function') {\n emitter.removeListener('error', errorListener);\n }\n resolve([].slice.call(arguments));\n };\n\n eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });\n if (name !== 'error') {\n addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });\n }\n });\n}\n\nfunction addErrorHandlerIfEventEmitter(emitter, handler, flags) {\n if (typeof emitter.on === 'function') {\n eventTargetAgnosticAddListener(emitter, 'error', handler, flags);\n }\n}\n\nfunction eventTargetAgnosticAddListener(emitter, name, listener, flags) {\n if (typeof emitter.on === 'function') {\n if (flags.once) {\n emitter.once(name, listener);\n } else {\n emitter.on(name, listener);\n }\n } else if (typeof emitter.addEventListener === 'function') {\n // EventTarget does not have `error` event semantics like Node\n // EventEmitters, we do not listen for `error` events here.\n emitter.addEventListener(name, function wrapListener(arg) {\n // IE does not have builtin `{ once: true }` support so we\n // have to do it manually.\n if (flags.once) {\n emitter.removeEventListener(name, wrapListener);\n }\n listener(arg);\n });\n } else {\n throw new TypeError('The \"emitter\" argument must be of type EventEmitter. Received type ' + typeof emitter);\n }\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/events/events.js?");
/***/ }),
/***/ "../node_modules/video.js/dist/alt/video.core-exposed.js":
/*!***************************************************************!*\
!*** ../node_modules/video.js/dist/alt/video.core-exposed.js ***!
\***************************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var ___EXPOSE_LOADER_IMPORT___ = __webpack_require__(/*! -!./video.core.js */ \"../node_modules/video.js/dist/alt/video.core.js\");\nvar ___EXPOSE_LOADER_GET_GLOBAL_THIS___ = __webpack_require__(/*! ../../../expose-loader/dist/runtime/getGlobalThis.js */ \"../node_modules/expose-loader/dist/runtime/getGlobalThis.js\");\nvar ___EXPOSE_LOADER_GLOBAL_THIS___ = ___EXPOSE_LOADER_GET_GLOBAL_THIS___;\n___EXPOSE_LOADER_GLOBAL_THIS___[\"videojs\"] = ___EXPOSE_LOADER_IMPORT___;\nmodule.exports = ___EXPOSE_LOADER_IMPORT___;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/video.js/dist/alt/video.core-exposed.js?");
/***/ }),
/***/ "../node_modules/expose-loader/dist/runtime/getGlobalThis.js":
/*!*******************************************************************!*\
!*** ../node_modules/expose-loader/dist/runtime/getGlobalThis.js ***!
\*******************************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
eval("\n\n// eslint-disable-next-line func-names\nmodule.exports = function () {\n if (typeof globalThis === \"object\") {\n return globalThis;\n }\n var g;\n try {\n // This works if eval is allowed (see CSP)\n // eslint-disable-next-line no-new-func\n g = this || new Function(\"return this\")();\n } catch (e) {\n // This works if the window reference is available\n if (typeof window === \"object\") {\n return window;\n }\n\n // This works if the self reference is available\n if (typeof self === \"object\") {\n return self;\n }\n\n // This works if the global reference is available\n if (typeof __webpack_require__.g !== \"undefined\") {\n return __webpack_require__.g;\n }\n }\n return g;\n}();\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/expose-loader/dist/runtime/getGlobalThis.js?");
/***/ }),
/***/ "../node_modules/lodash/_DataView.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_DataView.js ***!
\*******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var getNative = __webpack_require__(/*! ./_getNative */ \"../node_modules/lodash/_getNative.js\"),\n root = __webpack_require__(/*! ./_root */ \"../node_modules/lodash/_root.js\");\n\n/* Built-in method references that are verified to be native. */\nvar DataView = getNative(root, 'DataView');\n\nmodule.exports = DataView;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_DataView.js?");
/***/ }),
/***/ "../node_modules/lodash/_Hash.js":
/*!***************************************!*\
!*** ../node_modules/lodash/_Hash.js ***!
\***************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var hashClear = __webpack_require__(/*! ./_hashClear */ \"../node_modules/lodash/_hashClear.js\"),\n hashDelete = __webpack_require__(/*! ./_hashDelete */ \"../node_modules/lodash/_hashDelete.js\"),\n hashGet = __webpack_require__(/*! ./_hashGet */ \"../node_modules/lodash/_hashGet.js\"),\n hashHas = __webpack_require__(/*! ./_hashHas */ \"../node_modules/lodash/_hashHas.js\"),\n hashSet = __webpack_require__(/*! ./_hashSet */ \"../node_modules/lodash/_hashSet.js\");\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `Hash`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\nmodule.exports = Hash;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_Hash.js?");
/***/ }),
/***/ "../node_modules/lodash/_ListCache.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_ListCache.js ***!
\********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var listCacheClear = __webpack_require__(/*! ./_listCacheClear */ \"../node_modules/lodash/_listCacheClear.js\"),\n listCacheDelete = __webpack_require__(/*! ./_listCacheDelete */ \"../node_modules/lodash/_listCacheDelete.js\"),\n listCacheGet = __webpack_require__(/*! ./_listCacheGet */ \"../node_modules/lodash/_listCacheGet.js\"),\n listCacheHas = __webpack_require__(/*! ./_listCacheHas */ \"../node_modules/lodash/_listCacheHas.js\"),\n listCacheSet = __webpack_require__(/*! ./_listCacheSet */ \"../node_modules/lodash/_listCacheSet.js\");\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `ListCache`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\nmodule.exports = ListCache;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_ListCache.js?");
/***/ }),
/***/ "../node_modules/lodash/_Map.js":
/*!**************************************!*\
!*** ../node_modules/lodash/_Map.js ***!
\**************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var getNative = __webpack_require__(/*! ./_getNative */ \"../node_modules/lodash/_getNative.js\"),\n root = __webpack_require__(/*! ./_root */ \"../node_modules/lodash/_root.js\");\n\n/* Built-in method references that are verified to be native. */\nvar Map = getNative(root, 'Map');\n\nmodule.exports = Map;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_Map.js?");
/***/ }),
/***/ "../node_modules/lodash/_MapCache.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_MapCache.js ***!
\*******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var mapCacheClear = __webpack_require__(/*! ./_mapCacheClear */ \"../node_modules/lodash/_mapCacheClear.js\"),\n mapCacheDelete = __webpack_require__(/*! ./_mapCacheDelete */ \"../node_modules/lodash/_mapCacheDelete.js\"),\n mapCacheGet = __webpack_require__(/*! ./_mapCacheGet */ \"../node_modules/lodash/_mapCacheGet.js\"),\n mapCacheHas = __webpack_require__(/*! ./_mapCacheHas */ \"../node_modules/lodash/_mapCacheHas.js\"),\n mapCacheSet = __webpack_require__(/*! ./_mapCacheSet */ \"../node_modules/lodash/_mapCacheSet.js\");\n\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `MapCache`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\nmodule.exports = MapCache;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_MapCache.js?");
/***/ }),
/***/ "../node_modules/lodash/_Promise.js":
/*!******************************************!*\
!*** ../node_modules/lodash/_Promise.js ***!
\******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var getNative = __webpack_require__(/*! ./_getNative */ \"../node_modules/lodash/_getNative.js\"),\n root = __webpack_require__(/*! ./_root */ \"../node_modules/lodash/_root.js\");\n\n/* Built-in method references that are verified to be native. */\nvar Promise = getNative(root, 'Promise');\n\nmodule.exports = Promise;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_Promise.js?");
/***/ }),
/***/ "../node_modules/lodash/_Set.js":
/*!**************************************!*\
!*** ../node_modules/lodash/_Set.js ***!
\**************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var getNative = __webpack_require__(/*! ./_getNative */ \"../node_modules/lodash/_getNative.js\"),\n root = __webpack_require__(/*! ./_root */ \"../node_modules/lodash/_root.js\");\n\n/* Built-in method references that are verified to be native. */\nvar Set = getNative(root, 'Set');\n\nmodule.exports = Set;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_Set.js?");
/***/ }),
/***/ "../node_modules/lodash/_Stack.js":
/*!****************************************!*\
!*** ../node_modules/lodash/_Stack.js ***!
\****************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var ListCache = __webpack_require__(/*! ./_ListCache */ \"../node_modules/lodash/_ListCache.js\"),\n stackClear = __webpack_require__(/*! ./_stackClear */ \"../node_modules/lodash/_stackClear.js\"),\n stackDelete = __webpack_require__(/*! ./_stackDelete */ \"../node_modules/lodash/_stackDelete.js\"),\n stackGet = __webpack_require__(/*! ./_stackGet */ \"../node_modules/lodash/_stackGet.js\"),\n stackHas = __webpack_require__(/*! ./_stackHas */ \"../node_modules/lodash/_stackHas.js\"),\n stackSet = __webpack_require__(/*! ./_stackSet */ \"../node_modules/lodash/_stackSet.js\");\n\n/**\n * Creates a stack cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Stack(entries) {\n var data = this.__data__ = new ListCache(entries);\n this.size = data.size;\n}\n\n// Add methods to `Stack`.\nStack.prototype.clear = stackClear;\nStack.prototype['delete'] = stackDelete;\nStack.prototype.get = stackGet;\nStack.prototype.has = stackHas;\nStack.prototype.set = stackSet;\n\nmodule.exports = Stack;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_Stack.js?");
/***/ }),
/***/ "../node_modules/lodash/_Symbol.js":
/*!*****************************************!*\
!*** ../node_modules/lodash/_Symbol.js ***!
\*****************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var root = __webpack_require__(/*! ./_root */ \"../node_modules/lodash/_root.js\");\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nmodule.exports = Symbol;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_Symbol.js?");
/***/ }),
/***/ "../node_modules/lodash/_Uint8Array.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_Uint8Array.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var root = __webpack_require__(/*! ./_root */ \"../node_modules/lodash/_root.js\");\n\n/** Built-in value references. */\nvar Uint8Array = root.Uint8Array;\n\nmodule.exports = Uint8Array;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_Uint8Array.js?");
/***/ }),
/***/ "../node_modules/lodash/_WeakMap.js":
/*!******************************************!*\
!*** ../node_modules/lodash/_WeakMap.js ***!
\******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var getNative = __webpack_require__(/*! ./_getNative */ \"../node_modules/lodash/_getNative.js\"),\n root = __webpack_require__(/*! ./_root */ \"../node_modules/lodash/_root.js\");\n\n/* Built-in method references that are verified to be native. */\nvar WeakMap = getNative(root, 'WeakMap');\n\nmodule.exports = WeakMap;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_WeakMap.js?");
/***/ }),
/***/ "../node_modules/lodash/_apply.js":
/*!****************************************!*\
!*** ../node_modules/lodash/_apply.js ***!
\****************************************/
/***/ ((module) => {
eval("/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nmodule.exports = apply;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_apply.js?");
/***/ }),
/***/ "../node_modules/lodash/_arrayEach.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_arrayEach.js ***!
\********************************************/
/***/ ((module) => {
eval("/**\n * A specialized version of `_.forEach` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns `array`.\n */\nfunction arrayEach(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (iteratee(array[index], index, array) === false) {\n break;\n }\n }\n return array;\n}\n\nmodule.exports = arrayEach;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_arrayEach.js?");
/***/ }),
/***/ "../node_modules/lodash/_arrayFilter.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_arrayFilter.js ***!
\**********************************************/
/***/ ((module) => {
eval("/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nmodule.exports = arrayFilter;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_arrayFilter.js?");
/***/ }),
/***/ "../node_modules/lodash/_arrayLikeKeys.js":
/*!************************************************!*\
!*** ../node_modules/lodash/_arrayLikeKeys.js ***!
\************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseTimes = __webpack_require__(/*! ./_baseTimes */ \"../node_modules/lodash/_baseTimes.js\"),\n isArguments = __webpack_require__(/*! ./isArguments */ \"../node_modules/lodash/isArguments.js\"),\n isArray = __webpack_require__(/*! ./isArray */ \"../node_modules/lodash/isArray.js\"),\n isBuffer = __webpack_require__(/*! ./isBuffer */ \"../node_modules/lodash/isBuffer.js\"),\n isIndex = __webpack_require__(/*! ./_isIndex */ \"../node_modules/lodash/_isIndex.js\"),\n isTypedArray = __webpack_require__(/*! ./isTypedArray */ \"../node_modules/lodash/isTypedArray.js\");\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n var isArr = isArray(value),\n isArg = !isArr && isArguments(value),\n isBuff = !isArr && !isArg && isBuffer(value),\n isType = !isArr && !isArg && !isBuff && isTypedArray(value),\n skipIndexes = isArr || isArg || isBuff || isType,\n result = skipIndexes ? baseTimes(value.length, String) : [],\n length = result.length;\n\n for (var key in value) {\n if ((inherited || hasOwnProperty.call(value, key)) &&\n !(skipIndexes && (\n // Safari 9 has enumerable `arguments.length` in strict mode.\n key == 'length' ||\n // Node.js 0.10 has enumerable non-index properties on buffers.\n (isBuff && (key == 'offset' || key == 'parent')) ||\n // PhantomJS 2 has enumerable non-index properties on typed arrays.\n (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||\n // Skip index properties.\n isIndex(key, length)\n ))) {\n result.push(key);\n }\n }\n return result;\n}\n\nmodule.exports = arrayLikeKeys;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_arrayLikeKeys.js?");
/***/ }),
/***/ "../node_modules/lodash/_arrayMap.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_arrayMap.js ***!
\*******************************************/
/***/ ((module) => {
eval("/**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\nmodule.exports = arrayMap;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_arrayMap.js?");
/***/ }),
/***/ "../node_modules/lodash/_arrayPush.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_arrayPush.js ***!
\********************************************/
/***/ ((module) => {
eval("/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nmodule.exports = arrayPush;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_arrayPush.js?");
/***/ }),
/***/ "../node_modules/lodash/_arrayReduce.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_arrayReduce.js ***!
\**********************************************/
/***/ ((module) => {
eval("/**\n * A specialized version of `_.reduce` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @param {*} [accumulator] The initial value.\n * @param {boolean} [initAccum] Specify using the first element of `array` as\n * the initial value.\n * @returns {*} Returns the accumulated value.\n */\nfunction arrayReduce(array, iteratee, accumulator, initAccum) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n if (initAccum && length) {\n accumulator = array[++index];\n }\n while (++index < length) {\n accumulator = iteratee(accumulator, array[index], index, array);\n }\n return accumulator;\n}\n\nmodule.exports = arrayReduce;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_arrayReduce.js?");
/***/ }),
/***/ "../node_modules/lodash/_asciiToArray.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_asciiToArray.js ***!
\***********************************************/
/***/ ((module) => {
eval("/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n return string.split('');\n}\n\nmodule.exports = asciiToArray;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_asciiToArray.js?");
/***/ }),
/***/ "../node_modules/lodash/_asciiWords.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_asciiWords.js ***!
\*********************************************/
/***/ ((module) => {
eval("/** Used to match words composed of alphanumeric characters. */\nvar reAsciiWord = /[^\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\x7f]+/g;\n\n/**\n * Splits an ASCII `string` into an array of its words.\n *\n * @private\n * @param {string} The string to inspect.\n * @returns {Array} Returns the words of `string`.\n */\nfunction asciiWords(string) {\n return string.match(reAsciiWord) || [];\n}\n\nmodule.exports = asciiWords;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_asciiWords.js?");
/***/ }),
/***/ "../node_modules/lodash/_assignValue.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_assignValue.js ***!
\**********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseAssignValue = __webpack_require__(/*! ./_baseAssignValue */ \"../node_modules/lodash/_baseAssignValue.js\"),\n eq = __webpack_require__(/*! ./eq */ \"../node_modules/lodash/eq.js\");\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Assigns `value` to `key` of `object` if the existing value is not equivalent\n * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * for equality comparisons.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction assignValue(object, key, value) {\n var objValue = object[key];\n if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||\n (value === undefined && !(key in object))) {\n baseAssignValue(object, key, value);\n }\n}\n\nmodule.exports = assignValue;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_assignValue.js?");
/***/ }),
/***/ "../node_modules/lodash/_assocIndexOf.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_assocIndexOf.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var eq = __webpack_require__(/*! ./eq */ \"../node_modules/lodash/eq.js\");\n\n/**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction assocIndexOf(array, key) {\n var length = array.length;\n while (length--) {\n if (eq(array[length][0], key)) {\n return length;\n }\n }\n return -1;\n}\n\nmodule.exports = assocIndexOf;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_assocIndexOf.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseAssign.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_baseAssign.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var copyObject = __webpack_require__(/*! ./_copyObject */ \"../node_modules/lodash/_copyObject.js\"),\n keys = __webpack_require__(/*! ./keys */ \"../node_modules/lodash/keys.js\");\n\n/**\n * The base implementation of `_.assign` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssign(object, source) {\n return object && copyObject(source, keys(source), object);\n}\n\nmodule.exports = baseAssign;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseAssign.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseAssignIn.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_baseAssignIn.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var copyObject = __webpack_require__(/*! ./_copyObject */ \"../node_modules/lodash/_copyObject.js\"),\n keysIn = __webpack_require__(/*! ./keysIn */ \"../node_modules/lodash/keysIn.js\");\n\n/**\n * The base implementation of `_.assignIn` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssignIn(object, source) {\n return object && copyObject(source, keysIn(source), object);\n}\n\nmodule.exports = baseAssignIn;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseAssignIn.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseAssignValue.js":
/*!**************************************************!*\
!*** ../node_modules/lodash/_baseAssignValue.js ***!
\**************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var defineProperty = __webpack_require__(/*! ./_defineProperty */ \"../node_modules/lodash/_defineProperty.js\");\n\n/**\n * The base implementation of `assignValue` and `assignMergeValue` without\n * value checks.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction baseAssignValue(object, key, value) {\n if (key == '__proto__' && defineProperty) {\n defineProperty(object, key, {\n 'configurable': true,\n 'enumerable': true,\n 'value': value,\n 'writable': true\n });\n } else {\n object[key] = value;\n }\n}\n\nmodule.exports = baseAssignValue;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseAssignValue.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseClone.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_baseClone.js ***!
\********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var Stack = __webpack_require__(/*! ./_Stack */ \"../node_modules/lodash/_Stack.js\"),\n arrayEach = __webpack_require__(/*! ./_arrayEach */ \"../node_modules/lodash/_arrayEach.js\"),\n assignValue = __webpack_require__(/*! ./_assignValue */ \"../node_modules/lodash/_assignValue.js\"),\n baseAssign = __webpack_require__(/*! ./_baseAssign */ \"../node_modules/lodash/_baseAssign.js\"),\n baseAssignIn = __webpack_require__(/*! ./_baseAssignIn */ \"../node_modules/lodash/_baseAssignIn.js\"),\n cloneBuffer = __webpack_require__(/*! ./_cloneBuffer */ \"../node_modules/lodash/_cloneBuffer.js\"),\n copyArray = __webpack_require__(/*! ./_copyArray */ \"../node_modules/lodash/_copyArray.js\"),\n copySymbols = __webpack_require__(/*! ./_copySymbols */ \"../node_modules/lodash/_copySymbols.js\"),\n copySymbolsIn = __webpack_require__(/*! ./_copySymbolsIn */ \"../node_modules/lodash/_copySymbolsIn.js\"),\n getAllKeys = __webpack_require__(/*! ./_getAllKeys */ \"../node_modules/lodash/_getAllKeys.js\"),\n getAllKeysIn = __webpack_require__(/*! ./_getAllKeysIn */ \"../node_modules/lodash/_getAllKeysIn.js\"),\n getTag = __webpack_require__(/*! ./_getTag */ \"../node_modules/lodash/_getTag.js\"),\n initCloneArray = __webpack_require__(/*! ./_initCloneArray */ \"../node_modules/lodash/_initCloneArray.js\"),\n initCloneByTag = __webpack_require__(/*! ./_initCloneByTag */ \"../node_modules/lodash/_initCloneByTag.js\"),\n initCloneObject = __webpack_require__(/*! ./_initCloneObject */ \"../node_modules/lodash/_initCloneObject.js\"),\n isArray = __webpack_require__(/*! ./isArray */ \"../node_modules/lodash/isArray.js\"),\n isBuffer = __webpack_require__(/*! ./isBuffer */ \"../node_modules/lodash/isBuffer.js\"),\n isMap = __webpack_require__(/*! ./isMap */ \"../node_modules/lodash/isMap.js\"),\n isObject = __webpack_require__(/*! ./isObject */ \"../node_modules/lodash/isObject.js\"),\n isSet = __webpack_require__(/*! ./isSet */ \"../node_modules/lodash/isSet.js\"),\n keys = __webpack_require__(/*! ./keys */ \"../node_modules/lodash/keys.js\"),\n keysIn = __webpack_require__(/*! ./keysIn */ \"../node_modules/lodash/keysIn.js\");\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n CLONE_FLAT_FLAG = 2,\n CLONE_SYMBOLS_FLAG = 4;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n objectTag = '[object Object]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]',\n weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/** Used to identify `toStringTag` values supported by `_.clone`. */\nvar cloneableTags = {};\ncloneableTags[argsTag] = cloneableTags[arrayTag] =\ncloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =\ncloneableTags[boolTag] = cloneableTags[dateTag] =\ncloneableTags[float32Tag] = cloneableTags[float64Tag] =\ncloneableTags[int8Tag] = cloneableTags[int16Tag] =\ncloneableTags[int32Tag] = cloneableTags[mapTag] =\ncloneableTags[numberTag] = cloneableTags[objectTag] =\ncloneableTags[regexpTag] = cloneableTags[setTag] =\ncloneableTags[stringTag] = cloneableTags[symbolTag] =\ncloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =\ncloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;\ncloneableTags[errorTag] = cloneableTags[funcTag] =\ncloneableTags[weakMapTag] = false;\n\n/**\n * The base implementation of `_.clone` and `_.cloneDeep` which tracks\n * traversed objects.\n *\n * @private\n * @param {*} value The value to clone.\n * @param {boolean} bitmask The bitmask flags.\n * 1 - Deep clone\n * 2 - Flatten inherited properties\n * 4 - Clone symbols\n * @param {Function} [customizer] The function to customize cloning.\n * @param {string} [key] The key of `value`.\n * @param {Object} [object] The parent object of `value`.\n * @param {Object} [stack] Tracks traversed objects and their clone counterparts.\n * @returns {*} Returns the cloned value.\n */\nfunction baseClone(value, bitmask, customizer, key, object, stack) {\n var result,\n isDeep = bitmask & CLONE_DEEP_FLAG,\n isFlat = bitmask & CLONE_FLAT_FLAG,\n isFull = bitmask & CLONE_SYMBOLS_FLAG;\n\n if (customizer) {\n result = object ? customizer(value, key, object, stack) : customizer(value);\n }\n if (result !== undefined) {\n return result;\n }\n if (!isObject(value)) {\n return value;\n }\n var isArr = isArray(value);\n if (isArr) {\n result = initCloneArray(value);\n if (!isDeep) {\n return copyArray(value, result);\n }\n } else {\n var tag = getTag(value),\n isFunc = tag == funcTag || tag == genTag;\n\n if (isBuffer(value)) {\n return cloneBuffer(value, isDeep);\n }\n if (tag == objectTag || tag == argsTag || (isFunc && !object)) {\n result = (isFlat || isFunc) ? {} : initCloneObject(value);\n if (!isDeep) {\n return isFlat\n ? copySymbolsIn(value, baseAssignIn(result, value))\n : copySymbols(value, baseAssign(result, value));\n }\n } else {\n if (!cloneableTags[tag]) {\n return object ? value : {};\n }\n result = initCloneByTag(value, tag, isDeep);\n }\n }\n // Check for circular references and return its corresponding clone.\n stack || (stack = new Stack);\n var stacked = stack.get(value);\n if (stacked) {\n return stacked;\n }\n stack.set(value, result);\n\n if (isSet(value)) {\n value.forEach(function(subValue) {\n result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));\n });\n } else if (isMap(value)) {\n value.forEach(function(subValue, key) {\n result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));\n });\n }\n\n var keysFunc = isFull\n ? (isFlat ? getAllKeysIn : getAllKeys)\n : (isFlat ? keysIn : keys);\n\n var props = isArr ? undefined : keysFunc(value);\n arrayEach(props || value, function(subValue, key) {\n if (props) {\n key = subValue;\n subValue = value[key];\n }\n // Recursively populate clone (susceptible to call stack limits).\n assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));\n });\n return result;\n}\n\nmodule.exports = baseClone;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseClone.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseCreate.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_baseCreate.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var isObject = __webpack_require__(/*! ./isObject */ \"../node_modules/lodash/isObject.js\");\n\n/** Built-in value references. */\nvar objectCreate = Object.create;\n\n/**\n * The base implementation of `_.create` without support for assigning\n * properties to the created object.\n *\n * @private\n * @param {Object} proto The object to inherit from.\n * @returns {Object} Returns the new object.\n */\nvar baseCreate = (function() {\n function object() {}\n return function(proto) {\n if (!isObject(proto)) {\n return {};\n }\n if (objectCreate) {\n return objectCreate(proto);\n }\n object.prototype = proto;\n var result = new object;\n object.prototype = undefined;\n return result;\n };\n}());\n\nmodule.exports = baseCreate;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseCreate.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseFlatten.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_baseFlatten.js ***!
\**********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var arrayPush = __webpack_require__(/*! ./_arrayPush */ \"../node_modules/lodash/_arrayPush.js\"),\n isFlattenable = __webpack_require__(/*! ./_isFlattenable */ \"../node_modules/lodash/_isFlattenable.js\");\n\n/**\n * The base implementation of `_.flatten` with support for restricting flattening.\n *\n * @private\n * @param {Array} array The array to flatten.\n * @param {number} depth The maximum recursion depth.\n * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.\n * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.\n * @param {Array} [result=[]] The initial result value.\n * @returns {Array} Returns the new flattened array.\n */\nfunction baseFlatten(array, depth, predicate, isStrict, result) {\n var index = -1,\n length = array.length;\n\n predicate || (predicate = isFlattenable);\n result || (result = []);\n\n while (++index < length) {\n var value = array[index];\n if (depth > 0 && predicate(value)) {\n if (depth > 1) {\n // Recursively flatten arrays (susceptible to call stack limits).\n baseFlatten(value, depth - 1, predicate, isStrict, result);\n } else {\n arrayPush(result, value);\n }\n } else if (!isStrict) {\n result[result.length] = value;\n }\n }\n return result;\n}\n\nmodule.exports = baseFlatten;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseFlatten.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseGet.js":
/*!******************************************!*\
!*** ../node_modules/lodash/_baseGet.js ***!
\******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var castPath = __webpack_require__(/*! ./_castPath */ \"../node_modules/lodash/_castPath.js\"),\n toKey = __webpack_require__(/*! ./_toKey */ \"../node_modules/lodash/_toKey.js\");\n\n/**\n * The base implementation of `_.get` without support for default values.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Array|string} path The path of the property to get.\n * @returns {*} Returns the resolved value.\n */\nfunction baseGet(object, path) {\n path = castPath(path, object);\n\n var index = 0,\n length = path.length;\n\n while (object != null && index < length) {\n object = object[toKey(path[index++])];\n }\n return (index && index == length) ? object : undefined;\n}\n\nmodule.exports = baseGet;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseGet.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseGetAllKeys.js":
/*!*************************************************!*\
!*** ../node_modules/lodash/_baseGetAllKeys.js ***!
\*************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var arrayPush = __webpack_require__(/*! ./_arrayPush */ \"../node_modules/lodash/_arrayPush.js\"),\n isArray = __webpack_require__(/*! ./isArray */ \"../node_modules/lodash/isArray.js\");\n\n/**\n * The base implementation of `getAllKeys` and `getAllKeysIn` which uses\n * `keysFunc` and `symbolsFunc` to get the enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @param {Function} symbolsFunc The function to get the symbols of `object`.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n var result = keysFunc(object);\n return isArray(object) ? result : arrayPush(result, symbolsFunc(object));\n}\n\nmodule.exports = baseGetAllKeys;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseGetAllKeys.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseGetTag.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_baseGetTag.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var Symbol = __webpack_require__(/*! ./_Symbol */ \"../node_modules/lodash/_Symbol.js\"),\n getRawTag = __webpack_require__(/*! ./_getRawTag */ \"../node_modules/lodash/_getRawTag.js\"),\n objectToString = __webpack_require__(/*! ./_objectToString */ \"../node_modules/lodash/_objectToString.js\");\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nmodule.exports = baseGetTag;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseGetTag.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseHasIn.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_baseHasIn.js ***!
\********************************************/
/***/ ((module) => {
eval("/**\n * The base implementation of `_.hasIn` without support for deep paths.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {Array|string} key The key to check.\n * @returns {boolean} Returns `true` if `key` exists, else `false`.\n */\nfunction baseHasIn(object, key) {\n return object != null && key in Object(object);\n}\n\nmodule.exports = baseHasIn;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseHasIn.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseIsArguments.js":
/*!**************************************************!*\
!*** ../node_modules/lodash/_baseIsArguments.js ***!
\**************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseGetTag = __webpack_require__(/*! ./_baseGetTag */ \"../node_modules/lodash/_baseGetTag.js\"),\n isObjectLike = __webpack_require__(/*! ./isObjectLike */ \"../node_modules/lodash/isObjectLike.js\");\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]';\n\n/**\n * The base implementation of `_.isArguments`.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n */\nfunction baseIsArguments(value) {\n return isObjectLike(value) && baseGetTag(value) == argsTag;\n}\n\nmodule.exports = baseIsArguments;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseIsArguments.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseIsMap.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_baseIsMap.js ***!
\********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var getTag = __webpack_require__(/*! ./_getTag */ \"../node_modules/lodash/_getTag.js\"),\n isObjectLike = __webpack_require__(/*! ./isObjectLike */ \"../node_modules/lodash/isObjectLike.js\");\n\n/** `Object#toString` result references. */\nvar mapTag = '[object Map]';\n\n/**\n * The base implementation of `_.isMap` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a map, else `false`.\n */\nfunction baseIsMap(value) {\n return isObjectLike(value) && getTag(value) == mapTag;\n}\n\nmodule.exports = baseIsMap;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseIsMap.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseIsNative.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_baseIsNative.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var isFunction = __webpack_require__(/*! ./isFunction */ \"../node_modules/lodash/isFunction.js\"),\n isMasked = __webpack_require__(/*! ./_isMasked */ \"../node_modules/lodash/_isMasked.js\"),\n isObject = __webpack_require__(/*! ./isObject */ \"../node_modules/lodash/isObject.js\"),\n toSource = __webpack_require__(/*! ./_toSource */ \"../node_modules/lodash/_toSource.js\");\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n * else `false`.\n */\nfunction baseIsNative(value) {\n if (!isObject(value) || isMasked(value)) {\n return false;\n }\n var pattern = isFunction(value) ? reIsNative : reIsHostCtor;\n return pattern.test(toSource(value));\n}\n\nmodule.exports = baseIsNative;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseIsNative.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseIsSet.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_baseIsSet.js ***!
\********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var getTag = __webpack_require__(/*! ./_getTag */ \"../node_modules/lodash/_getTag.js\"),\n isObjectLike = __webpack_require__(/*! ./isObjectLike */ \"../node_modules/lodash/isObjectLike.js\");\n\n/** `Object#toString` result references. */\nvar setTag = '[object Set]';\n\n/**\n * The base implementation of `_.isSet` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a set, else `false`.\n */\nfunction baseIsSet(value) {\n return isObjectLike(value) && getTag(value) == setTag;\n}\n\nmodule.exports = baseIsSet;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseIsSet.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseIsTypedArray.js":
/*!***************************************************!*\
!*** ../node_modules/lodash/_baseIsTypedArray.js ***!
\***************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseGetTag = __webpack_require__(/*! ./_baseGetTag */ \"../node_modules/lodash/_baseGetTag.js\"),\n isLength = __webpack_require__(/*! ./isLength */ \"../node_modules/lodash/isLength.js\"),\n isObjectLike = __webpack_require__(/*! ./isObjectLike */ \"../node_modules/lodash/isObjectLike.js\");\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n funcTag = '[object Function]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n objectTag = '[object Object]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/** Used to identify `toStringTag` values of typed arrays. */\nvar typedArrayTags = {};\ntypedArrayTags[float32Tag] = typedArrayTags[float64Tag] =\ntypedArrayTags[int8Tag] = typedArrayTags[int16Tag] =\ntypedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =\ntypedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =\ntypedArrayTags[uint32Tag] = true;\ntypedArrayTags[argsTag] = typedArrayTags[arrayTag] =\ntypedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =\ntypedArrayTags[dataViewTag] = typedArrayTags[dateTag] =\ntypedArrayTags[errorTag] = typedArrayTags[funcTag] =\ntypedArrayTags[mapTag] = typedArrayTags[numberTag] =\ntypedArrayTags[objectTag] = typedArrayTags[regexpTag] =\ntypedArrayTags[setTag] = typedArrayTags[stringTag] =\ntypedArrayTags[weakMapTag] = false;\n\n/**\n * The base implementation of `_.isTypedArray` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n */\nfunction baseIsTypedArray(value) {\n return isObjectLike(value) &&\n isLength(value.length) && !!typedArrayTags[baseGetTag(value)];\n}\n\nmodule.exports = baseIsTypedArray;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseIsTypedArray.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseKeys.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_baseKeys.js ***!
\*******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var isPrototype = __webpack_require__(/*! ./_isPrototype */ \"../node_modules/lodash/_isPrototype.js\"),\n nativeKeys = __webpack_require__(/*! ./_nativeKeys */ \"../node_modules/lodash/_nativeKeys.js\");\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n if (!isPrototype(object)) {\n return nativeKeys(object);\n }\n var result = [];\n for (var key in Object(object)) {\n if (hasOwnProperty.call(object, key) && key != 'constructor') {\n result.push(key);\n }\n }\n return result;\n}\n\nmodule.exports = baseKeys;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseKeys.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseKeysIn.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_baseKeysIn.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var isObject = __webpack_require__(/*! ./isObject */ \"../node_modules/lodash/isObject.js\"),\n isPrototype = __webpack_require__(/*! ./_isPrototype */ \"../node_modules/lodash/_isPrototype.js\"),\n nativeKeysIn = __webpack_require__(/*! ./_nativeKeysIn */ \"../node_modules/lodash/_nativeKeysIn.js\");\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeysIn(object) {\n if (!isObject(object)) {\n return nativeKeysIn(object);\n }\n var isProto = isPrototype(object),\n result = [];\n\n for (var key in object) {\n if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {\n result.push(key);\n }\n }\n return result;\n}\n\nmodule.exports = baseKeysIn;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseKeysIn.js?");
/***/ }),
/***/ "../node_modules/lodash/_basePick.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_basePick.js ***!
\*******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var basePickBy = __webpack_require__(/*! ./_basePickBy */ \"../node_modules/lodash/_basePickBy.js\"),\n hasIn = __webpack_require__(/*! ./hasIn */ \"../node_modules/lodash/hasIn.js\");\n\n/**\n * The base implementation of `_.pick` without support for individual\n * property identifiers.\n *\n * @private\n * @param {Object} object The source object.\n * @param {string[]} paths The property paths to pick.\n * @returns {Object} Returns the new object.\n */\nfunction basePick(object, paths) {\n return basePickBy(object, paths, function(value, path) {\n return hasIn(object, path);\n });\n}\n\nmodule.exports = basePick;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_basePick.js?");
/***/ }),
/***/ "../node_modules/lodash/_basePickBy.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_basePickBy.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseGet = __webpack_require__(/*! ./_baseGet */ \"../node_modules/lodash/_baseGet.js\"),\n baseSet = __webpack_require__(/*! ./_baseSet */ \"../node_modules/lodash/_baseSet.js\"),\n castPath = __webpack_require__(/*! ./_castPath */ \"../node_modules/lodash/_castPath.js\");\n\n/**\n * The base implementation of `_.pickBy` without support for iteratee shorthands.\n *\n * @private\n * @param {Object} object The source object.\n * @param {string[]} paths The property paths to pick.\n * @param {Function} predicate The function invoked per property.\n * @returns {Object} Returns the new object.\n */\nfunction basePickBy(object, paths, predicate) {\n var index = -1,\n length = paths.length,\n result = {};\n\n while (++index < length) {\n var path = paths[index],\n value = baseGet(object, path);\n\n if (predicate(value, path)) {\n baseSet(result, castPath(path, object), value);\n }\n }\n return result;\n}\n\nmodule.exports = basePickBy;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_basePickBy.js?");
/***/ }),
/***/ "../node_modules/lodash/_basePropertyOf.js":
/*!*************************************************!*\
!*** ../node_modules/lodash/_basePropertyOf.js ***!
\*************************************************/
/***/ ((module) => {
eval("/**\n * The base implementation of `_.propertyOf` without support for deep paths.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Function} Returns the new accessor function.\n */\nfunction basePropertyOf(object) {\n return function(key) {\n return object == null ? undefined : object[key];\n };\n}\n\nmodule.exports = basePropertyOf;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_basePropertyOf.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseSet.js":
/*!******************************************!*\
!*** ../node_modules/lodash/_baseSet.js ***!
\******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var assignValue = __webpack_require__(/*! ./_assignValue */ \"../node_modules/lodash/_assignValue.js\"),\n castPath = __webpack_require__(/*! ./_castPath */ \"../node_modules/lodash/_castPath.js\"),\n isIndex = __webpack_require__(/*! ./_isIndex */ \"../node_modules/lodash/_isIndex.js\"),\n isObject = __webpack_require__(/*! ./isObject */ \"../node_modules/lodash/isObject.js\"),\n toKey = __webpack_require__(/*! ./_toKey */ \"../node_modules/lodash/_toKey.js\");\n\n/**\n * The base implementation of `_.set`.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to set.\n * @param {*} value The value to set.\n * @param {Function} [customizer] The function to customize path creation.\n * @returns {Object} Returns `object`.\n */\nfunction baseSet(object, path, value, customizer) {\n if (!isObject(object)) {\n return object;\n }\n path = castPath(path, object);\n\n var index = -1,\n length = path.length,\n lastIndex = length - 1,\n nested = object;\n\n while (nested != null && ++index < length) {\n var key = toKey(path[index]),\n newValue = value;\n\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n return object;\n }\n\n if (index != lastIndex) {\n var objValue = nested[key];\n newValue = customizer ? customizer(objValue, key, nested) : undefined;\n if (newValue === undefined) {\n newValue = isObject(objValue)\n ? objValue\n : (isIndex(path[index + 1]) ? [] : {});\n }\n }\n assignValue(nested, key, newValue);\n nested = nested[key];\n }\n return object;\n}\n\nmodule.exports = baseSet;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseSet.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseSetToString.js":
/*!**************************************************!*\
!*** ../node_modules/lodash/_baseSetToString.js ***!
\**************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var constant = __webpack_require__(/*! ./constant */ \"../node_modules/lodash/constant.js\"),\n defineProperty = __webpack_require__(/*! ./_defineProperty */ \"../node_modules/lodash/_defineProperty.js\"),\n identity = __webpack_require__(/*! ./identity */ \"../node_modules/lodash/identity.js\");\n\n/**\n * The base implementation of `setToString` without support for hot loop shorting.\n *\n * @private\n * @param {Function} func The function to modify.\n * @param {Function} string The `toString` result.\n * @returns {Function} Returns `func`.\n */\nvar baseSetToString = !defineProperty ? identity : function(func, string) {\n return defineProperty(func, 'toString', {\n 'configurable': true,\n 'enumerable': false,\n 'value': constant(string),\n 'writable': true\n });\n};\n\nmodule.exports = baseSetToString;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseSetToString.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseSlice.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_baseSlice.js ***!
\********************************************/
/***/ ((module) => {
eval("/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n var index = -1,\n length = array.length;\n\n if (start < 0) {\n start = -start > length ? 0 : (length + start);\n }\n end = end > length ? length : end;\n if (end < 0) {\n end += length;\n }\n length = start > end ? 0 : ((end - start) >>> 0);\n start >>>= 0;\n\n var result = Array(length);\n while (++index < length) {\n result[index] = array[index + start];\n }\n return result;\n}\n\nmodule.exports = baseSlice;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseSlice.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseTimes.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_baseTimes.js ***!
\********************************************/
/***/ ((module) => {
eval("/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nmodule.exports = baseTimes;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseTimes.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseToString.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_baseToString.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var Symbol = __webpack_require__(/*! ./_Symbol */ \"../node_modules/lodash/_Symbol.js\"),\n arrayMap = __webpack_require__(/*! ./_arrayMap */ \"../node_modules/lodash/_arrayMap.js\"),\n isArray = __webpack_require__(/*! ./isArray */ \"../node_modules/lodash/isArray.js\"),\n isSymbol = __webpack_require__(/*! ./isSymbol */ \"../node_modules/lodash/isSymbol.js\");\n\n/** Used as references for various `Number` constants. */\nvar INFINITY = 1 / 0;\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolToString = symbolProto ? symbolProto.toString : undefined;\n\n/**\n * The base implementation of `_.toString` which doesn't convert nullish\n * values to empty strings.\n *\n * @private\n * @param {*} value The value to process.\n * @returns {string} Returns the string.\n */\nfunction baseToString(value) {\n // Exit early for strings to avoid a performance hit in some environments.\n if (typeof value == 'string') {\n return value;\n }\n if (isArray(value)) {\n // Recursively convert values (susceptible to call stack limits).\n return arrayMap(value, baseToString) + '';\n }\n if (isSymbol(value)) {\n return symbolToString ? symbolToString.call(value) : '';\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\nmodule.exports = baseToString;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseToString.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseUnary.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_baseUnary.js ***!
\********************************************/
/***/ ((module) => {
eval("/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nmodule.exports = baseUnary;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseUnary.js?");
/***/ }),
/***/ "../node_modules/lodash/_baseUnset.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_baseUnset.js ***!
\********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var castPath = __webpack_require__(/*! ./_castPath */ \"../node_modules/lodash/_castPath.js\"),\n last = __webpack_require__(/*! ./last */ \"../node_modules/lodash/last.js\"),\n parent = __webpack_require__(/*! ./_parent */ \"../node_modules/lodash/_parent.js\"),\n toKey = __webpack_require__(/*! ./_toKey */ \"../node_modules/lodash/_toKey.js\");\n\n/**\n * The base implementation of `_.unset`.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {Array|string} path The property path to unset.\n * @returns {boolean} Returns `true` if the property is deleted, else `false`.\n */\nfunction baseUnset(object, path) {\n path = castPath(path, object);\n object = parent(object, path);\n return object == null || delete object[toKey(last(path))];\n}\n\nmodule.exports = baseUnset;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_baseUnset.js?");
/***/ }),
/***/ "../node_modules/lodash/_castPath.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_castPath.js ***!
\*******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var isArray = __webpack_require__(/*! ./isArray */ \"../node_modules/lodash/isArray.js\"),\n isKey = __webpack_require__(/*! ./_isKey */ \"../node_modules/lodash/_isKey.js\"),\n stringToPath = __webpack_require__(/*! ./_stringToPath */ \"../node_modules/lodash/_stringToPath.js\"),\n toString = __webpack_require__(/*! ./toString */ \"../node_modules/lodash/toString.js\");\n\n/**\n * Casts `value` to a path array if it's not one.\n *\n * @private\n * @param {*} value The value to inspect.\n * @param {Object} [object] The object to query keys on.\n * @returns {Array} Returns the cast property path array.\n */\nfunction castPath(value, object) {\n if (isArray(value)) {\n return value;\n }\n return isKey(value, object) ? [value] : stringToPath(toString(value));\n}\n\nmodule.exports = castPath;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_castPath.js?");
/***/ }),
/***/ "../node_modules/lodash/_castSlice.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_castSlice.js ***!
\********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseSlice = __webpack_require__(/*! ./_baseSlice */ \"../node_modules/lodash/_baseSlice.js\");\n\n/**\n * Casts `array` to a slice if it's needed.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {number} start The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the cast slice.\n */\nfunction castSlice(array, start, end) {\n var length = array.length;\n end = end === undefined ? length : end;\n return (!start && end >= length) ? array : baseSlice(array, start, end);\n}\n\nmodule.exports = castSlice;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_castSlice.js?");
/***/ }),
/***/ "../node_modules/lodash/_cloneArrayBuffer.js":
/*!***************************************************!*\
!*** ../node_modules/lodash/_cloneArrayBuffer.js ***!
\***************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var Uint8Array = __webpack_require__(/*! ./_Uint8Array */ \"../node_modules/lodash/_Uint8Array.js\");\n\n/**\n * Creates a clone of `arrayBuffer`.\n *\n * @private\n * @param {ArrayBuffer} arrayBuffer The array buffer to clone.\n * @returns {ArrayBuffer} Returns the cloned array buffer.\n */\nfunction cloneArrayBuffer(arrayBuffer) {\n var result = new arrayBuffer.constructor(arrayBuffer.byteLength);\n new Uint8Array(result).set(new Uint8Array(arrayBuffer));\n return result;\n}\n\nmodule.exports = cloneArrayBuffer;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_cloneArrayBuffer.js?");
/***/ }),
/***/ "../node_modules/lodash/_cloneBuffer.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_cloneBuffer.js ***!
\**********************************************/
/***/ ((module, exports, __webpack_require__) => {
eval("/* module decorator */ module = __webpack_require__.nmd(module);\nvar root = __webpack_require__(/*! ./_root */ \"../node_modules/lodash/_root.js\");\n\n/** Detect free variable `exports`. */\nvar freeExports = true && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && \"object\" == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined,\n allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined;\n\n/**\n * Creates a clone of `buffer`.\n *\n * @private\n * @param {Buffer} buffer The buffer to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Buffer} Returns the cloned buffer.\n */\nfunction cloneBuffer(buffer, isDeep) {\n if (isDeep) {\n return buffer.slice();\n }\n var length = buffer.length,\n result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);\n\n buffer.copy(result);\n return result;\n}\n\nmodule.exports = cloneBuffer;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_cloneBuffer.js?");
/***/ }),
/***/ "../node_modules/lodash/_cloneDataView.js":
/*!************************************************!*\
!*** ../node_modules/lodash/_cloneDataView.js ***!
\************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var cloneArrayBuffer = __webpack_require__(/*! ./_cloneArrayBuffer */ \"../node_modules/lodash/_cloneArrayBuffer.js\");\n\n/**\n * Creates a clone of `dataView`.\n *\n * @private\n * @param {Object} dataView The data view to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned data view.\n */\nfunction cloneDataView(dataView, isDeep) {\n var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;\n return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);\n}\n\nmodule.exports = cloneDataView;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_cloneDataView.js?");
/***/ }),
/***/ "../node_modules/lodash/_cloneRegExp.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_cloneRegExp.js ***!
\**********************************************/
/***/ ((module) => {
eval("/** Used to match `RegExp` flags from their coerced string values. */\nvar reFlags = /\\w*$/;\n\n/**\n * Creates a clone of `regexp`.\n *\n * @private\n * @param {Object} regexp The regexp to clone.\n * @returns {Object} Returns the cloned regexp.\n */\nfunction cloneRegExp(regexp) {\n var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));\n result.lastIndex = regexp.lastIndex;\n return result;\n}\n\nmodule.exports = cloneRegExp;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_cloneRegExp.js?");
/***/ }),
/***/ "../node_modules/lodash/_cloneSymbol.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_cloneSymbol.js ***!
\**********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var Symbol = __webpack_require__(/*! ./_Symbol */ \"../node_modules/lodash/_Symbol.js\");\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * Creates a clone of the `symbol` object.\n *\n * @private\n * @param {Object} symbol The symbol object to clone.\n * @returns {Object} Returns the cloned symbol object.\n */\nfunction cloneSymbol(symbol) {\n return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};\n}\n\nmodule.exports = cloneSymbol;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_cloneSymbol.js?");
/***/ }),
/***/ "../node_modules/lodash/_cloneTypedArray.js":
/*!**************************************************!*\
!*** ../node_modules/lodash/_cloneTypedArray.js ***!
\**************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var cloneArrayBuffer = __webpack_require__(/*! ./_cloneArrayBuffer */ \"../node_modules/lodash/_cloneArrayBuffer.js\");\n\n/**\n * Creates a clone of `typedArray`.\n *\n * @private\n * @param {Object} typedArray The typed array to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned typed array.\n */\nfunction cloneTypedArray(typedArray, isDeep) {\n var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;\n return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);\n}\n\nmodule.exports = cloneTypedArray;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_cloneTypedArray.js?");
/***/ }),
/***/ "../node_modules/lodash/_copyArray.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_copyArray.js ***!
\********************************************/
/***/ ((module) => {
eval("/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nmodule.exports = copyArray;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_copyArray.js?");
/***/ }),
/***/ "../node_modules/lodash/_copyObject.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_copyObject.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var assignValue = __webpack_require__(/*! ./_assignValue */ \"../node_modules/lodash/_assignValue.js\"),\n baseAssignValue = __webpack_require__(/*! ./_baseAssignValue */ \"../node_modules/lodash/_baseAssignValue.js\");\n\n/**\n * Copies properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy properties from.\n * @param {Array} props The property identifiers to copy.\n * @param {Object} [object={}] The object to copy properties to.\n * @param {Function} [customizer] The function to customize copied values.\n * @returns {Object} Returns `object`.\n */\nfunction copyObject(source, props, object, customizer) {\n var isNew = !object;\n object || (object = {});\n\n var index = -1,\n length = props.length;\n\n while (++index < length) {\n var key = props[index];\n\n var newValue = customizer\n ? customizer(object[key], source[key], key, object, source)\n : undefined;\n\n if (newValue === undefined) {\n newValue = source[key];\n }\n if (isNew) {\n baseAssignValue(object, key, newValue);\n } else {\n assignValue(object, key, newValue);\n }\n }\n return object;\n}\n\nmodule.exports = copyObject;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_copyObject.js?");
/***/ }),
/***/ "../node_modules/lodash/_copySymbols.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_copySymbols.js ***!
\**********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var copyObject = __webpack_require__(/*! ./_copyObject */ \"../node_modules/lodash/_copyObject.js\"),\n getSymbols = __webpack_require__(/*! ./_getSymbols */ \"../node_modules/lodash/_getSymbols.js\");\n\n/**\n * Copies own symbols of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbols(source, object) {\n return copyObject(source, getSymbols(source), object);\n}\n\nmodule.exports = copySymbols;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_copySymbols.js?");
/***/ }),
/***/ "../node_modules/lodash/_copySymbolsIn.js":
/*!************************************************!*\
!*** ../node_modules/lodash/_copySymbolsIn.js ***!
\************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var copyObject = __webpack_require__(/*! ./_copyObject */ \"../node_modules/lodash/_copyObject.js\"),\n getSymbolsIn = __webpack_require__(/*! ./_getSymbolsIn */ \"../node_modules/lodash/_getSymbolsIn.js\");\n\n/**\n * Copies own and inherited symbols of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbolsIn(source, object) {\n return copyObject(source, getSymbolsIn(source), object);\n}\n\nmodule.exports = copySymbolsIn;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_copySymbolsIn.js?");
/***/ }),
/***/ "../node_modules/lodash/_coreJsData.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_coreJsData.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var root = __webpack_require__(/*! ./_root */ \"../node_modules/lodash/_root.js\");\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\nmodule.exports = coreJsData;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_coreJsData.js?");
/***/ }),
/***/ "../node_modules/lodash/_createCaseFirst.js":
/*!**************************************************!*\
!*** ../node_modules/lodash/_createCaseFirst.js ***!
\**************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var castSlice = __webpack_require__(/*! ./_castSlice */ \"../node_modules/lodash/_castSlice.js\"),\n hasUnicode = __webpack_require__(/*! ./_hasUnicode */ \"../node_modules/lodash/_hasUnicode.js\"),\n stringToArray = __webpack_require__(/*! ./_stringToArray */ \"../node_modules/lodash/_stringToArray.js\"),\n toString = __webpack_require__(/*! ./toString */ \"../node_modules/lodash/toString.js\");\n\n/**\n * Creates a function like `_.lowerFirst`.\n *\n * @private\n * @param {string} methodName The name of the `String` case method to use.\n * @returns {Function} Returns the new case function.\n */\nfunction createCaseFirst(methodName) {\n return function(string) {\n string = toString(string);\n\n var strSymbols = hasUnicode(string)\n ? stringToArray(string)\n : undefined;\n\n var chr = strSymbols\n ? strSymbols[0]\n : string.charAt(0);\n\n var trailing = strSymbols\n ? castSlice(strSymbols, 1).join('')\n : string.slice(1);\n\n return chr[methodName]() + trailing;\n };\n}\n\nmodule.exports = createCaseFirst;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_createCaseFirst.js?");
/***/ }),
/***/ "../node_modules/lodash/_createCompounder.js":
/*!***************************************************!*\
!*** ../node_modules/lodash/_createCompounder.js ***!
\***************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var arrayReduce = __webpack_require__(/*! ./_arrayReduce */ \"../node_modules/lodash/_arrayReduce.js\"),\n deburr = __webpack_require__(/*! ./deburr */ \"../node_modules/lodash/deburr.js\"),\n words = __webpack_require__(/*! ./words */ \"../node_modules/lodash/words.js\");\n\n/** Used to compose unicode capture groups. */\nvar rsApos = \"['\\u2019]\";\n\n/** Used to match apostrophes. */\nvar reApos = RegExp(rsApos, 'g');\n\n/**\n * Creates a function like `_.camelCase`.\n *\n * @private\n * @param {Function} callback The function to combine each word.\n * @returns {Function} Returns the new compounder function.\n */\nfunction createCompounder(callback) {\n return function(string) {\n return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');\n };\n}\n\nmodule.exports = createCompounder;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_createCompounder.js?");
/***/ }),
/***/ "../node_modules/lodash/_customOmitClone.js":
/*!**************************************************!*\
!*** ../node_modules/lodash/_customOmitClone.js ***!
\**************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var isPlainObject = __webpack_require__(/*! ./isPlainObject */ \"../node_modules/lodash/isPlainObject.js\");\n\n/**\n * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain\n * objects.\n *\n * @private\n * @param {*} value The value to inspect.\n * @param {string} key The key of the property to inspect.\n * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`.\n */\nfunction customOmitClone(value) {\n return isPlainObject(value) ? undefined : value;\n}\n\nmodule.exports = customOmitClone;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_customOmitClone.js?");
/***/ }),
/***/ "../node_modules/lodash/_deburrLetter.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_deburrLetter.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var basePropertyOf = __webpack_require__(/*! ./_basePropertyOf */ \"../node_modules/lodash/_basePropertyOf.js\");\n\n/** Used to map Latin Unicode letters to basic Latin letters. */\nvar deburredLetters = {\n // Latin-1 Supplement block.\n '\\xc0': 'A', '\\xc1': 'A', '\\xc2': 'A', '\\xc3': 'A', '\\xc4': 'A', '\\xc5': 'A',\n '\\xe0': 'a', '\\xe1': 'a', '\\xe2': 'a', '\\xe3': 'a', '\\xe4': 'a', '\\xe5': 'a',\n '\\xc7': 'C', '\\xe7': 'c',\n '\\xd0': 'D', '\\xf0': 'd',\n '\\xc8': 'E', '\\xc9': 'E', '\\xca': 'E', '\\xcb': 'E',\n '\\xe8': 'e', '\\xe9': 'e', '\\xea': 'e', '\\xeb': 'e',\n '\\xcc': 'I', '\\xcd': 'I', '\\xce': 'I', '\\xcf': 'I',\n '\\xec': 'i', '\\xed': 'i', '\\xee': 'i', '\\xef': 'i',\n '\\xd1': 'N', '\\xf1': 'n',\n '\\xd2': 'O', '\\xd3': 'O', '\\xd4': 'O', '\\xd5': 'O', '\\xd6': 'O', '\\xd8': 'O',\n '\\xf2': 'o', '\\xf3': 'o', '\\xf4': 'o', '\\xf5': 'o', '\\xf6': 'o', '\\xf8': 'o',\n '\\xd9': 'U', '\\xda': 'U', '\\xdb': 'U', '\\xdc': 'U',\n '\\xf9': 'u', '\\xfa': 'u', '\\xfb': 'u', '\\xfc': 'u',\n '\\xdd': 'Y', '\\xfd': 'y', '\\xff': 'y',\n '\\xc6': 'Ae', '\\xe6': 'ae',\n '\\xde': 'Th', '\\xfe': 'th',\n '\\xdf': 'ss',\n // Latin Extended-A block.\n '\\u0100': 'A', '\\u0102': 'A', '\\u0104': 'A',\n '\\u0101': 'a', '\\u0103': 'a', '\\u0105': 'a',\n '\\u0106': 'C', '\\u0108': 'C', '\\u010a': 'C', '\\u010c': 'C',\n '\\u0107': 'c', '\\u0109': 'c', '\\u010b': 'c', '\\u010d': 'c',\n '\\u010e': 'D', '\\u0110': 'D', '\\u010f': 'd', '\\u0111': 'd',\n '\\u0112': 'E', '\\u0114': 'E', '\\u0116': 'E', '\\u0118': 'E', '\\u011a': 'E',\n '\\u0113': 'e', '\\u0115': 'e', '\\u0117': 'e', '\\u0119': 'e', '\\u011b': 'e',\n '\\u011c': 'G', '\\u011e': 'G', '\\u0120': 'G', '\\u0122': 'G',\n '\\u011d': 'g', '\\u011f': 'g', '\\u0121': 'g', '\\u0123': 'g',\n '\\u0124': 'H', '\\u0126': 'H', '\\u0125': 'h', '\\u0127': 'h',\n '\\u0128': 'I', '\\u012a': 'I', '\\u012c': 'I', '\\u012e': 'I', '\\u0130': 'I',\n '\\u0129': 'i', '\\u012b': 'i', '\\u012d': 'i', '\\u012f': 'i', '\\u0131': 'i',\n '\\u0134': 'J', '\\u0135': 'j',\n '\\u0136': 'K', '\\u0137': 'k', '\\u0138': 'k',\n '\\u0139': 'L', '\\u013b': 'L', '\\u013d': 'L', '\\u013f': 'L', '\\u0141': 'L',\n '\\u013a': 'l', '\\u013c': 'l', '\\u013e': 'l', '\\u0140': 'l', '\\u0142': 'l',\n '\\u0143': 'N', '\\u0145': 'N', '\\u0147': 'N', '\\u014a': 'N',\n '\\u0144': 'n', '\\u0146': 'n', '\\u0148': 'n', '\\u014b': 'n',\n '\\u014c': 'O', '\\u014e': 'O', '\\u0150': 'O',\n '\\u014d': 'o', '\\u014f': 'o', '\\u0151': 'o',\n '\\u0154': 'R', '\\u0156': 'R', '\\u0158': 'R',\n '\\u0155': 'r', '\\u0157': 'r', '\\u0159': 'r',\n '\\u015a': 'S', '\\u015c': 'S', '\\u015e': 'S', '\\u0160': 'S',\n '\\u015b': 's', '\\u015d': 's', '\\u015f': 's', '\\u0161': 's',\n '\\u0162': 'T', '\\u0164': 'T', '\\u0166': 'T',\n '\\u0163': 't', '\\u0165': 't', '\\u0167': 't',\n '\\u0168': 'U', '\\u016a': 'U', '\\u016c': 'U', '\\u016e': 'U', '\\u0170': 'U', '\\u0172': 'U',\n '\\u0169': 'u', '\\u016b': 'u', '\\u016d': 'u', '\\u016f': 'u', '\\u0171': 'u', '\\u0173': 'u',\n '\\u0174': 'W', '\\u0175': 'w',\n '\\u0176': 'Y', '\\u0177': 'y', '\\u0178': 'Y',\n '\\u0179': 'Z', '\\u017b': 'Z', '\\u017d': 'Z',\n '\\u017a': 'z', '\\u017c': 'z', '\\u017e': 'z',\n '\\u0132': 'IJ', '\\u0133': 'ij',\n '\\u0152': 'Oe', '\\u0153': 'oe',\n '\\u0149': \"'n\", '\\u017f': 's'\n};\n\n/**\n * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A\n * letters to basic Latin letters.\n *\n * @private\n * @param {string} letter The matched letter to deburr.\n * @returns {string} Returns the deburred letter.\n */\nvar deburrLetter = basePropertyOf(deburredLetters);\n\nmodule.exports = deburrLetter;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_deburrLetter.js?");
/***/ }),
/***/ "../node_modules/lodash/_defineProperty.js":
/*!*************************************************!*\
!*** ../node_modules/lodash/_defineProperty.js ***!
\*************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var getNative = __webpack_require__(/*! ./_getNative */ \"../node_modules/lodash/_getNative.js\");\n\nvar defineProperty = (function() {\n try {\n var func = getNative(Object, 'defineProperty');\n func({}, '', {});\n return func;\n } catch (e) {}\n}());\n\nmodule.exports = defineProperty;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_defineProperty.js?");
/***/ }),
/***/ "../node_modules/lodash/_flatRest.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_flatRest.js ***!
\*******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var flatten = __webpack_require__(/*! ./flatten */ \"../node_modules/lodash/flatten.js\"),\n overRest = __webpack_require__(/*! ./_overRest */ \"../node_modules/lodash/_overRest.js\"),\n setToString = __webpack_require__(/*! ./_setToString */ \"../node_modules/lodash/_setToString.js\");\n\n/**\n * A specialized version of `baseRest` which flattens the rest array.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @returns {Function} Returns the new function.\n */\nfunction flatRest(func) {\n return setToString(overRest(func, undefined, flatten), func + '');\n}\n\nmodule.exports = flatRest;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_flatRest.js?");
/***/ }),
/***/ "../node_modules/lodash/_freeGlobal.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_freeGlobal.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof __webpack_require__.g == 'object' && __webpack_require__.g && __webpack_require__.g.Object === Object && __webpack_require__.g;\n\nmodule.exports = freeGlobal;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_freeGlobal.js?");
/***/ }),
/***/ "../node_modules/lodash/_getAllKeys.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_getAllKeys.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseGetAllKeys = __webpack_require__(/*! ./_baseGetAllKeys */ \"../node_modules/lodash/_baseGetAllKeys.js\"),\n getSymbols = __webpack_require__(/*! ./_getSymbols */ \"../node_modules/lodash/_getSymbols.js\"),\n keys = __webpack_require__(/*! ./keys */ \"../node_modules/lodash/keys.js\");\n\n/**\n * Creates an array of own enumerable property names and symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeys(object) {\n return baseGetAllKeys(object, keys, getSymbols);\n}\n\nmodule.exports = getAllKeys;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_getAllKeys.js?");
/***/ }),
/***/ "../node_modules/lodash/_getAllKeysIn.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_getAllKeysIn.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseGetAllKeys = __webpack_require__(/*! ./_baseGetAllKeys */ \"../node_modules/lodash/_baseGetAllKeys.js\"),\n getSymbolsIn = __webpack_require__(/*! ./_getSymbolsIn */ \"../node_modules/lodash/_getSymbolsIn.js\"),\n keysIn = __webpack_require__(/*! ./keysIn */ \"../node_modules/lodash/keysIn.js\");\n\n/**\n * Creates an array of own and inherited enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeysIn(object) {\n return baseGetAllKeys(object, keysIn, getSymbolsIn);\n}\n\nmodule.exports = getAllKeysIn;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_getAllKeysIn.js?");
/***/ }),
/***/ "../node_modules/lodash/_getMapData.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_getMapData.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var isKeyable = __webpack_require__(/*! ./_isKeyable */ \"../node_modules/lodash/_isKeyable.js\");\n\n/**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n var data = map.__data__;\n return isKeyable(key)\n ? data[typeof key == 'string' ? 'string' : 'hash']\n : data.map;\n}\n\nmodule.exports = getMapData;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_getMapData.js?");
/***/ }),
/***/ "../node_modules/lodash/_getNative.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_getNative.js ***!
\********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseIsNative = __webpack_require__(/*! ./_baseIsNative */ \"../node_modules/lodash/_baseIsNative.js\"),\n getValue = __webpack_require__(/*! ./_getValue */ \"../node_modules/lodash/_getValue.js\");\n\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n var value = getValue(object, key);\n return baseIsNative(value) ? value : undefined;\n}\n\nmodule.exports = getNative;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_getNative.js?");
/***/ }),
/***/ "../node_modules/lodash/_getPrototype.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_getPrototype.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var overArg = __webpack_require__(/*! ./_overArg */ \"../node_modules/lodash/_overArg.js\");\n\n/** Built-in value references. */\nvar getPrototype = overArg(Object.getPrototypeOf, Object);\n\nmodule.exports = getPrototype;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_getPrototype.js?");
/***/ }),
/***/ "../node_modules/lodash/_getRawTag.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_getRawTag.js ***!
\********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var Symbol = __webpack_require__(/*! ./_Symbol */ \"../node_modules/lodash/_Symbol.js\");\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\nmodule.exports = getRawTag;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_getRawTag.js?");
/***/ }),
/***/ "../node_modules/lodash/_getSymbols.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_getSymbols.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var arrayFilter = __webpack_require__(/*! ./_arrayFilter */ \"../node_modules/lodash/_arrayFilter.js\"),\n stubArray = __webpack_require__(/*! ./stubArray */ \"../node_modules/lodash/stubArray.js\");\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols;\n\n/**\n * Creates an array of the own enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbols = !nativeGetSymbols ? stubArray : function(object) {\n if (object == null) {\n return [];\n }\n object = Object(object);\n return arrayFilter(nativeGetSymbols(object), function(symbol) {\n return propertyIsEnumerable.call(object, symbol);\n });\n};\n\nmodule.exports = getSymbols;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_getSymbols.js?");
/***/ }),
/***/ "../node_modules/lodash/_getSymbolsIn.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_getSymbolsIn.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var arrayPush = __webpack_require__(/*! ./_arrayPush */ \"../node_modules/lodash/_arrayPush.js\"),\n getPrototype = __webpack_require__(/*! ./_getPrototype */ \"../node_modules/lodash/_getPrototype.js\"),\n getSymbols = __webpack_require__(/*! ./_getSymbols */ \"../node_modules/lodash/_getSymbols.js\"),\n stubArray = __webpack_require__(/*! ./stubArray */ \"../node_modules/lodash/stubArray.js\");\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols;\n\n/**\n * Creates an array of the own and inherited enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {\n var result = [];\n while (object) {\n arrayPush(result, getSymbols(object));\n object = getPrototype(object);\n }\n return result;\n};\n\nmodule.exports = getSymbolsIn;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_getSymbolsIn.js?");
/***/ }),
/***/ "../node_modules/lodash/_getTag.js":
/*!*****************************************!*\
!*** ../node_modules/lodash/_getTag.js ***!
\*****************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var DataView = __webpack_require__(/*! ./_DataView */ \"../node_modules/lodash/_DataView.js\"),\n Map = __webpack_require__(/*! ./_Map */ \"../node_modules/lodash/_Map.js\"),\n Promise = __webpack_require__(/*! ./_Promise */ \"../node_modules/lodash/_Promise.js\"),\n Set = __webpack_require__(/*! ./_Set */ \"../node_modules/lodash/_Set.js\"),\n WeakMap = __webpack_require__(/*! ./_WeakMap */ \"../node_modules/lodash/_WeakMap.js\"),\n baseGetTag = __webpack_require__(/*! ./_baseGetTag */ \"../node_modules/lodash/_baseGetTag.js\"),\n toSource = __webpack_require__(/*! ./_toSource */ \"../node_modules/lodash/_toSource.js\");\n\n/** `Object#toString` result references. */\nvar mapTag = '[object Map]',\n objectTag = '[object Object]',\n promiseTag = '[object Promise]',\n setTag = '[object Set]',\n weakMapTag = '[object WeakMap]';\n\nvar dataViewTag = '[object DataView]';\n\n/** Used to detect maps, sets, and weakmaps. */\nvar dataViewCtorString = toSource(DataView),\n mapCtorString = toSource(Map),\n promiseCtorString = toSource(Promise),\n setCtorString = toSource(Set),\n weakMapCtorString = toSource(WeakMap);\n\n/**\n * Gets the `toStringTag` of `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nvar getTag = baseGetTag;\n\n// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.\nif ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||\n (Map && getTag(new Map) != mapTag) ||\n (Promise && getTag(Promise.resolve()) != promiseTag) ||\n (Set && getTag(new Set) != setTag) ||\n (WeakMap && getTag(new WeakMap) != weakMapTag)) {\n getTag = function(value) {\n var result = baseGetTag(value),\n Ctor = result == objectTag ? value.constructor : undefined,\n ctorString = Ctor ? toSource(Ctor) : '';\n\n if (ctorString) {\n switch (ctorString) {\n case dataViewCtorString: return dataViewTag;\n case mapCtorString: return mapTag;\n case promiseCtorString: return promiseTag;\n case setCtorString: return setTag;\n case weakMapCtorString: return weakMapTag;\n }\n }\n return result;\n };\n}\n\nmodule.exports = getTag;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_getTag.js?");
/***/ }),
/***/ "../node_modules/lodash/_getValue.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_getValue.js ***!
\*******************************************/
/***/ ((module) => {
eval("/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nmodule.exports = getValue;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_getValue.js?");
/***/ }),
/***/ "../node_modules/lodash/_hasPath.js":
/*!******************************************!*\
!*** ../node_modules/lodash/_hasPath.js ***!
\******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var castPath = __webpack_require__(/*! ./_castPath */ \"../node_modules/lodash/_castPath.js\"),\n isArguments = __webpack_require__(/*! ./isArguments */ \"../node_modules/lodash/isArguments.js\"),\n isArray = __webpack_require__(/*! ./isArray */ \"../node_modules/lodash/isArray.js\"),\n isIndex = __webpack_require__(/*! ./_isIndex */ \"../node_modules/lodash/_isIndex.js\"),\n isLength = __webpack_require__(/*! ./isLength */ \"../node_modules/lodash/isLength.js\"),\n toKey = __webpack_require__(/*! ./_toKey */ \"../node_modules/lodash/_toKey.js\");\n\n/**\n * Checks if `path` exists on `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Array|string} path The path to check.\n * @param {Function} hasFunc The function to check properties.\n * @returns {boolean} Returns `true` if `path` exists, else `false`.\n */\nfunction hasPath(object, path, hasFunc) {\n path = castPath(path, object);\n\n var index = -1,\n length = path.length,\n result = false;\n\n while (++index < length) {\n var key = toKey(path[index]);\n if (!(result = object != null && hasFunc(object, key))) {\n break;\n }\n object = object[key];\n }\n if (result || ++index != length) {\n return result;\n }\n length = object == null ? 0 : object.length;\n return !!length && isLength(length) && isIndex(key, length) &&\n (isArray(object) || isArguments(object));\n}\n\nmodule.exports = hasPath;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_hasPath.js?");
/***/ }),
/***/ "../node_modules/lodash/_hasUnicode.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_hasUnicode.js ***!
\*********************************************/
/***/ ((module) => {
eval("/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n return reHasUnicode.test(string);\n}\n\nmodule.exports = hasUnicode;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_hasUnicode.js?");
/***/ }),
/***/ "../node_modules/lodash/_hasUnicodeWord.js":
/*!*************************************************!*\
!*** ../node_modules/lodash/_hasUnicodeWord.js ***!
\*************************************************/
/***/ ((module) => {
eval("/** Used to detect strings that need a more robust regexp to match words. */\nvar reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;\n\n/**\n * Checks if `string` contains a word composed of Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a word is found, else `false`.\n */\nfunction hasUnicodeWord(string) {\n return reHasUnicodeWord.test(string);\n}\n\nmodule.exports = hasUnicodeWord;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_hasUnicodeWord.js?");
/***/ }),
/***/ "../node_modules/lodash/_hashClear.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_hashClear.js ***!
\********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var nativeCreate = __webpack_require__(/*! ./_nativeCreate */ \"../node_modules/lodash/_nativeCreate.js\");\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n this.__data__ = nativeCreate ? nativeCreate(null) : {};\n this.size = 0;\n}\n\nmodule.exports = hashClear;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_hashClear.js?");
/***/ }),
/***/ "../node_modules/lodash/_hashDelete.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_hashDelete.js ***!
\*********************************************/
/***/ ((module) => {
eval("/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nmodule.exports = hashDelete;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_hashDelete.js?");
/***/ }),
/***/ "../node_modules/lodash/_hashGet.js":
/*!******************************************!*\
!*** ../node_modules/lodash/_hashGet.js ***!
\******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var nativeCreate = __webpack_require__(/*! ./_nativeCreate */ \"../node_modules/lodash/_nativeCreate.js\");\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n var data = this.__data__;\n if (nativeCreate) {\n var result = data[key];\n return result === HASH_UNDEFINED ? undefined : result;\n }\n return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\nmodule.exports = hashGet;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_hashGet.js?");
/***/ }),
/***/ "../node_modules/lodash/_hashHas.js":
/*!******************************************!*\
!*** ../node_modules/lodash/_hashHas.js ***!
\******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var nativeCreate = __webpack_require__(/*! ./_nativeCreate */ \"../node_modules/lodash/_nativeCreate.js\");\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction hashHas(key) {\n var data = this.__data__;\n return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);\n}\n\nmodule.exports = hashHas;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_hashHas.js?");
/***/ }),
/***/ "../node_modules/lodash/_hashSet.js":
/*!******************************************!*\
!*** ../node_modules/lodash/_hashSet.js ***!
\******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var nativeCreate = __webpack_require__(/*! ./_nativeCreate */ \"../node_modules/lodash/_nativeCreate.js\");\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n var data = this.__data__;\n this.size += this.has(key) ? 0 : 1;\n data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n return this;\n}\n\nmodule.exports = hashSet;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_hashSet.js?");
/***/ }),
/***/ "../node_modules/lodash/_initCloneArray.js":
/*!*************************************************!*\
!*** ../node_modules/lodash/_initCloneArray.js ***!
\*************************************************/
/***/ ((module) => {
eval("/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Initializes an array clone.\n *\n * @private\n * @param {Array} array The array to clone.\n * @returns {Array} Returns the initialized clone.\n */\nfunction initCloneArray(array) {\n var length = array.length,\n result = new array.constructor(length);\n\n // Add properties assigned by `RegExp#exec`.\n if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {\n result.index = array.index;\n result.input = array.input;\n }\n return result;\n}\n\nmodule.exports = initCloneArray;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_initCloneArray.js?");
/***/ }),
/***/ "../node_modules/lodash/_initCloneByTag.js":
/*!*************************************************!*\
!*** ../node_modules/lodash/_initCloneByTag.js ***!
\*************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var cloneArrayBuffer = __webpack_require__(/*! ./_cloneArrayBuffer */ \"../node_modules/lodash/_cloneArrayBuffer.js\"),\n cloneDataView = __webpack_require__(/*! ./_cloneDataView */ \"../node_modules/lodash/_cloneDataView.js\"),\n cloneRegExp = __webpack_require__(/*! ./_cloneRegExp */ \"../node_modules/lodash/_cloneRegExp.js\"),\n cloneSymbol = __webpack_require__(/*! ./_cloneSymbol */ \"../node_modules/lodash/_cloneSymbol.js\"),\n cloneTypedArray = __webpack_require__(/*! ./_cloneTypedArray */ \"../node_modules/lodash/_cloneTypedArray.js\");\n\n/** `Object#toString` result references. */\nvar boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/**\n * Initializes an object clone based on its `toStringTag`.\n *\n * **Note:** This function only supports cloning values with tags of\n * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.\n *\n * @private\n * @param {Object} object The object to clone.\n * @param {string} tag The `toStringTag` of the object to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneByTag(object, tag, isDeep) {\n var Ctor = object.constructor;\n switch (tag) {\n case arrayBufferTag:\n return cloneArrayBuffer(object);\n\n case boolTag:\n case dateTag:\n return new Ctor(+object);\n\n case dataViewTag:\n return cloneDataView(object, isDeep);\n\n case float32Tag: case float64Tag:\n case int8Tag: case int16Tag: case int32Tag:\n case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:\n return cloneTypedArray(object, isDeep);\n\n case mapTag:\n return new Ctor;\n\n case numberTag:\n case stringTag:\n return new Ctor(object);\n\n case regexpTag:\n return cloneRegExp(object);\n\n case setTag:\n return new Ctor;\n\n case symbolTag:\n return cloneSymbol(object);\n }\n}\n\nmodule.exports = initCloneByTag;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_initCloneByTag.js?");
/***/ }),
/***/ "../node_modules/lodash/_initCloneObject.js":
/*!**************************************************!*\
!*** ../node_modules/lodash/_initCloneObject.js ***!
\**************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseCreate = __webpack_require__(/*! ./_baseCreate */ \"../node_modules/lodash/_baseCreate.js\"),\n getPrototype = __webpack_require__(/*! ./_getPrototype */ \"../node_modules/lodash/_getPrototype.js\"),\n isPrototype = __webpack_require__(/*! ./_isPrototype */ \"../node_modules/lodash/_isPrototype.js\");\n\n/**\n * Initializes an object clone.\n *\n * @private\n * @param {Object} object The object to clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneObject(object) {\n return (typeof object.constructor == 'function' && !isPrototype(object))\n ? baseCreate(getPrototype(object))\n : {};\n}\n\nmodule.exports = initCloneObject;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_initCloneObject.js?");
/***/ }),
/***/ "../node_modules/lodash/_isFlattenable.js":
/*!************************************************!*\
!*** ../node_modules/lodash/_isFlattenable.js ***!
\************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var Symbol = __webpack_require__(/*! ./_Symbol */ \"../node_modules/lodash/_Symbol.js\"),\n isArguments = __webpack_require__(/*! ./isArguments */ \"../node_modules/lodash/isArguments.js\"),\n isArray = __webpack_require__(/*! ./isArray */ \"../node_modules/lodash/isArray.js\");\n\n/** Built-in value references. */\nvar spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined;\n\n/**\n * Checks if `value` is a flattenable `arguments` object or array.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.\n */\nfunction isFlattenable(value) {\n return isArray(value) || isArguments(value) ||\n !!(spreadableSymbol && value && value[spreadableSymbol]);\n}\n\nmodule.exports = isFlattenable;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_isFlattenable.js?");
/***/ }),
/***/ "../node_modules/lodash/_isIndex.js":
/*!******************************************!*\
!*** ../node_modules/lodash/_isIndex.js ***!
\******************************************/
/***/ ((module) => {
eval("/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nmodule.exports = isIndex;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_isIndex.js?");
/***/ }),
/***/ "../node_modules/lodash/_isKey.js":
/*!****************************************!*\
!*** ../node_modules/lodash/_isKey.js ***!
\****************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var isArray = __webpack_require__(/*! ./isArray */ \"../node_modules/lodash/isArray.js\"),\n isSymbol = __webpack_require__(/*! ./isSymbol */ \"../node_modules/lodash/isSymbol.js\");\n\n/** Used to match property names within property paths. */\nvar reIsDeepProp = /\\.|\\[(?:[^[\\]]*|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*?\\1)\\]/,\n reIsPlainProp = /^\\w*$/;\n\n/**\n * Checks if `value` is a property name and not a property path.\n *\n * @private\n * @param {*} value The value to check.\n * @param {Object} [object] The object to query keys on.\n * @returns {boolean} Returns `true` if `value` is a property name, else `false`.\n */\nfunction isKey(value, object) {\n if (isArray(value)) {\n return false;\n }\n var type = typeof value;\n if (type == 'number' || type == 'symbol' || type == 'boolean' ||\n value == null || isSymbol(value)) {\n return true;\n }\n return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||\n (object != null && value in Object(object));\n}\n\nmodule.exports = isKey;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_isKey.js?");
/***/ }),
/***/ "../node_modules/lodash/_isKeyable.js":
/*!********************************************!*\
!*** ../node_modules/lodash/_isKeyable.js ***!
\********************************************/
/***/ ((module) => {
eval("/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nmodule.exports = isKeyable;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_isKeyable.js?");
/***/ }),
/***/ "../node_modules/lodash/_isMasked.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_isMasked.js ***!
\*******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var coreJsData = __webpack_require__(/*! ./_coreJsData */ \"../node_modules/lodash/_coreJsData.js\");\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n return !!maskSrcKey && (maskSrcKey in func);\n}\n\nmodule.exports = isMasked;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_isMasked.js?");
/***/ }),
/***/ "../node_modules/lodash/_isPrototype.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_isPrototype.js ***!
\**********************************************/
/***/ ((module) => {
eval("/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nmodule.exports = isPrototype;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_isPrototype.js?");
/***/ }),
/***/ "../node_modules/lodash/_listCacheClear.js":
/*!*************************************************!*\
!*** ../node_modules/lodash/_listCacheClear.js ***!
\*************************************************/
/***/ ((module) => {
eval("/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nmodule.exports = listCacheClear;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_listCacheClear.js?");
/***/ }),
/***/ "../node_modules/lodash/_listCacheDelete.js":
/*!**************************************************!*\
!*** ../node_modules/lodash/_listCacheDelete.js ***!
\**************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var assocIndexOf = __webpack_require__(/*! ./_assocIndexOf */ \"../node_modules/lodash/_assocIndexOf.js\");\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype;\n\n/** Built-in value references. */\nvar splice = arrayProto.splice;\n\n/**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction listCacheDelete(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n return false;\n }\n var lastIndex = data.length - 1;\n if (index == lastIndex) {\n data.pop();\n } else {\n splice.call(data, index, 1);\n }\n --this.size;\n return true;\n}\n\nmodule.exports = listCacheDelete;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_listCacheDelete.js?");
/***/ }),
/***/ "../node_modules/lodash/_listCacheGet.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_listCacheGet.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var assocIndexOf = __webpack_require__(/*! ./_assocIndexOf */ \"../node_modules/lodash/_assocIndexOf.js\");\n\n/**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n return index < 0 ? undefined : data[index][1];\n}\n\nmodule.exports = listCacheGet;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_listCacheGet.js?");
/***/ }),
/***/ "../node_modules/lodash/_listCacheHas.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_listCacheHas.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var assocIndexOf = __webpack_require__(/*! ./_assocIndexOf */ \"../node_modules/lodash/_assocIndexOf.js\");\n\n/**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction listCacheHas(key) {\n return assocIndexOf(this.__data__, key) > -1;\n}\n\nmodule.exports = listCacheHas;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_listCacheHas.js?");
/***/ }),
/***/ "../node_modules/lodash/_listCacheSet.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_listCacheSet.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var assocIndexOf = __webpack_require__(/*! ./_assocIndexOf */ \"../node_modules/lodash/_assocIndexOf.js\");\n\n/**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n ++this.size;\n data.push([key, value]);\n } else {\n data[index][1] = value;\n }\n return this;\n}\n\nmodule.exports = listCacheSet;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_listCacheSet.js?");
/***/ }),
/***/ "../node_modules/lodash/_mapCacheClear.js":
/*!************************************************!*\
!*** ../node_modules/lodash/_mapCacheClear.js ***!
\************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var Hash = __webpack_require__(/*! ./_Hash */ \"../node_modules/lodash/_Hash.js\"),\n ListCache = __webpack_require__(/*! ./_ListCache */ \"../node_modules/lodash/_ListCache.js\"),\n Map = __webpack_require__(/*! ./_Map */ \"../node_modules/lodash/_Map.js\");\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n this.size = 0;\n this.__data__ = {\n 'hash': new Hash,\n 'map': new (Map || ListCache),\n 'string': new Hash\n };\n}\n\nmodule.exports = mapCacheClear;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_mapCacheClear.js?");
/***/ }),
/***/ "../node_modules/lodash/_mapCacheDelete.js":
/*!*************************************************!*\
!*** ../node_modules/lodash/_mapCacheDelete.js ***!
\*************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var getMapData = __webpack_require__(/*! ./_getMapData */ \"../node_modules/lodash/_getMapData.js\");\n\n/**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction mapCacheDelete(key) {\n var result = getMapData(this, key)['delete'](key);\n this.size -= result ? 1 : 0;\n return result;\n}\n\nmodule.exports = mapCacheDelete;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_mapCacheDelete.js?");
/***/ }),
/***/ "../node_modules/lodash/_mapCacheGet.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_mapCacheGet.js ***!
\**********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var getMapData = __webpack_require__(/*! ./_getMapData */ \"../node_modules/lodash/_getMapData.js\");\n\n/**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n return getMapData(this, key).get(key);\n}\n\nmodule.exports = mapCacheGet;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_mapCacheGet.js?");
/***/ }),
/***/ "../node_modules/lodash/_mapCacheHas.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_mapCacheHas.js ***!
\**********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var getMapData = __webpack_require__(/*! ./_getMapData */ \"../node_modules/lodash/_getMapData.js\");\n\n/**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction mapCacheHas(key) {\n return getMapData(this, key).has(key);\n}\n\nmodule.exports = mapCacheHas;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_mapCacheHas.js?");
/***/ }),
/***/ "../node_modules/lodash/_mapCacheSet.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_mapCacheSet.js ***!
\**********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var getMapData = __webpack_require__(/*! ./_getMapData */ \"../node_modules/lodash/_getMapData.js\");\n\n/**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n var data = getMapData(this, key),\n size = data.size;\n\n data.set(key, value);\n this.size += data.size == size ? 0 : 1;\n return this;\n}\n\nmodule.exports = mapCacheSet;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_mapCacheSet.js?");
/***/ }),
/***/ "../node_modules/lodash/_memoizeCapped.js":
/*!************************************************!*\
!*** ../node_modules/lodash/_memoizeCapped.js ***!
\************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var memoize = __webpack_require__(/*! ./memoize */ \"../node_modules/lodash/memoize.js\");\n\n/** Used as the maximum memoize cache size. */\nvar MAX_MEMOIZE_SIZE = 500;\n\n/**\n * A specialized version of `_.memoize` which clears the memoized function's\n * cache when it exceeds `MAX_MEMOIZE_SIZE`.\n *\n * @private\n * @param {Function} func The function to have its output memoized.\n * @returns {Function} Returns the new memoized function.\n */\nfunction memoizeCapped(func) {\n var result = memoize(func, function(key) {\n if (cache.size === MAX_MEMOIZE_SIZE) {\n cache.clear();\n }\n return key;\n });\n\n var cache = result.cache;\n return result;\n}\n\nmodule.exports = memoizeCapped;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_memoizeCapped.js?");
/***/ }),
/***/ "../node_modules/lodash/_nativeCreate.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_nativeCreate.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var getNative = __webpack_require__(/*! ./_getNative */ \"../node_modules/lodash/_getNative.js\");\n\n/* Built-in method references that are verified to be native. */\nvar nativeCreate = getNative(Object, 'create');\n\nmodule.exports = nativeCreate;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_nativeCreate.js?");
/***/ }),
/***/ "../node_modules/lodash/_nativeKeys.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_nativeKeys.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var overArg = __webpack_require__(/*! ./_overArg */ \"../node_modules/lodash/_overArg.js\");\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeKeys = overArg(Object.keys, Object);\n\nmodule.exports = nativeKeys;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_nativeKeys.js?");
/***/ }),
/***/ "../node_modules/lodash/_nativeKeysIn.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_nativeKeysIn.js ***!
\***********************************************/
/***/ ((module) => {
eval("/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nmodule.exports = nativeKeysIn;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_nativeKeysIn.js?");
/***/ }),
/***/ "../node_modules/lodash/_nodeUtil.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_nodeUtil.js ***!
\*******************************************/
/***/ ((module, exports, __webpack_require__) => {
eval("/* module decorator */ module = __webpack_require__.nmd(module);\nvar freeGlobal = __webpack_require__(/*! ./_freeGlobal */ \"../node_modules/lodash/_freeGlobal.js\");\n\n/** Detect free variable `exports`. */\nvar freeExports = true && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && \"object\" == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Detect free variable `process` from Node.js. */\nvar freeProcess = moduleExports && freeGlobal.process;\n\n/** Used to access faster Node.js helpers. */\nvar nodeUtil = (function() {\n try {\n // Use `util.types` for Node.js 10+.\n var types = freeModule && freeModule.require && freeModule.require('util').types;\n\n if (types) {\n return types;\n }\n\n // Legacy `process.binding('util')` for Node.js < 10.\n return freeProcess && freeProcess.binding && freeProcess.binding('util');\n } catch (e) {}\n}());\n\nmodule.exports = nodeUtil;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_nodeUtil.js?");
/***/ }),
/***/ "../node_modules/lodash/_objectToString.js":
/*!*************************************************!*\
!*** ../node_modules/lodash/_objectToString.js ***!
\*************************************************/
/***/ ((module) => {
eval("/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nmodule.exports = objectToString;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_objectToString.js?");
/***/ }),
/***/ "../node_modules/lodash/_overArg.js":
/*!******************************************!*\
!*** ../node_modules/lodash/_overArg.js ***!
\******************************************/
/***/ ((module) => {
eval("/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nmodule.exports = overArg;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_overArg.js?");
/***/ }),
/***/ "../node_modules/lodash/_overRest.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_overRest.js ***!
\*******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var apply = __webpack_require__(/*! ./_apply */ \"../node_modules/lodash/_apply.js\");\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max;\n\n/**\n * A specialized version of `baseRest` which transforms the rest array.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @param {number} [start=func.length-1] The start position of the rest parameter.\n * @param {Function} transform The rest array transform.\n * @returns {Function} Returns the new function.\n */\nfunction overRest(func, start, transform) {\n start = nativeMax(start === undefined ? (func.length - 1) : start, 0);\n return function() {\n var args = arguments,\n index = -1,\n length = nativeMax(args.length - start, 0),\n array = Array(length);\n\n while (++index < length) {\n array[index] = args[start + index];\n }\n index = -1;\n var otherArgs = Array(start + 1);\n while (++index < start) {\n otherArgs[index] = args[index];\n }\n otherArgs[start] = transform(array);\n return apply(func, this, otherArgs);\n };\n}\n\nmodule.exports = overRest;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_overRest.js?");
/***/ }),
/***/ "../node_modules/lodash/_parent.js":
/*!*****************************************!*\
!*** ../node_modules/lodash/_parent.js ***!
\*****************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseGet = __webpack_require__(/*! ./_baseGet */ \"../node_modules/lodash/_baseGet.js\"),\n baseSlice = __webpack_require__(/*! ./_baseSlice */ \"../node_modules/lodash/_baseSlice.js\");\n\n/**\n * Gets the parent value at `path` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Array} path The path to get the parent value of.\n * @returns {*} Returns the parent value.\n */\nfunction parent(object, path) {\n return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));\n}\n\nmodule.exports = parent;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_parent.js?");
/***/ }),
/***/ "../node_modules/lodash/_root.js":
/*!***************************************!*\
!*** ../node_modules/lodash/_root.js ***!
\***************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var freeGlobal = __webpack_require__(/*! ./_freeGlobal */ \"../node_modules/lodash/_freeGlobal.js\");\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nmodule.exports = root;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_root.js?");
/***/ }),
/***/ "../node_modules/lodash/_setToString.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_setToString.js ***!
\**********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseSetToString = __webpack_require__(/*! ./_baseSetToString */ \"../node_modules/lodash/_baseSetToString.js\"),\n shortOut = __webpack_require__(/*! ./_shortOut */ \"../node_modules/lodash/_shortOut.js\");\n\n/**\n * Sets the `toString` method of `func` to return `string`.\n *\n * @private\n * @param {Function} func The function to modify.\n * @param {Function} string The `toString` result.\n * @returns {Function} Returns `func`.\n */\nvar setToString = shortOut(baseSetToString);\n\nmodule.exports = setToString;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_setToString.js?");
/***/ }),
/***/ "../node_modules/lodash/_shortOut.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_shortOut.js ***!
\*******************************************/
/***/ ((module) => {
eval("/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nmodule.exports = shortOut;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_shortOut.js?");
/***/ }),
/***/ "../node_modules/lodash/_stackClear.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/_stackClear.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var ListCache = __webpack_require__(/*! ./_ListCache */ \"../node_modules/lodash/_ListCache.js\");\n\n/**\n * Removes all key-value entries from the stack.\n *\n * @private\n * @name clear\n * @memberOf Stack\n */\nfunction stackClear() {\n this.__data__ = new ListCache;\n this.size = 0;\n}\n\nmodule.exports = stackClear;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_stackClear.js?");
/***/ }),
/***/ "../node_modules/lodash/_stackDelete.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/_stackDelete.js ***!
\**********************************************/
/***/ ((module) => {
eval("/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nmodule.exports = stackDelete;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_stackDelete.js?");
/***/ }),
/***/ "../node_modules/lodash/_stackGet.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_stackGet.js ***!
\*******************************************/
/***/ ((module) => {
eval("/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nmodule.exports = stackGet;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_stackGet.js?");
/***/ }),
/***/ "../node_modules/lodash/_stackHas.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_stackHas.js ***!
\*******************************************/
/***/ ((module) => {
eval("/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nmodule.exports = stackHas;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_stackHas.js?");
/***/ }),
/***/ "../node_modules/lodash/_stackSet.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_stackSet.js ***!
\*******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var ListCache = __webpack_require__(/*! ./_ListCache */ \"../node_modules/lodash/_ListCache.js\"),\n Map = __webpack_require__(/*! ./_Map */ \"../node_modules/lodash/_Map.js\"),\n MapCache = __webpack_require__(/*! ./_MapCache */ \"../node_modules/lodash/_MapCache.js\");\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/**\n * Sets the stack `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Stack\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the stack cache instance.\n */\nfunction stackSet(key, value) {\n var data = this.__data__;\n if (data instanceof ListCache) {\n var pairs = data.__data__;\n if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {\n pairs.push([key, value]);\n this.size = ++data.size;\n return this;\n }\n data = this.__data__ = new MapCache(pairs);\n }\n data.set(key, value);\n this.size = data.size;\n return this;\n}\n\nmodule.exports = stackSet;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_stackSet.js?");
/***/ }),
/***/ "../node_modules/lodash/_stringToArray.js":
/*!************************************************!*\
!*** ../node_modules/lodash/_stringToArray.js ***!
\************************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var asciiToArray = __webpack_require__(/*! ./_asciiToArray */ \"../node_modules/lodash/_asciiToArray.js\"),\n hasUnicode = __webpack_require__(/*! ./_hasUnicode */ \"../node_modules/lodash/_hasUnicode.js\"),\n unicodeToArray = __webpack_require__(/*! ./_unicodeToArray */ \"../node_modules/lodash/_unicodeToArray.js\");\n\n/**\n * Converts `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction stringToArray(string) {\n return hasUnicode(string)\n ? unicodeToArray(string)\n : asciiToArray(string);\n}\n\nmodule.exports = stringToArray;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_stringToArray.js?");
/***/ }),
/***/ "../node_modules/lodash/_stringToPath.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_stringToPath.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var memoizeCapped = __webpack_require__(/*! ./_memoizeCapped */ \"../node_modules/lodash/_memoizeCapped.js\");\n\n/** Used to match property names within property paths. */\nvar rePropName = /[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g;\n\n/** Used to match backslashes in property paths. */\nvar reEscapeChar = /\\\\(\\\\)?/g;\n\n/**\n * Converts `string` to a property path array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the property path array.\n */\nvar stringToPath = memoizeCapped(function(string) {\n var result = [];\n if (string.charCodeAt(0) === 46 /* . */) {\n result.push('');\n }\n string.replace(rePropName, function(match, number, quote, subString) {\n result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match));\n });\n return result;\n});\n\nmodule.exports = stringToPath;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_stringToPath.js?");
/***/ }),
/***/ "../node_modules/lodash/_toKey.js":
/*!****************************************!*\
!*** ../node_modules/lodash/_toKey.js ***!
\****************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var isSymbol = __webpack_require__(/*! ./isSymbol */ \"../node_modules/lodash/isSymbol.js\");\n\n/** Used as references for various `Number` constants. */\nvar INFINITY = 1 / 0;\n\n/**\n * Converts `value` to a string key if it's not a string or symbol.\n *\n * @private\n * @param {*} value The value to inspect.\n * @returns {string|symbol} Returns the key.\n */\nfunction toKey(value) {\n if (typeof value == 'string' || isSymbol(value)) {\n return value;\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\nmodule.exports = toKey;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_toKey.js?");
/***/ }),
/***/ "../node_modules/lodash/_toSource.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/_toSource.js ***!
\*******************************************/
/***/ ((module) => {
eval("/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nmodule.exports = toSource;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_toSource.js?");
/***/ }),
/***/ "../node_modules/lodash/_unicodeToArray.js":
/*!*************************************************!*\
!*** ../node_modules/lodash/_unicodeToArray.js ***!
\*************************************************/
/***/ ((module) => {
eval("/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange + ']',\n rsCombo = '[' + rsComboRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n return string.match(reUnicode) || [];\n}\n\nmodule.exports = unicodeToArray;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_unicodeToArray.js?");
/***/ }),
/***/ "../node_modules/lodash/_unicodeWords.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/_unicodeWords.js ***!
\***********************************************/
/***/ ((module) => {
eval("/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsDingbatRange = '\\\\u2700-\\\\u27bf',\n rsLowerRange = 'a-z\\\\xdf-\\\\xf6\\\\xf8-\\\\xff',\n rsMathOpRange = '\\\\xac\\\\xb1\\\\xd7\\\\xf7',\n rsNonCharRange = '\\\\x00-\\\\x2f\\\\x3a-\\\\x40\\\\x5b-\\\\x60\\\\x7b-\\\\xbf',\n rsPunctuationRange = '\\\\u2000-\\\\u206f',\n rsSpaceRange = ' \\\\t\\\\x0b\\\\f\\\\xa0\\\\ufeff\\\\n\\\\r\\\\u2028\\\\u2029\\\\u1680\\\\u180e\\\\u2000\\\\u2001\\\\u2002\\\\u2003\\\\u2004\\\\u2005\\\\u2006\\\\u2007\\\\u2008\\\\u2009\\\\u200a\\\\u202f\\\\u205f\\\\u3000',\n rsUpperRange = 'A-Z\\\\xc0-\\\\xd6\\\\xd8-\\\\xde',\n rsVarRange = '\\\\ufe0e\\\\ufe0f',\n rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;\n\n/** Used to compose unicode capture groups. */\nvar rsApos = \"['\\u2019]\",\n rsBreak = '[' + rsBreakRange + ']',\n rsCombo = '[' + rsComboRange + ']',\n rsDigits = '\\\\d+',\n rsDingbat = '[' + rsDingbatRange + ']',\n rsLower = '[' + rsLowerRange + ']',\n rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsUpper = '[' + rsUpperRange + ']',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',\n rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',\n rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',\n rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',\n reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsOrdLower = '\\\\d*(?:1st|2nd|3rd|(?![123])\\\\dth)(?=\\\\b|[A-Z_])',\n rsOrdUpper = '\\\\d*(?:1ST|2ND|3RD|(?![123])\\\\dTH)(?=\\\\b|[a-z_])',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq;\n\n/** Used to match complex or compound words. */\nvar reUnicodeWord = RegExp([\n rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',\n rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')',\n rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,\n rsUpper + '+' + rsOptContrUpper,\n rsOrdUpper,\n rsOrdLower,\n rsDigits,\n rsEmoji\n].join('|'), 'g');\n\n/**\n * Splits a Unicode `string` into an array of its words.\n *\n * @private\n * @param {string} The string to inspect.\n * @returns {Array} Returns the words of `string`.\n */\nfunction unicodeWords(string) {\n return string.match(reUnicodeWord) || [];\n}\n\nmodule.exports = unicodeWords;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/_unicodeWords.js?");
/***/ }),
/***/ "../node_modules/lodash/camelCase.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/camelCase.js ***!
\*******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var capitalize = __webpack_require__(/*! ./capitalize */ \"../node_modules/lodash/capitalize.js\"),\n createCompounder = __webpack_require__(/*! ./_createCompounder */ \"../node_modules/lodash/_createCompounder.js\");\n\n/**\n * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the camel cased string.\n * @example\n *\n * _.camelCase('Foo Bar');\n * // => 'fooBar'\n *\n * _.camelCase('--foo-bar--');\n * // => 'fooBar'\n *\n * _.camelCase('__FOO_BAR__');\n * // => 'fooBar'\n */\nvar camelCase = createCompounder(function(result, word, index) {\n word = word.toLowerCase();\n return result + (index ? capitalize(word) : word);\n});\n\nmodule.exports = camelCase;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/camelCase.js?");
/***/ }),
/***/ "../node_modules/lodash/capitalize.js":
/*!********************************************!*\
!*** ../node_modules/lodash/capitalize.js ***!
\********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var toString = __webpack_require__(/*! ./toString */ \"../node_modules/lodash/toString.js\"),\n upperFirst = __webpack_require__(/*! ./upperFirst */ \"../node_modules/lodash/upperFirst.js\");\n\n/**\n * Converts the first character of `string` to upper case and the remaining\n * to lower case.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to capitalize.\n * @returns {string} Returns the capitalized string.\n * @example\n *\n * _.capitalize('FRED');\n * // => 'Fred'\n */\nfunction capitalize(string) {\n return upperFirst(toString(string).toLowerCase());\n}\n\nmodule.exports = capitalize;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/capitalize.js?");
/***/ }),
/***/ "../node_modules/lodash/castArray.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/castArray.js ***!
\*******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var isArray = __webpack_require__(/*! ./isArray */ \"../node_modules/lodash/isArray.js\");\n\n/**\n * Casts `value` as an array if it's not one.\n *\n * @static\n * @memberOf _\n * @since 4.4.0\n * @category Lang\n * @param {*} value The value to inspect.\n * @returns {Array} Returns the cast array.\n * @example\n *\n * _.castArray(1);\n * // => [1]\n *\n * _.castArray({ 'a': 1 });\n * // => [{ 'a': 1 }]\n *\n * _.castArray('abc');\n * // => ['abc']\n *\n * _.castArray(null);\n * // => [null]\n *\n * _.castArray(undefined);\n * // => [undefined]\n *\n * _.castArray();\n * // => []\n *\n * var array = [1, 2, 3];\n * console.log(_.castArray(array) === array);\n * // => true\n */\nfunction castArray() {\n if (!arguments.length) {\n return [];\n }\n var value = arguments[0];\n return isArray(value) ? value : [value];\n}\n\nmodule.exports = castArray;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/castArray.js?");
/***/ }),
/***/ "../node_modules/lodash/constant.js":
/*!******************************************!*\
!*** ../node_modules/lodash/constant.js ***!
\******************************************/
/***/ ((module) => {
eval("/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nmodule.exports = constant;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/constant.js?");
/***/ }),
/***/ "../node_modules/lodash/deburr.js":
/*!****************************************!*\
!*** ../node_modules/lodash/deburr.js ***!
\****************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var deburrLetter = __webpack_require__(/*! ./_deburrLetter */ \"../node_modules/lodash/_deburrLetter.js\"),\n toString = __webpack_require__(/*! ./toString */ \"../node_modules/lodash/toString.js\");\n\n/** Used to match Latin Unicode letters (excluding mathematical operators). */\nvar reLatin = /[\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\xff\\u0100-\\u017f]/g;\n\n/** Used to compose unicode character classes. */\nvar rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange;\n\n/** Used to compose unicode capture groups. */\nvar rsCombo = '[' + rsComboRange + ']';\n\n/**\n * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and\n * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).\n */\nvar reComboMark = RegExp(rsCombo, 'g');\n\n/**\n * Deburrs `string` by converting\n * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)\n * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)\n * letters to basic Latin letters and removing\n * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to deburr.\n * @returns {string} Returns the deburred string.\n * @example\n *\n * _.deburr('déjà vu');\n * // => 'deja vu'\n */\nfunction deburr(string) {\n string = toString(string);\n return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');\n}\n\nmodule.exports = deburr;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/deburr.js?");
/***/ }),
/***/ "../node_modules/lodash/eq.js":
/*!************************************!*\
!*** ../node_modules/lodash/eq.js ***!
\************************************/
/***/ ((module) => {
eval("/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nmodule.exports = eq;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/eq.js?");
/***/ }),
/***/ "../node_modules/lodash/flatten.js":
/*!*****************************************!*\
!*** ../node_modules/lodash/flatten.js ***!
\*****************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseFlatten = __webpack_require__(/*! ./_baseFlatten */ \"../node_modules/lodash/_baseFlatten.js\");\n\n/**\n * Flattens `array` a single level deep.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Array\n * @param {Array} array The array to flatten.\n * @returns {Array} Returns the new flattened array.\n * @example\n *\n * _.flatten([1, [2, [3, [4]], 5]]);\n * // => [1, 2, [3, [4]], 5]\n */\nfunction flatten(array) {\n var length = array == null ? 0 : array.length;\n return length ? baseFlatten(array, 1) : [];\n}\n\nmodule.exports = flatten;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/flatten.js?");
/***/ }),
/***/ "../node_modules/lodash/get.js":
/*!*************************************!*\
!*** ../node_modules/lodash/get.js ***!
\*************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseGet = __webpack_require__(/*! ./_baseGet */ \"../node_modules/lodash/_baseGet.js\");\n\n/**\n * Gets the value at `path` of `object`. If the resolved value is\n * `undefined`, the `defaultValue` is returned in its place.\n *\n * @static\n * @memberOf _\n * @since 3.7.0\n * @category Object\n * @param {Object} object The object to query.\n * @param {Array|string} path The path of the property to get.\n * @param {*} [defaultValue] The value returned for `undefined` resolved values.\n * @returns {*} Returns the resolved value.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 3 } }] };\n *\n * _.get(object, 'a[0].b.c');\n * // => 3\n *\n * _.get(object, ['a', '0', 'b', 'c']);\n * // => 3\n *\n * _.get(object, 'a.b.c', 'default');\n * // => 'default'\n */\nfunction get(object, path, defaultValue) {\n var result = object == null ? undefined : baseGet(object, path);\n return result === undefined ? defaultValue : result;\n}\n\nmodule.exports = get;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/get.js?");
/***/ }),
/***/ "../node_modules/lodash/hasIn.js":
/*!***************************************!*\
!*** ../node_modules/lodash/hasIn.js ***!
\***************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseHasIn = __webpack_require__(/*! ./_baseHasIn */ \"../node_modules/lodash/_baseHasIn.js\"),\n hasPath = __webpack_require__(/*! ./_hasPath */ \"../node_modules/lodash/_hasPath.js\");\n\n/**\n * Checks if `path` is a direct or inherited property of `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The object to query.\n * @param {Array|string} path The path to check.\n * @returns {boolean} Returns `true` if `path` exists, else `false`.\n * @example\n *\n * var object = _.create({ 'a': _.create({ 'b': 2 }) });\n *\n * _.hasIn(object, 'a');\n * // => true\n *\n * _.hasIn(object, 'a.b');\n * // => true\n *\n * _.hasIn(object, ['a', 'b']);\n * // => true\n *\n * _.hasIn(object, 'b');\n * // => false\n */\nfunction hasIn(object, path) {\n return object != null && hasPath(object, path, baseHasIn);\n}\n\nmodule.exports = hasIn;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/hasIn.js?");
/***/ }),
/***/ "../node_modules/lodash/identity.js":
/*!******************************************!*\
!*** ../node_modules/lodash/identity.js ***!
\******************************************/
/***/ ((module) => {
eval("/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nmodule.exports = identity;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/identity.js?");
/***/ }),
/***/ "../node_modules/lodash/isArguments.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/isArguments.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseIsArguments = __webpack_require__(/*! ./_baseIsArguments */ \"../node_modules/lodash/_baseIsArguments.js\"),\n isObjectLike = __webpack_require__(/*! ./isObjectLike */ \"../node_modules/lodash/isObjectLike.js\");\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n * else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nvar isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {\n return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&\n !propertyIsEnumerable.call(value, 'callee');\n};\n\nmodule.exports = isArguments;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isArguments.js?");
/***/ }),
/***/ "../node_modules/lodash/isArray.js":
/*!*****************************************!*\
!*** ../node_modules/lodash/isArray.js ***!
\*****************************************/
/***/ ((module) => {
eval("/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nmodule.exports = isArray;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isArray.js?");
/***/ }),
/***/ "../node_modules/lodash/isArrayLike.js":
/*!*********************************************!*\
!*** ../node_modules/lodash/isArrayLike.js ***!
\*********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var isFunction = __webpack_require__(/*! ./isFunction */ \"../node_modules/lodash/isFunction.js\"),\n isLength = __webpack_require__(/*! ./isLength */ \"../node_modules/lodash/isLength.js\");\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n return value != null && isLength(value.length) && !isFunction(value);\n}\n\nmodule.exports = isArrayLike;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isArrayLike.js?");
/***/ }),
/***/ "../node_modules/lodash/isBuffer.js":
/*!******************************************!*\
!*** ../node_modules/lodash/isBuffer.js ***!
\******************************************/
/***/ ((module, exports, __webpack_require__) => {
eval("/* module decorator */ module = __webpack_require__.nmd(module);\nvar root = __webpack_require__(/*! ./_root */ \"../node_modules/lodash/_root.js\"),\n stubFalse = __webpack_require__(/*! ./stubFalse */ \"../node_modules/lodash/stubFalse.js\");\n\n/** Detect free variable `exports`. */\nvar freeExports = true && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && \"object\" == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined;\n\n/**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n\nmodule.exports = isBuffer;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isBuffer.js?");
/***/ }),
/***/ "../node_modules/lodash/isElement.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/isElement.js ***!
\*******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var isObjectLike = __webpack_require__(/*! ./isObjectLike */ \"../node_modules/lodash/isObjectLike.js\"),\n isPlainObject = __webpack_require__(/*! ./isPlainObject */ \"../node_modules/lodash/isPlainObject.js\");\n\n/**\n * Checks if `value` is likely a DOM element.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.\n * @example\n *\n * _.isElement(document.body);\n * // => true\n *\n * _.isElement('<body>');\n * // => false\n */\nfunction isElement(value) {\n return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);\n}\n\nmodule.exports = isElement;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isElement.js?");
/***/ }),
/***/ "../node_modules/lodash/isEmpty.js":
/*!*****************************************!*\
!*** ../node_modules/lodash/isEmpty.js ***!
\*****************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseKeys = __webpack_require__(/*! ./_baseKeys */ \"../node_modules/lodash/_baseKeys.js\"),\n getTag = __webpack_require__(/*! ./_getTag */ \"../node_modules/lodash/_getTag.js\"),\n isArguments = __webpack_require__(/*! ./isArguments */ \"../node_modules/lodash/isArguments.js\"),\n isArray = __webpack_require__(/*! ./isArray */ \"../node_modules/lodash/isArray.js\"),\n isArrayLike = __webpack_require__(/*! ./isArrayLike */ \"../node_modules/lodash/isArrayLike.js\"),\n isBuffer = __webpack_require__(/*! ./isBuffer */ \"../node_modules/lodash/isBuffer.js\"),\n isPrototype = __webpack_require__(/*! ./_isPrototype */ \"../node_modules/lodash/_isPrototype.js\"),\n isTypedArray = __webpack_require__(/*! ./isTypedArray */ \"../node_modules/lodash/isTypedArray.js\");\n\n/** `Object#toString` result references. */\nvar mapTag = '[object Map]',\n setTag = '[object Set]';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Checks if `value` is an empty object, collection, map, or set.\n *\n * Objects are considered empty if they have no own enumerable string keyed\n * properties.\n *\n * Array-like values such as `arguments` objects, arrays, buffers, strings, or\n * jQuery-like collections are considered empty if they have a `length` of `0`.\n * Similarly, maps and sets are considered empty if they have a `size` of `0`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is empty, else `false`.\n * @example\n *\n * _.isEmpty(null);\n * // => true\n *\n * _.isEmpty(true);\n * // => true\n *\n * _.isEmpty(1);\n * // => true\n *\n * _.isEmpty([1, 2, 3]);\n * // => false\n *\n * _.isEmpty({ 'a': 1 });\n * // => false\n */\nfunction isEmpty(value) {\n if (value == null) {\n return true;\n }\n if (isArrayLike(value) &&\n (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' ||\n isBuffer(value) || isTypedArray(value) || isArguments(value))) {\n return !value.length;\n }\n var tag = getTag(value);\n if (tag == mapTag || tag == setTag) {\n return !value.size;\n }\n if (isPrototype(value)) {\n return !baseKeys(value).length;\n }\n for (var key in value) {\n if (hasOwnProperty.call(value, key)) {\n return false;\n }\n }\n return true;\n}\n\nmodule.exports = isEmpty;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isEmpty.js?");
/***/ }),
/***/ "../node_modules/lodash/isFunction.js":
/*!********************************************!*\
!*** ../node_modules/lodash/isFunction.js ***!
\********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseGetTag = __webpack_require__(/*! ./_baseGetTag */ \"../node_modules/lodash/_baseGetTag.js\"),\n isObject = __webpack_require__(/*! ./isObject */ \"../node_modules/lodash/isObject.js\");\n\n/** `Object#toString` result references. */\nvar asyncTag = '[object AsyncFunction]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n proxyTag = '[object Proxy]';\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n if (!isObject(value)) {\n return false;\n }\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 9 which returns 'object' for typed arrays and other constructors.\n var tag = baseGetTag(value);\n return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\n\nmodule.exports = isFunction;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isFunction.js?");
/***/ }),
/***/ "../node_modules/lodash/isLength.js":
/*!******************************************!*\
!*** ../node_modules/lodash/isLength.js ***!
\******************************************/
/***/ ((module) => {
eval("/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nmodule.exports = isLength;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isLength.js?");
/***/ }),
/***/ "../node_modules/lodash/isMap.js":
/*!***************************************!*\
!*** ../node_modules/lodash/isMap.js ***!
\***************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseIsMap = __webpack_require__(/*! ./_baseIsMap */ \"../node_modules/lodash/_baseIsMap.js\"),\n baseUnary = __webpack_require__(/*! ./_baseUnary */ \"../node_modules/lodash/_baseUnary.js\"),\n nodeUtil = __webpack_require__(/*! ./_nodeUtil */ \"../node_modules/lodash/_nodeUtil.js\");\n\n/* Node.js helper references. */\nvar nodeIsMap = nodeUtil && nodeUtil.isMap;\n\n/**\n * Checks if `value` is classified as a `Map` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a map, else `false`.\n * @example\n *\n * _.isMap(new Map);\n * // => true\n *\n * _.isMap(new WeakMap);\n * // => false\n */\nvar isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;\n\nmodule.exports = isMap;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isMap.js?");
/***/ }),
/***/ "../node_modules/lodash/isObject.js":
/*!******************************************!*\
!*** ../node_modules/lodash/isObject.js ***!
\******************************************/
/***/ ((module) => {
eval("/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nmodule.exports = isObject;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isObject.js?");
/***/ }),
/***/ "../node_modules/lodash/isObjectLike.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/isObjectLike.js ***!
\**********************************************/
/***/ ((module) => {
eval("/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nmodule.exports = isObjectLike;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isObjectLike.js?");
/***/ }),
/***/ "../node_modules/lodash/isPlainObject.js":
/*!***********************************************!*\
!*** ../node_modules/lodash/isPlainObject.js ***!
\***********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseGetTag = __webpack_require__(/*! ./_baseGetTag */ \"../node_modules/lodash/_baseGetTag.js\"),\n getPrototype = __webpack_require__(/*! ./_getPrototype */ \"../node_modules/lodash/_getPrototype.js\"),\n isObjectLike = __webpack_require__(/*! ./isObjectLike */ \"../node_modules/lodash/isObjectLike.js\");\n\n/** `Object#toString` result references. */\nvar objectTag = '[object Object]';\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to infer the `Object` constructor. */\nvar objectCtorString = funcToString.call(Object);\n\n/**\n * Checks if `value` is a plain object, that is, an object created by the\n * `Object` constructor or one with a `[[Prototype]]` of `null`.\n *\n * @static\n * @memberOf _\n * @since 0.8.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * }\n *\n * _.isPlainObject(new Foo);\n * // => false\n *\n * _.isPlainObject([1, 2, 3]);\n * // => false\n *\n * _.isPlainObject({ 'x': 0, 'y': 0 });\n * // => true\n *\n * _.isPlainObject(Object.create(null));\n * // => true\n */\nfunction isPlainObject(value) {\n if (!isObjectLike(value) || baseGetTag(value) != objectTag) {\n return false;\n }\n var proto = getPrototype(value);\n if (proto === null) {\n return true;\n }\n var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;\n return typeof Ctor == 'function' && Ctor instanceof Ctor &&\n funcToString.call(Ctor) == objectCtorString;\n}\n\nmodule.exports = isPlainObject;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isPlainObject.js?");
/***/ }),
/***/ "../node_modules/lodash/isSet.js":
/*!***************************************!*\
!*** ../node_modules/lodash/isSet.js ***!
\***************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseIsSet = __webpack_require__(/*! ./_baseIsSet */ \"../node_modules/lodash/_baseIsSet.js\"),\n baseUnary = __webpack_require__(/*! ./_baseUnary */ \"../node_modules/lodash/_baseUnary.js\"),\n nodeUtil = __webpack_require__(/*! ./_nodeUtil */ \"../node_modules/lodash/_nodeUtil.js\");\n\n/* Node.js helper references. */\nvar nodeIsSet = nodeUtil && nodeUtil.isSet;\n\n/**\n * Checks if `value` is classified as a `Set` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a set, else `false`.\n * @example\n *\n * _.isSet(new Set);\n * // => true\n *\n * _.isSet(new WeakSet);\n * // => false\n */\nvar isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;\n\nmodule.exports = isSet;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isSet.js?");
/***/ }),
/***/ "../node_modules/lodash/isString.js":
/*!******************************************!*\
!*** ../node_modules/lodash/isString.js ***!
\******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseGetTag = __webpack_require__(/*! ./_baseGetTag */ \"../node_modules/lodash/_baseGetTag.js\"),\n isArray = __webpack_require__(/*! ./isArray */ \"../node_modules/lodash/isArray.js\"),\n isObjectLike = __webpack_require__(/*! ./isObjectLike */ \"../node_modules/lodash/isObjectLike.js\");\n\n/** `Object#toString` result references. */\nvar stringTag = '[object String]';\n\n/**\n * Checks if `value` is classified as a `String` primitive or object.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a string, else `false`.\n * @example\n *\n * _.isString('abc');\n * // => true\n *\n * _.isString(1);\n * // => false\n */\nfunction isString(value) {\n return typeof value == 'string' ||\n (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);\n}\n\nmodule.exports = isString;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isString.js?");
/***/ }),
/***/ "../node_modules/lodash/isSymbol.js":
/*!******************************************!*\
!*** ../node_modules/lodash/isSymbol.js ***!
\******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseGetTag = __webpack_require__(/*! ./_baseGetTag */ \"../node_modules/lodash/_baseGetTag.js\"),\n isObjectLike = __webpack_require__(/*! ./isObjectLike */ \"../node_modules/lodash/isObjectLike.js\");\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && baseGetTag(value) == symbolTag);\n}\n\nmodule.exports = isSymbol;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isSymbol.js?");
/***/ }),
/***/ "../node_modules/lodash/isTypedArray.js":
/*!**********************************************!*\
!*** ../node_modules/lodash/isTypedArray.js ***!
\**********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseIsTypedArray = __webpack_require__(/*! ./_baseIsTypedArray */ \"../node_modules/lodash/_baseIsTypedArray.js\"),\n baseUnary = __webpack_require__(/*! ./_baseUnary */ \"../node_modules/lodash/_baseUnary.js\"),\n nodeUtil = __webpack_require__(/*! ./_nodeUtil */ \"../node_modules/lodash/_nodeUtil.js\");\n\n/* Node.js helper references. */\nvar nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;\n\n/**\n * Checks if `value` is classified as a typed array.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n * @example\n *\n * _.isTypedArray(new Uint8Array);\n * // => true\n *\n * _.isTypedArray([]);\n * // => false\n */\nvar isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;\n\nmodule.exports = isTypedArray;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/isTypedArray.js?");
/***/ }),
/***/ "../node_modules/lodash/keys.js":
/*!**************************************!*\
!*** ../node_modules/lodash/keys.js ***!
\**************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var arrayLikeKeys = __webpack_require__(/*! ./_arrayLikeKeys */ \"../node_modules/lodash/_arrayLikeKeys.js\"),\n baseKeys = __webpack_require__(/*! ./_baseKeys */ \"../node_modules/lodash/_baseKeys.js\"),\n isArrayLike = __webpack_require__(/*! ./isArrayLike */ \"../node_modules/lodash/isArrayLike.js\");\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\nmodule.exports = keys;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/keys.js?");
/***/ }),
/***/ "../node_modules/lodash/keysIn.js":
/*!****************************************!*\
!*** ../node_modules/lodash/keysIn.js ***!
\****************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var arrayLikeKeys = __webpack_require__(/*! ./_arrayLikeKeys */ \"../node_modules/lodash/_arrayLikeKeys.js\"),\n baseKeysIn = __webpack_require__(/*! ./_baseKeysIn */ \"../node_modules/lodash/_baseKeysIn.js\"),\n isArrayLike = __webpack_require__(/*! ./isArrayLike */ \"../node_modules/lodash/isArrayLike.js\");\n\n/**\n * Creates an array of the own and inherited enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keysIn(new Foo);\n * // => ['a', 'b', 'c'] (iteration order is not guaranteed)\n */\nfunction keysIn(object) {\n return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);\n}\n\nmodule.exports = keysIn;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/keysIn.js?");
/***/ }),
/***/ "../node_modules/lodash/last.js":
/*!**************************************!*\
!*** ../node_modules/lodash/last.js ***!
\**************************************/
/***/ ((module) => {
eval("/**\n * Gets the last element of `array`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Array\n * @param {Array} array The array to query.\n * @returns {*} Returns the last element of `array`.\n * @example\n *\n * _.last([1, 2, 3]);\n * // => 3\n */\nfunction last(array) {\n var length = array == null ? 0 : array.length;\n return length ? array[length - 1] : undefined;\n}\n\nmodule.exports = last;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/last.js?");
/***/ }),
/***/ "../node_modules/lodash/memoize.js":
/*!*****************************************!*\
!*** ../node_modules/lodash/memoize.js ***!
\*****************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var MapCache = __webpack_require__(/*! ./_MapCache */ \"../node_modules/lodash/_MapCache.js\");\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a function that memoizes the result of `func`. If `resolver` is\n * provided, it determines the cache key for storing the result based on the\n * arguments provided to the memoized function. By default, the first argument\n * provided to the memoized function is used as the map cache key. The `func`\n * is invoked with the `this` binding of the memoized function.\n *\n * **Note:** The cache is exposed as the `cache` property on the memoized\n * function. Its creation may be customized by replacing the `_.memoize.Cache`\n * constructor with one whose instances implement the\n * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)\n * method interface of `clear`, `delete`, `get`, `has`, and `set`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to have its output memoized.\n * @param {Function} [resolver] The function to resolve the cache key.\n * @returns {Function} Returns the new memoized function.\n * @example\n *\n * var object = { 'a': 1, 'b': 2 };\n * var other = { 'c': 3, 'd': 4 };\n *\n * var values = _.memoize(_.values);\n * values(object);\n * // => [1, 2]\n *\n * values(other);\n * // => [3, 4]\n *\n * object.a = 2;\n * values(object);\n * // => [1, 2]\n *\n * // Modify the result cache.\n * values.cache.set(object, ['a', 'b']);\n * values(object);\n * // => ['a', 'b']\n *\n * // Replace `_.memoize.Cache`.\n * _.memoize.Cache = WeakMap;\n */\nfunction memoize(func, resolver) {\n if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n var memoized = function() {\n var args = arguments,\n key = resolver ? resolver.apply(this, args) : args[0],\n cache = memoized.cache;\n\n if (cache.has(key)) {\n return cache.get(key);\n }\n var result = func.apply(this, args);\n memoized.cache = cache.set(key, result) || cache;\n return result;\n };\n memoized.cache = new (memoize.Cache || MapCache);\n return memoized;\n}\n\n// Expose `MapCache`.\nmemoize.Cache = MapCache;\n\nmodule.exports = memoize;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/memoize.js?");
/***/ }),
/***/ "../node_modules/lodash/omit.js":
/*!**************************************!*\
!*** ../node_modules/lodash/omit.js ***!
\**************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var arrayMap = __webpack_require__(/*! ./_arrayMap */ \"../node_modules/lodash/_arrayMap.js\"),\n baseClone = __webpack_require__(/*! ./_baseClone */ \"../node_modules/lodash/_baseClone.js\"),\n baseUnset = __webpack_require__(/*! ./_baseUnset */ \"../node_modules/lodash/_baseUnset.js\"),\n castPath = __webpack_require__(/*! ./_castPath */ \"../node_modules/lodash/_castPath.js\"),\n copyObject = __webpack_require__(/*! ./_copyObject */ \"../node_modules/lodash/_copyObject.js\"),\n customOmitClone = __webpack_require__(/*! ./_customOmitClone */ \"../node_modules/lodash/_customOmitClone.js\"),\n flatRest = __webpack_require__(/*! ./_flatRest */ \"../node_modules/lodash/_flatRest.js\"),\n getAllKeysIn = __webpack_require__(/*! ./_getAllKeysIn */ \"../node_modules/lodash/_getAllKeysIn.js\");\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n CLONE_FLAT_FLAG = 2,\n CLONE_SYMBOLS_FLAG = 4;\n\n/**\n * The opposite of `_.pick`; this method creates an object composed of the\n * own and inherited enumerable property paths of `object` that are not omitted.\n *\n * **Note:** This method is considerably slower than `_.pick`.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The source object.\n * @param {...(string|string[])} [paths] The property paths to omit.\n * @returns {Object} Returns the new object.\n * @example\n *\n * var object = { 'a': 1, 'b': '2', 'c': 3 };\n *\n * _.omit(object, ['a', 'c']);\n * // => { 'b': '2' }\n */\nvar omit = flatRest(function(object, paths) {\n var result = {};\n if (object == null) {\n return result;\n }\n var isDeep = false;\n paths = arrayMap(paths, function(path) {\n path = castPath(path, object);\n isDeep || (isDeep = path.length > 1);\n return path;\n });\n copyObject(object, getAllKeysIn(object), result);\n if (isDeep) {\n result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone);\n }\n var length = paths.length;\n while (length--) {\n baseUnset(result, paths[length]);\n }\n return result;\n});\n\nmodule.exports = omit;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/omit.js?");
/***/ }),
/***/ "../node_modules/lodash/pick.js":
/*!**************************************!*\
!*** ../node_modules/lodash/pick.js ***!
\**************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var basePick = __webpack_require__(/*! ./_basePick */ \"../node_modules/lodash/_basePick.js\"),\n flatRest = __webpack_require__(/*! ./_flatRest */ \"../node_modules/lodash/_flatRest.js\");\n\n/**\n * Creates an object composed of the picked `object` properties.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The source object.\n * @param {...(string|string[])} [paths] The property paths to pick.\n * @returns {Object} Returns the new object.\n * @example\n *\n * var object = { 'a': 1, 'b': '2', 'c': 3 };\n *\n * _.pick(object, ['a', 'c']);\n * // => { 'a': 1, 'c': 3 }\n */\nvar pick = flatRest(function(object, paths) {\n return object == null ? {} : basePick(object, paths);\n});\n\nmodule.exports = pick;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/pick.js?");
/***/ }),
/***/ "../node_modules/lodash/snakeCase.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/snakeCase.js ***!
\*******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var createCompounder = __webpack_require__(/*! ./_createCompounder */ \"../node_modules/lodash/_createCompounder.js\");\n\n/**\n * Converts `string` to\n * [snake case](https://en.wikipedia.org/wiki/Snake_case).\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the snake cased string.\n * @example\n *\n * _.snakeCase('Foo Bar');\n * // => 'foo_bar'\n *\n * _.snakeCase('fooBar');\n * // => 'foo_bar'\n *\n * _.snakeCase('--FOO-BAR--');\n * // => 'foo_bar'\n */\nvar snakeCase = createCompounder(function(result, word, index) {\n return result + (index ? '_' : '') + word.toLowerCase();\n});\n\nmodule.exports = snakeCase;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/snakeCase.js?");
/***/ }),
/***/ "../node_modules/lodash/stubArray.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/stubArray.js ***!
\*******************************************/
/***/ ((module) => {
eval("/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nmodule.exports = stubArray;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/stubArray.js?");
/***/ }),
/***/ "../node_modules/lodash/stubFalse.js":
/*!*******************************************!*\
!*** ../node_modules/lodash/stubFalse.js ***!
\*******************************************/
/***/ ((module) => {
eval("/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nmodule.exports = stubFalse;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/stubFalse.js?");
/***/ }),
/***/ "../node_modules/lodash/toString.js":
/*!******************************************!*\
!*** ../node_modules/lodash/toString.js ***!
\******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var baseToString = __webpack_require__(/*! ./_baseToString */ \"../node_modules/lodash/_baseToString.js\");\n\n/**\n * Converts `value` to a string. An empty string is returned for `null`\n * and `undefined` values. The sign of `-0` is preserved.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n * @example\n *\n * _.toString(null);\n * // => ''\n *\n * _.toString(-0);\n * // => '-0'\n *\n * _.toString([1, 2, 3]);\n * // => '1,2,3'\n */\nfunction toString(value) {\n return value == null ? '' : baseToString(value);\n}\n\nmodule.exports = toString;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/toString.js?");
/***/ }),
/***/ "../node_modules/lodash/upperFirst.js":
/*!********************************************!*\
!*** ../node_modules/lodash/upperFirst.js ***!
\********************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var createCaseFirst = __webpack_require__(/*! ./_createCaseFirst */ \"../node_modules/lodash/_createCaseFirst.js\");\n\n/**\n * Converts the first character of `string` to upper case.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the converted string.\n * @example\n *\n * _.upperFirst('fred');\n * // => 'Fred'\n *\n * _.upperFirst('FRED');\n * // => 'FRED'\n */\nvar upperFirst = createCaseFirst('toUpperCase');\n\nmodule.exports = upperFirst;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/upperFirst.js?");
/***/ }),
/***/ "../node_modules/lodash/words.js":
/*!***************************************!*\
!*** ../node_modules/lodash/words.js ***!
\***************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var asciiWords = __webpack_require__(/*! ./_asciiWords */ \"../node_modules/lodash/_asciiWords.js\"),\n hasUnicodeWord = __webpack_require__(/*! ./_hasUnicodeWord */ \"../node_modules/lodash/_hasUnicodeWord.js\"),\n toString = __webpack_require__(/*! ./toString */ \"../node_modules/lodash/toString.js\"),\n unicodeWords = __webpack_require__(/*! ./_unicodeWords */ \"../node_modules/lodash/_unicodeWords.js\");\n\n/**\n * Splits `string` into an array of its words.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to inspect.\n * @param {RegExp|string} [pattern] The pattern to match words.\n * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.\n * @returns {Array} Returns the words of `string`.\n * @example\n *\n * _.words('fred, barney, & pebbles');\n * // => ['fred', 'barney', 'pebbles']\n *\n * _.words('fred, barney, & pebbles', /[^, ]+/g);\n * // => ['fred', 'barney', '&', 'pebbles']\n */\nfunction words(string, pattern, guard) {\n string = toString(string);\n pattern = guard ? undefined : pattern;\n\n if (pattern === undefined) {\n return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);\n }\n return string.match(pattern) || [];\n}\n\nmodule.exports = words;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/lodash/words.js?");
/***/ }),
/***/ "./assets/styles/components/title-bar.scss":
/*!*************************************************!*\
!*** ./assets/styles/components/title-bar.scss ***!
\*************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://cloudinary-video-player/./assets/styles/components/title-bar.scss?");
/***/ }),
/***/ "./assets/styles/main.scss":
/*!*********************************!*\
!*** ./assets/styles/main.scss ***!
\*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://cloudinary-video-player/./assets/styles/main.scss?");
/***/ }),
/***/ "./components/logoButton/logo-button.scss":
/*!************************************************!*\
!*** ./components/logoButton/logo-button.scss ***!
\************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://cloudinary-video-player/./components/logoButton/logo-button.scss?");
/***/ }),
/***/ "./plugins/ai-highlights-graph/ai-highlights-graph.scss":
/*!**************************************************************!*\
!*** ./plugins/ai-highlights-graph/ai-highlights-graph.scss ***!
\**************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/ai-highlights-graph/ai-highlights-graph.scss?");
/***/ }),
/***/ "./plugins/context-menu/context-menu.scss":
/*!************************************************!*\
!*** ./plugins/context-menu/context-menu.scss ***!
\************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/context-menu/context-menu.scss?");
/***/ }),
/***/ "./plugins/floating-player/floating-player.scss":
/*!******************************************************!*\
!*** ./plugins/floating-player/floating-player.scss ***!
\******************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/floating-player/floating-player.scss?");
/***/ }),
/***/ "./plugins/styled-text-tracks/styled-text-tracks.scss":
/*!************************************************************!*\
!*** ./plugins/styled-text-tracks/styled-text-tracks.scss ***!
\************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/styled-text-tracks/styled-text-tracks.scss?");
/***/ }),
/***/ "./plugins/vtt-thumbnails/vtt-thumbnails.scss":
/*!****************************************************!*\
!*** ./plugins/vtt-thumbnails/vtt-thumbnails.scss ***!
\****************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://cloudinary-video-player/./plugins/vtt-thumbnails/vtt-thumbnails.scss?");
/***/ }),
/***/ "../node_modules/video.js/dist/alt/video.core.js":
/*!*******************************************************!*\
!*** ../node_modules/video.js/dist/alt/video.core.js ***!
\*******************************************************/
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
eval("/**\n * @license\n * Video.js 8.23.3 <http://videojs.com/>\n * Copyright Brightcove, Inc. <https://www.brightcove.com/>\n * Available under Apache License Version 2.0\n * <https://github.com/videojs/video.js/blob/main/LICENSE>\n *\n * Includes vtt.js <https://github.com/mozilla/vtt.js>\n * Available under Apache License Version 2.0\n * <https://github.com/mozilla/vtt.js/blob/main/LICENSE>\n */\n\n(function (global, factory) {\n true ? module.exports = factory() :\n 0;\n})(this, (function () { 'use strict';\n\n var version = \"8.23.3\";\n\n /**\n * An Object that contains lifecycle hooks as keys which point to an array\n * of functions that are run when a lifecycle is triggered\n *\n * @private\n */\n const hooks_ = {};\n\n /**\n * Get a list of hooks for a specific lifecycle\n *\n * @param {string} type\n * the lifecycle to get hooks from\n *\n * @param {Function|Function[]} [fn]\n * Optionally add a hook (or hooks) to the lifecycle that your are getting.\n *\n * @return {Array}\n * an array of hooks, or an empty array if there are none.\n */\n const hooks = function (type, fn) {\n hooks_[type] = hooks_[type] || [];\n if (fn) {\n hooks_[type] = hooks_[type].concat(fn);\n }\n return hooks_[type];\n };\n\n /**\n * Add a function hook to a specific videojs lifecycle.\n *\n * @param {string} type\n * the lifecycle to hook the function to.\n *\n * @param {Function|Function[]}\n * The function or array of functions to attach.\n */\n const hook = function (type, fn) {\n hooks(type, fn);\n };\n\n /**\n * Remove a hook from a specific videojs lifecycle.\n *\n * @param {string} type\n * the lifecycle that the function hooked to\n *\n * @param {Function} fn\n * The hooked function to remove\n *\n * @return {boolean}\n * The function that was removed or undef\n */\n const removeHook = function (type, fn) {\n const index = hooks(type).indexOf(fn);\n if (index <= -1) {\n return false;\n }\n hooks_[type] = hooks_[type].slice();\n hooks_[type].splice(index, 1);\n return true;\n };\n\n /**\n * Add a function hook that will only run once to a specific videojs lifecycle.\n *\n * @param {string} type\n * the lifecycle to hook the function to.\n *\n * @param {Function|Function[]}\n * The function or array of functions to attach.\n */\n const hookOnce = function (type, fn) {\n hooks(type, [].concat(fn).map(original => {\n const wrapper = (...args) => {\n removeHook(type, wrapper);\n return original(...args);\n };\n return wrapper;\n }));\n };\n\n /**\n * @file fullscreen-api.js\n * @module fullscreen-api\n */\n\n /**\n * Store the browser-specific methods for the fullscreen API.\n *\n * @type {Object}\n * @see [Specification]{@link https://fullscreen.spec.whatwg.org}\n * @see [Map Approach From Screenfull.js]{@link https://github.com/sindresorhus/screenfull.js}\n */\n const FullscreenApi = {\n prefixed: true\n };\n\n // browser API methods\n const apiMap = [['requestFullscreen', 'exitFullscreen', 'fullscreenElement', 'fullscreenEnabled', 'fullscreenchange', 'fullscreenerror', 'fullscreen'],\n // WebKit\n ['webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitFullscreenElement', 'webkitFullscreenEnabled', 'webkitfullscreenchange', 'webkitfullscreenerror', '-webkit-full-screen']];\n const specApi = apiMap[0];\n let browserApi;\n\n // determine the supported set of functions\n for (let i = 0; i < apiMap.length; i++) {\n // check for exitFullscreen function\n if (apiMap[i][1] in document) {\n browserApi = apiMap[i];\n break;\n }\n }\n\n // map the browser API names to the spec API names\n if (browserApi) {\n for (let i = 0; i < browserApi.length; i++) {\n FullscreenApi[specApi[i]] = browserApi[i];\n }\n FullscreenApi.prefixed = browserApi[0] !== specApi[0];\n }\n\n /**\n * @file create-logger.js\n * @module create-logger\n */\n\n // This is the private tracking variable for the logging history.\n let history = [];\n\n /**\n * Log messages to the console and history based on the type of message\n *\n * @private\n * @param {string} name\n * The name of the console method to use.\n *\n * @param {Object} log\n * The arguments to be passed to the matching console method.\n *\n * @param {string} [styles]\n * styles for name\n */\n const LogByTypeFactory = (name, log, styles) => (type, level, args) => {\n const lvl = log.levels[level];\n const lvlRegExp = new RegExp(`^(${lvl})$`);\n let resultName = name;\n if (type !== 'log') {\n // Add the type to the front of the message when it's not \"log\".\n args.unshift(type.toUpperCase() + ':');\n }\n if (styles) {\n resultName = `%c${name}`;\n args.unshift(styles);\n }\n\n // Add console prefix after adding to history.\n args.unshift(resultName + ':');\n\n // Add a clone of the args at this point to history.\n if (history) {\n history.push([].concat(args));\n\n // only store 1000 history entries\n const splice = history.length - 1000;\n history.splice(0, splice > 0 ? splice : 0);\n }\n\n // If there's no console then don't try to output messages, but they will\n // still be stored in history.\n if (!window.console) {\n return;\n }\n\n // Was setting these once outside of this function, but containing them\n // in the function makes it easier to test cases where console doesn't exist\n // when the module is executed.\n let fn = window.console[type];\n if (!fn && type === 'debug') {\n // Certain browsers don't have support for console.debug. For those, we\n // should default to the closest comparable log.\n fn = window.console.info || window.console.log;\n }\n\n // Bail out if there's no console or if this type is not allowed by the\n // current logging level.\n if (!fn || !lvl || !lvlRegExp.test(type)) {\n return;\n }\n fn[Array.isArray(args) ? 'apply' : 'call'](window.console, args);\n };\n function createLogger$1(name, delimiter = ':', styles = '') {\n // This is the private tracking variable for logging level.\n let level = 'info';\n\n // the curried logByType bound to the specific log and history\n let logByType;\n\n /**\n * Logs plain debug messages. Similar to `console.log`.\n *\n * Due to [limitations](https://github.com/jsdoc3/jsdoc/issues/955#issuecomment-313829149)\n * of our JSDoc template, we cannot properly document this as both a function\n * and a namespace, so its function signature is documented here.\n *\n * #### Arguments\n * ##### *args\n * *[]\n *\n * Any combination of values that could be passed to `console.log()`.\n *\n * #### Return Value\n *\n * `undefined`\n *\n * @namespace\n * @param {...*} args\n * One or more messages or objects that should be logged.\n */\n function log(...args) {\n logByType('log', level, args);\n }\n\n // This is the logByType helper that the logging methods below use\n logByType = LogByTypeFactory(name, log, styles);\n\n /**\n * Create a new subLogger which chains the old name to the new name.\n *\n * For example, doing `mylogger = videojs.log.createLogger('player')` and then using that logger will log the following:\n * ```js\n * mylogger('foo');\n * // > VIDEOJS: player: foo\n * ```\n *\n * @param {string} subName\n * The name to add call the new logger\n * @param {string} [subDelimiter]\n * Optional delimiter\n * @param {string} [subStyles]\n * Optional styles\n * @return {Object}\n */\n log.createLogger = (subName, subDelimiter, subStyles) => {\n const resultDelimiter = subDelimiter !== undefined ? subDelimiter : delimiter;\n const resultStyles = subStyles !== undefined ? subStyles : styles;\n const resultName = `${name} ${resultDelimiter} ${subName}`;\n return createLogger$1(resultName, resultDelimiter, resultStyles);\n };\n\n /**\n * Create a new logger.\n *\n * @param {string} newName\n * The name for the new logger\n * @param {string} [newDelimiter]\n * Optional delimiter\n * @param {string} [newStyles]\n * Optional styles\n * @return {Object}\n */\n log.createNewLogger = (newName, newDelimiter, newStyles) => {\n return createLogger$1(newName, newDelimiter, newStyles);\n };\n\n /**\n * Enumeration of available logging levels, where the keys are the level names\n * and the values are `|`-separated strings containing logging methods allowed\n * in that logging level. These strings are used to create a regular expression\n * matching the function name being called.\n *\n * Levels provided by Video.js are:\n *\n * - `off`: Matches no calls. Any value that can be cast to `false` will have\n * this effect. The most restrictive.\n * - `all`: Matches only Video.js-provided functions (`debug`, `log`,\n * `log.warn`, and `log.error`).\n * - `debug`: Matches `log.debug`, `log`, `log.warn`, and `log.error` calls.\n * - `info` (default): Matches `log`, `log.warn`, and `log.error` calls.\n * - `warn`: Matches `log.warn` and `log.error` calls.\n * - `error`: Matches only `log.error` calls.\n *\n * @type {Object}\n */\n log.levels = {\n all: 'debug|log|warn|error',\n off: '',\n debug: 'debug|log|warn|error',\n info: 'log|warn|error',\n warn: 'warn|error',\n error: 'error',\n DEFAULT: level\n };\n\n /**\n * Get or set the current logging level.\n *\n * If a string matching a key from {@link module:log.levels} is provided, acts\n * as a setter.\n *\n * @param {'all'|'debug'|'info'|'warn'|'error'|'off'} [lvl]\n * Pass a valid level to set a new logging level.\n *\n * @return {string}\n * The current logging level.\n */\n log.level = lvl => {\n if (typeof lvl === 'string') {\n if (!log.levels.hasOwnProperty(lvl)) {\n throw new Error(`\"${lvl}\" in not a valid log level`);\n }\n level = lvl;\n }\n return level;\n };\n\n /**\n * Returns an array containing everything that has been logged to the history.\n *\n * This array is a shallow clone of the internal history record. However, its\n * contents are _not_ cloned; so, mutating objects inside this array will\n * mutate them in history.\n *\n * @return {Array}\n */\n log.history = () => history ? [].concat(history) : [];\n\n /**\n * Allows you to filter the history by the given logger name\n *\n * @param {string} fname\n * The name to filter by\n *\n * @return {Array}\n * The filtered list to return\n */\n log.history.filter = fname => {\n return (history || []).filter(historyItem => {\n // if the first item in each historyItem includes `fname`, then it's a match\n return new RegExp(`.*${fname}.*`).test(historyItem[0]);\n });\n };\n\n /**\n * Clears the internal history tracking, but does not prevent further history\n * tracking.\n */\n log.history.clear = () => {\n if (history) {\n history.length = 0;\n }\n };\n\n /**\n * Disable history tracking if it is currently enabled.\n */\n log.history.disable = () => {\n if (history !== null) {\n history.length = 0;\n history = null;\n }\n };\n\n /**\n * Enable history tracking if it is currently disabled.\n */\n log.history.enable = () => {\n if (history === null) {\n history = [];\n }\n };\n\n /**\n * Logs error messages. Similar to `console.error`.\n *\n * @param {...*} args\n * One or more messages or objects that should be logged as an error\n */\n log.error = (...args) => logByType('error', level, args);\n\n /**\n * Logs warning messages. Similar to `console.warn`.\n *\n * @param {...*} args\n * One or more messages or objects that should be logged as a warning.\n */\n log.warn = (...args) => logByType('warn', level, args);\n\n /**\n * Logs debug messages. Similar to `console.debug`, but may also act as a comparable\n * log if `console.debug` is not available\n *\n * @param {...*} args\n * One or more messages or objects that should be logged as debug.\n */\n log.debug = (...args) => logByType('debug', level, args);\n return log;\n }\n\n /**\n * @file log.js\n * @module log\n */\n const log = createLogger$1('VIDEOJS');\n const createLogger = log.createLogger;\n\n /**\n * @file obj.js\n * @module obj\n */\n\n /**\n * @callback obj:EachCallback\n *\n * @param {*} value\n * The current key for the object that is being iterated over.\n *\n * @param {string} key\n * The current key-value for object that is being iterated over\n */\n\n /**\n * @callback obj:ReduceCallback\n *\n * @param {*} accum\n * The value that is accumulating over the reduce loop.\n *\n * @param {*} value\n * The current key for the object that is being iterated over.\n *\n * @param {string} key\n * The current key-value for object that is being iterated over\n *\n * @return {*}\n * The new accumulated value.\n */\n const toString$1 = Object.prototype.toString;\n\n /**\n * Get the keys of an Object\n *\n * @param {Object}\n * The Object to get the keys from\n *\n * @return {string[]}\n * An array of the keys from the object. Returns an empty array if the\n * object passed in was invalid or had no keys.\n *\n * @private\n */\n const keys = function (object) {\n return isObject(object) ? Object.keys(object) : [];\n };\n\n /**\n * Array-like iteration for objects.\n *\n * @param {Object} object\n * The object to iterate over\n *\n * @param {obj:EachCallback} fn\n * The callback function which is called for each key in the object.\n */\n function each(object, fn) {\n keys(object).forEach(key => fn(object[key], key));\n }\n\n /**\n * Array-like reduce for objects.\n *\n * @param {Object} object\n * The Object that you want to reduce.\n *\n * @param {Function} fn\n * A callback function which is called for each key in the object. It\n * receives the accumulated value and the per-iteration value and key\n * as arguments.\n *\n * @param {*} [initial = 0]\n * Starting value\n *\n * @return {*}\n * The final accumulated value.\n */\n function reduce(object, fn, initial = 0) {\n return keys(object).reduce((accum, key) => fn(accum, object[key], key), initial);\n }\n\n /**\n * Returns whether a value is an object of any kind - including DOM nodes,\n * arrays, regular expressions, etc. Not functions, though.\n *\n * This avoids the gotcha where using `typeof` on a `null` value\n * results in `'object'`.\n *\n * @param {Object} value\n * @return {boolean}\n */\n function isObject(value) {\n return !!value && typeof value === 'object';\n }\n\n /**\n * Returns whether an object appears to be a \"plain\" object - that is, a\n * direct instance of `Object`.\n *\n * @param {Object} value\n * @return {boolean}\n */\n function isPlain(value) {\n return isObject(value) && toString$1.call(value) === '[object Object]' && value.constructor === Object;\n }\n\n /**\n * Merge two objects recursively.\n *\n * Performs a deep merge like\n * {@link https://lodash.com/docs/4.17.10#merge|lodash.merge}, but only merges\n * plain objects (not arrays, elements, or anything else).\n *\n * Non-plain object values will be copied directly from the right-most\n * argument.\n *\n * @param {Object[]} sources\n * One or more objects to merge into a new object.\n *\n * @return {Object}\n * A new object that is the merged result of all sources.\n */\n function merge(...sources) {\n const result = {};\n sources.forEach(source => {\n if (!source) {\n return;\n }\n each(source, (value, key) => {\n if (!isPlain(value)) {\n result[key] = value;\n return;\n }\n if (!isPlain(result[key])) {\n result[key] = {};\n }\n result[key] = merge(result[key], value);\n });\n });\n return result;\n }\n\n /**\n * Returns an array of values for a given object\n *\n * @param {Object} source - target object\n * @return {Array<unknown>} - object values\n */\n function values(source = {}) {\n const result = [];\n for (const key in source) {\n if (source.hasOwnProperty(key)) {\n const value = source[key];\n result.push(value);\n }\n }\n return result;\n }\n\n /**\n * Object.defineProperty but \"lazy\", which means that the value is only set after\n * it is retrieved the first time, rather than being set right away.\n *\n * @param {Object} obj the object to set the property on\n * @param {string} key the key for the property to set\n * @param {Function} getValue the function used to get the value when it is needed.\n * @param {boolean} setter whether a setter should be allowed or not\n */\n function defineLazyProperty(obj, key, getValue, setter = true) {\n const set = value => Object.defineProperty(obj, key, {\n value,\n enumerable: true,\n writable: true\n });\n const options = {\n configurable: true,\n enumerable: true,\n get() {\n const value = getValue();\n set(value);\n return value;\n }\n };\n if (setter) {\n options.set = set;\n }\n return Object.defineProperty(obj, key, options);\n }\n\n var Obj = /*#__PURE__*/Object.freeze({\n __proto__: null,\n each: each,\n reduce: reduce,\n isObject: isObject,\n isPlain: isPlain,\n merge: merge,\n values: values,\n defineLazyProperty: defineLazyProperty\n });\n\n /**\n * @file browser.js\n * @module browser\n */\n\n /**\n * Whether or not this device is an iPod.\n *\n * @static\n * @type {Boolean}\n */\n let IS_IPOD = false;\n\n /**\n * The detected iOS version - or `null`.\n *\n * @static\n * @type {string|null}\n */\n let IOS_VERSION = null;\n\n /**\n * Whether or not this is an Android device.\n *\n * @static\n * @type {Boolean}\n */\n let IS_ANDROID = false;\n\n /**\n * The detected Android version - or `null` if not Android or indeterminable.\n *\n * @static\n * @type {number|string|null}\n */\n let ANDROID_VERSION;\n\n /**\n * Whether or not this is Mozilla Firefox.\n *\n * @static\n * @type {Boolean}\n */\n let IS_FIREFOX = false;\n\n /**\n * Whether or not this is Microsoft Edge.\n *\n * @static\n * @type {Boolean}\n */\n let IS_EDGE = false;\n\n /**\n * Whether or not this is any Chromium Browser\n *\n * @static\n * @type {Boolean}\n */\n let IS_CHROMIUM = false;\n\n /**\n * Whether or not this is any Chromium browser that is not Edge.\n *\n * This will also be `true` for Chrome on iOS, which will have different support\n * as it is actually Safari under the hood.\n *\n * Deprecated, as the behaviour to not match Edge was to prevent Legacy Edge's UA matching.\n * IS_CHROMIUM should be used instead.\n * \"Chromium but not Edge\" could be explicitly tested with IS_CHROMIUM && !IS_EDGE\n *\n * @static\n * @deprecated\n * @type {Boolean}\n */\n let IS_CHROME = false;\n\n /**\n * The detected Chromium version - or `null`.\n *\n * @static\n * @type {number|null}\n */\n let CHROMIUM_VERSION = null;\n\n /**\n * The detected Google Chrome version - or `null`.\n * This has always been the _Chromium_ version, i.e. would return on Chromium Edge.\n * Deprecated, use CHROMIUM_VERSION instead.\n *\n * @static\n * @deprecated\n * @type {number|null}\n */\n let CHROME_VERSION = null;\n\n /**\n * Whether or not this is a Chromecast receiver application.\n *\n * @static\n * @type {Boolean}\n */\n const IS_CHROMECAST_RECEIVER = Boolean(window.cast && window.cast.framework && window.cast.framework.CastReceiverContext);\n\n /**\n * The detected Internet Explorer version - or `null`.\n *\n * @static\n * @deprecated\n * @type {number|null}\n */\n let IE_VERSION = null;\n\n /**\n * Whether or not this is desktop Safari.\n *\n * @static\n * @type {Boolean}\n */\n let IS_SAFARI = false;\n\n /**\n * Whether or not this is a Windows machine.\n *\n * @static\n * @type {Boolean}\n */\n let IS_WINDOWS = false;\n\n /**\n * Whether or not this device is an iPad.\n *\n * @static\n * @type {Boolean}\n */\n let IS_IPAD = false;\n\n /**\n * Whether or not this device is an iPhone.\n *\n * @static\n * @type {Boolean}\n */\n // The Facebook app's UIWebView identifies as both an iPhone and iPad, so\n // to identify iPhones, we need to exclude iPads.\n // http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/\n let IS_IPHONE = false;\n\n /**\n * Whether or not this is a Tizen device.\n *\n * @static\n * @type {Boolean}\n */\n let IS_TIZEN = false;\n\n /**\n * Whether or not this is a WebOS device.\n *\n * @static\n * @type {Boolean}\n */\n let IS_WEBOS = false;\n\n /**\n * Whether or not this is a Smart TV (Tizen or WebOS) device.\n *\n * @static\n * @type {Boolean}\n */\n let IS_SMART_TV = false;\n\n /**\n * Whether or not this device is touch-enabled.\n *\n * @static\n * @const\n * @type {Boolean}\n */\n const TOUCH_ENABLED = Boolean(isReal() && ('ontouchstart' in window || window.navigator.maxTouchPoints || window.DocumentTouch && window.document instanceof window.DocumentTouch));\n const UAD = window.navigator && window.navigator.userAgentData;\n if (UAD && UAD.platform && UAD.brands) {\n // If userAgentData is present, use it instead of userAgent to avoid warnings\n // Currently only implemented on Chromium\n // userAgentData does not expose Android version, so ANDROID_VERSION remains `null`\n\n IS_ANDROID = UAD.platform === 'Android';\n IS_EDGE = Boolean(UAD.brands.find(b => b.brand === 'Microsoft Edge'));\n IS_CHROMIUM = Boolean(UAD.brands.find(b => b.brand === 'Chromium'));\n IS_CHROME = !IS_EDGE && IS_CHROMIUM;\n CHROMIUM_VERSION = CHROME_VERSION = (UAD.brands.find(b => b.brand === 'Chromium') || {}).version || null;\n IS_WINDOWS = UAD.platform === 'Windows';\n }\n\n // If the browser is not Chromium, either userAgentData is not present which could be an old Chromium browser,\n // or it's a browser that has added userAgentData since that we don't have tests for yet. In either case,\n // the checks need to be made agiainst the regular userAgent string.\n if (!IS_CHROMIUM) {\n const USER_AGENT = window.navigator && window.navigator.userAgent || '';\n IS_IPOD = /iPod/i.test(USER_AGENT);\n IOS_VERSION = function () {\n const match = USER_AGENT.match(/OS (\\d+)_/i);\n if (match && match[1]) {\n return match[1];\n }\n return null;\n }();\n IS_ANDROID = /Android/i.test(USER_AGENT);\n ANDROID_VERSION = function () {\n // This matches Android Major.Minor.Patch versions\n // ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned\n const match = USER_AGENT.match(/Android (\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))*/i);\n if (!match) {\n return null;\n }\n const major = match[1] && parseFloat(match[1]);\n const minor = match[2] && parseFloat(match[2]);\n if (major && minor) {\n return parseFloat(match[1] + '.' + match[2]);\n } else if (major) {\n return major;\n }\n return null;\n }();\n IS_FIREFOX = /Firefox/i.test(USER_AGENT);\n IS_EDGE = /Edg/i.test(USER_AGENT);\n IS_CHROMIUM = /Chrome/i.test(USER_AGENT) || /CriOS/i.test(USER_AGENT);\n IS_CHROME = !IS_EDGE && IS_CHROMIUM;\n CHROMIUM_VERSION = CHROME_VERSION = function () {\n const match = USER_AGENT.match(/(Chrome|CriOS)\\/(\\d+)/);\n if (match && match[2]) {\n return parseFloat(match[2]);\n }\n return null;\n }();\n IE_VERSION = function () {\n const result = /MSIE\\s(\\d+)\\.\\d/.exec(USER_AGENT);\n let version = result && parseFloat(result[1]);\n if (!version && /Trident\\/7.0/i.test(USER_AGENT) && /rv:11.0/.test(USER_AGENT)) {\n // IE 11 has a different user agent string than other IE versions\n version = 11.0;\n }\n return version;\n }();\n IS_TIZEN = /Tizen/i.test(USER_AGENT);\n IS_WEBOS = /Web0S/i.test(USER_AGENT);\n IS_SMART_TV = IS_TIZEN || IS_WEBOS;\n IS_SAFARI = /Safari/i.test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE && !IS_SMART_TV;\n IS_WINDOWS = /Windows/i.test(USER_AGENT);\n IS_IPAD = /iPad/i.test(USER_AGENT) || IS_SAFARI && TOUCH_ENABLED && !/iPhone/i.test(USER_AGENT);\n IS_IPHONE = /iPhone/i.test(USER_AGENT) && !IS_IPAD;\n }\n\n /**\n * Whether or not this is an iOS device.\n *\n * @static\n * @const\n * @type {Boolean}\n */\n const IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD;\n\n /**\n * Whether or not this is any flavor of Safari - including iOS.\n *\n * @static\n * @const\n * @type {Boolean}\n */\n const IS_ANY_SAFARI = (IS_SAFARI || IS_IOS) && !IS_CHROME;\n\n var browser = /*#__PURE__*/Object.freeze({\n __proto__: null,\n get IS_IPOD () { return IS_IPOD; },\n get IOS_VERSION () { return IOS_VERSION; },\n get IS_ANDROID () { return IS_ANDROID; },\n get ANDROID_VERSION () { return ANDROID_VERSION; },\n get IS_FIREFOX () { return IS_FIREFOX; },\n get IS_EDGE () { return IS_EDGE; },\n get IS_CHROMIUM () { return IS_CHROMIUM; },\n get IS_CHROME () { return IS_CHROME; },\n get CHROMIUM_VERSION () { return CHROMIUM_VERSION; },\n get CHROME_VERSION () { return CHROME_VERSION; },\n IS_CHROMECAST_RECEIVER: IS_CHROMECAST_RECEIVER,\n get IE_VERSION () { return IE_VERSION; },\n get IS_SAFARI () { return IS_SAFARI; },\n get IS_WINDOWS () { return IS_WINDOWS; },\n get IS_IPAD () { return IS_IPAD; },\n get IS_IPHONE () { return IS_IPHONE; },\n get IS_TIZEN () { return IS_TIZEN; },\n get IS_WEBOS () { return IS_WEBOS; },\n get IS_SMART_TV () { return IS_SMART_TV; },\n TOUCH_ENABLED: TOUCH_ENABLED,\n IS_IOS: IS_IOS,\n IS_ANY_SAFARI: IS_ANY_SAFARI\n });\n\n /**\n * @file dom.js\n * @module dom\n */\n\n /**\n * Detect if a value is a string with any non-whitespace characters.\n *\n * @private\n * @param {string} str\n * The string to check\n *\n * @return {boolean}\n * Will be `true` if the string is non-blank, `false` otherwise.\n *\n */\n function isNonBlankString(str) {\n // we use str.trim as it will trim any whitespace characters\n // from the front or back of non-whitespace characters. aka\n // Any string that contains non-whitespace characters will\n // still contain them after `trim` but whitespace only strings\n // will have a length of 0, failing this check.\n return typeof str === 'string' && Boolean(str.trim());\n }\n\n /**\n * Throws an error if the passed string has whitespace. This is used by\n * class methods to be relatively consistent with the classList API.\n *\n * @private\n * @param {string} str\n * The string to check for whitespace.\n *\n * @throws {Error}\n * Throws an error if there is whitespace in the string.\n */\n function throwIfWhitespace(str) {\n // str.indexOf instead of regex because str.indexOf is faster performance wise.\n if (str.indexOf(' ') >= 0) {\n throw new Error('class has illegal whitespace characters');\n }\n }\n\n /**\n * Whether the current DOM interface appears to be real (i.e. not simulated).\n *\n * @return {boolean}\n * Will be `true` if the DOM appears to be real, `false` otherwise.\n */\n function isReal() {\n // Both document and window will never be undefined thanks to `global`.\n return document === window.document;\n }\n\n /**\n * Determines, via duck typing, whether or not a value is a DOM element.\n *\n * @param {*} value\n * The value to check.\n *\n * @return {boolean}\n * Will be `true` if the value is a DOM element, `false` otherwise.\n */\n function isEl(value) {\n return isObject(value) && value.nodeType === 1;\n }\n\n /**\n * Determines if the current DOM is embedded in an iframe.\n *\n * @return {boolean}\n * Will be `true` if the DOM is embedded in an iframe, `false`\n * otherwise.\n */\n function isInFrame() {\n // We need a try/catch here because Safari will throw errors when attempting\n // to get either `parent` or `self`\n try {\n return window.parent !== window.self;\n } catch (x) {\n return true;\n }\n }\n\n /**\n * Creates functions to query the DOM using a given method.\n *\n * @private\n * @param {string} method\n * The method to create the query with.\n *\n * @return {Function}\n * The query method\n */\n function createQuerier(method) {\n return function (selector, context) {\n if (!isNonBlankString(selector)) {\n return document[method](null);\n }\n if (isNonBlankString(context)) {\n context = document.querySelector(context);\n }\n const ctx = isEl(context) ? context : document;\n return ctx[method] && ctx[method](selector);\n };\n }\n\n /**\n * Creates an element and applies properties, attributes, and inserts content.\n *\n * @param {string} [tagName='div']\n * Name of tag to be created.\n *\n * @param {Object} [properties={}]\n * Element properties to be applied.\n *\n * @param {Object} [attributes={}]\n * Element attributes to be applied.\n *\n * @param {ContentDescriptor} [content]\n * A content descriptor object.\n *\n * @return {Element}\n * The element that was created.\n */\n function createEl(tagName = 'div', properties = {}, attributes = {}, content) {\n const el = document.createElement(tagName);\n Object.getOwnPropertyNames(properties).forEach(function (propName) {\n const val = properties[propName];\n\n // Handle textContent since it's not supported everywhere and we have a\n // method for it.\n if (propName === 'textContent') {\n textContent(el, val);\n } else if (el[propName] !== val || propName === 'tabIndex') {\n el[propName] = val;\n }\n });\n Object.getOwnPropertyNames(attributes).forEach(function (attrName) {\n el.setAttribute(attrName, attributes[attrName]);\n });\n if (content) {\n appendContent(el, content);\n }\n return el;\n }\n\n /**\n * Injects text into an element, replacing any existing contents entirely.\n *\n * @param {HTMLElement} el\n * The element to add text content into\n *\n * @param {string} text\n * The text content to add.\n *\n * @return {Element}\n * The element with added text content.\n */\n function textContent(el, text) {\n if (typeof el.textContent === 'undefined') {\n el.innerText = text;\n } else {\n el.textContent = text;\n }\n return el;\n }\n\n /**\n * Insert an element as the first child node of another\n *\n * @param {Element} child\n * Element to insert\n *\n * @param {Element} parent\n * Element to insert child into\n */\n function prependTo(child, parent) {\n if (parent.firstChild) {\n parent.insertBefore(child, parent.firstChild);\n } else {\n parent.appendChild(child);\n }\n }\n\n /**\n * Check if an element has a class name.\n *\n * @param {Element} element\n * Element to check\n *\n * @param {string} classToCheck\n * Class name to check for\n *\n * @return {boolean}\n * Will be `true` if the element has a class, `false` otherwise.\n *\n * @throws {Error}\n * Throws an error if `classToCheck` has white space.\n */\n function hasClass(element, classToCheck) {\n throwIfWhitespace(classToCheck);\n return element.classList.contains(classToCheck);\n }\n\n /**\n * Add a class name to an element.\n *\n * @param {Element} element\n * Element to add class name to.\n *\n * @param {...string} classesToAdd\n * One or more class name to add.\n *\n * @return {Element}\n * The DOM element with the added class name.\n */\n function addClass(element, ...classesToAdd) {\n element.classList.add(...classesToAdd.reduce((prev, current) => prev.concat(current.split(/\\s+/)), []));\n return element;\n }\n\n /**\n * Remove a class name from an element.\n *\n * @param {Element} element\n * Element to remove a class name from.\n *\n * @param {...string} classesToRemove\n * One or more class name to remove.\n *\n * @return {Element}\n * The DOM element with class name removed.\n */\n function removeClass(element, ...classesToRemove) {\n // Protect in case the player gets disposed\n if (!element) {\n log.warn(\"removeClass was called with an element that doesn't exist\");\n return null;\n }\n element.classList.remove(...classesToRemove.reduce((prev, current) => prev.concat(current.split(/\\s+/)), []));\n return element;\n }\n\n /**\n * The callback definition for toggleClass.\n *\n * @callback PredicateCallback\n * @param {Element} element\n * The DOM element of the Component.\n *\n * @param {string} classToToggle\n * The `className` that wants to be toggled\n *\n * @return {boolean|undefined}\n * If `true` is returned, the `classToToggle` will be added to the\n * `element`, but not removed. If `false`, the `classToToggle` will be removed from\n * the `element`, but not added. If `undefined`, the callback will be ignored.\n *\n */\n\n /**\n * Adds or removes a class name to/from an element depending on an optional\n * condition or the presence/absence of the class name.\n *\n * @param {Element} element\n * The element to toggle a class name on.\n *\n * @param {string} classToToggle\n * The class that should be toggled.\n *\n * @param {boolean|PredicateCallback} [predicate]\n * See the return value for {@link module:dom~PredicateCallback}\n *\n * @return {Element}\n * The element with a class that has been toggled.\n */\n function toggleClass(element, classToToggle, predicate) {\n if (typeof predicate === 'function') {\n predicate = predicate(element, classToToggle);\n }\n if (typeof predicate !== 'boolean') {\n predicate = undefined;\n }\n classToToggle.split(/\\s+/).forEach(className => element.classList.toggle(className, predicate));\n return element;\n }\n\n /**\n * Apply attributes to an HTML element.\n *\n * @param {Element} el\n * Element to add attributes to.\n *\n * @param {Object} [attributes]\n * Attributes to be applied.\n */\n function setAttributes(el, attributes) {\n Object.getOwnPropertyNames(attributes).forEach(function (attrName) {\n const attrValue = attributes[attrName];\n if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) {\n el.removeAttribute(attrName);\n } else {\n el.setAttribute(attrName, attrValue === true ? '' : attrValue);\n }\n });\n }\n\n /**\n * Get an element's attribute values, as defined on the HTML tag.\n *\n * Attributes are not the same as properties. They're defined on the tag\n * or with setAttribute.\n *\n * @param {Element} tag\n * Element from which to get tag attributes.\n *\n * @return {Object}\n * All attributes of the element. Boolean attributes will be `true` or\n * `false`, others will be strings.\n */\n function getAttributes(tag) {\n const obj = {};\n\n // known boolean attributes\n // we can check for matching boolean properties, but not all browsers\n // and not all tags know about these attributes, so, we still want to check them manually\n const knownBooleans = ['autoplay', 'controls', 'playsinline', 'loop', 'muted', 'default', 'defaultMuted'];\n if (tag && tag.attributes && tag.attributes.length > 0) {\n const attrs = tag.attributes;\n for (let i = attrs.length - 1; i >= 0; i--) {\n const attrName = attrs[i].name;\n /** @type {boolean|string} */\n let attrVal = attrs[i].value;\n\n // check for known booleans\n // the matching element property will return a value for typeof\n if (knownBooleans.includes(attrName)) {\n // the value of an included boolean attribute is typically an empty\n // string ('') which would equal false if we just check for a false value.\n // we also don't want support bad code like autoplay='false'\n attrVal = attrVal !== null ? true : false;\n }\n obj[attrName] = attrVal;\n }\n }\n return obj;\n }\n\n /**\n * Get the value of an element's attribute.\n *\n * @param {Element} el\n * A DOM element.\n *\n * @param {string} attribute\n * Attribute to get the value of.\n *\n * @return {string}\n * The value of the attribute.\n */\n function getAttribute(el, attribute) {\n return el.getAttribute(attribute);\n }\n\n /**\n * Set the value of an element's attribute.\n *\n * @param {Element} el\n * A DOM element.\n *\n * @param {string} attribute\n * Attribute to set.\n *\n * @param {string} value\n * Value to set the attribute to.\n */\n function setAttribute(el, attribute, value) {\n el.setAttribute(attribute, value);\n }\n\n /**\n * Remove an element's attribute.\n *\n * @param {Element} el\n * A DOM element.\n *\n * @param {string} attribute\n * Attribute to remove.\n */\n function removeAttribute(el, attribute) {\n el.removeAttribute(attribute);\n }\n\n /**\n * Attempt to block the ability to select text.\n */\n function blockTextSelection() {\n document.body.focus();\n document.onselectstart = function () {\n return false;\n };\n }\n\n /**\n * Turn off text selection blocking.\n */\n function unblockTextSelection() {\n document.onselectstart = function () {\n return true;\n };\n }\n\n /**\n * Identical to the native `getBoundingClientRect` function, but ensures that\n * the method is supported at all (it is in all browsers we claim to support)\n * and that the element is in the DOM before continuing.\n *\n * This wrapper function also shims properties which are not provided by some\n * older browsers (namely, IE8).\n *\n * Additionally, some browsers do not support adding properties to a\n * `ClientRect`/`DOMRect` object; so, we shallow-copy it with the standard\n * properties (except `x` and `y` which are not widely supported). This helps\n * avoid implementations where keys are non-enumerable.\n *\n * @param {Element} el\n * Element whose `ClientRect` we want to calculate.\n *\n * @return {Object|undefined}\n * Always returns a plain object - or `undefined` if it cannot.\n */\n function getBoundingClientRect(el) {\n if (el && el.getBoundingClientRect && el.parentNode) {\n const rect = el.getBoundingClientRect();\n const result = {};\n ['bottom', 'height', 'left', 'right', 'top', 'width'].forEach(k => {\n if (rect[k] !== undefined) {\n result[k] = rect[k];\n }\n });\n if (!result.height) {\n result.height = parseFloat(computedStyle(el, 'height'));\n }\n if (!result.width) {\n result.width = parseFloat(computedStyle(el, 'width'));\n }\n return result;\n }\n }\n\n /**\n * Represents the position of a DOM element on the page.\n *\n * @typedef {Object} module:dom~Position\n *\n * @property {number} left\n * Pixels to the left.\n *\n * @property {number} top\n * Pixels from the top.\n */\n\n /**\n * Get the position of an element in the DOM.\n *\n * Uses `getBoundingClientRect` technique from John Resig.\n *\n * @see http://ejohn.org/blog/getboundingclientrect-is-awesome/\n *\n * @param {Element} el\n * Element from which to get offset.\n *\n * @return {module:dom~Position}\n * The position of the element that was passed in.\n */\n function findPosition(el) {\n if (!el || el && !el.offsetParent) {\n return {\n left: 0,\n top: 0,\n width: 0,\n height: 0\n };\n }\n const width = el.offsetWidth;\n const height = el.offsetHeight;\n let left = 0;\n let top = 0;\n while (el.offsetParent && el !== document[FullscreenApi.fullscreenElement]) {\n left += el.offsetLeft;\n top += el.offsetTop;\n el = el.offsetParent;\n }\n return {\n left,\n top,\n width,\n height\n };\n }\n\n /**\n * Represents x and y coordinates for a DOM element or mouse pointer.\n *\n * @typedef {Object} module:dom~Coordinates\n *\n * @property {number} x\n * x coordinate in pixels\n *\n * @property {number} y\n * y coordinate in pixels\n */\n\n /**\n * Get the pointer position within an element.\n *\n * The base on the coordinates are the bottom left of the element.\n *\n * @param {Element} el\n * Element on which to get the pointer position on.\n *\n * @param {Event} event\n * Event object.\n *\n * @return {module:dom~Coordinates}\n * A coordinates object corresponding to the mouse position.\n *\n */\n function getPointerPosition(el, event) {\n const translated = {\n x: 0,\n y: 0\n };\n if (IS_IOS) {\n let item = el;\n while (item && item.nodeName.toLowerCase() !== 'html') {\n const transform = computedStyle(item, 'transform');\n if (/^matrix/.test(transform)) {\n const values = transform.slice(7, -1).split(/,\\s/).map(Number);\n translated.x += values[4];\n translated.y += values[5];\n } else if (/^matrix3d/.test(transform)) {\n const values = transform.slice(9, -1).split(/,\\s/).map(Number);\n translated.x += values[12];\n translated.y += values[13];\n }\n if (item.assignedSlot && item.assignedSlot.parentElement && window.WebKitCSSMatrix) {\n const transformValue = window.getComputedStyle(item.assignedSlot.parentElement).transform;\n const matrix = new window.WebKitCSSMatrix(transformValue);\n translated.x += matrix.m41;\n translated.y += matrix.m42;\n }\n item = item.parentNode || item.host;\n }\n }\n const position = {};\n const boxTarget = findPosition(event.target);\n const box = findPosition(el);\n const boxW = box.width;\n const boxH = box.height;\n let offsetY = event.offsetY - (box.top - boxTarget.top);\n let offsetX = event.offsetX - (box.left - boxTarget.left);\n if (event.changedTouches) {\n offsetX = event.changedTouches[0].pageX - box.left;\n offsetY = event.changedTouches[0].pageY + box.top;\n if (IS_IOS) {\n offsetX -= translated.x;\n offsetY -= translated.y;\n }\n }\n position.y = 1 - Math.max(0, Math.min(1, offsetY / boxH));\n position.x = Math.max(0, Math.min(1, offsetX / boxW));\n return position;\n }\n\n /**\n * Determines, via duck typing, whether or not a value is a text node.\n *\n * @param {*} value\n * Check if this value is a text node.\n *\n * @return {boolean}\n * Will be `true` if the value is a text node, `false` otherwise.\n */\n function isTextNode(value) {\n return isObject(value) && value.nodeType === 3;\n }\n\n /**\n * Empties the contents of an element.\n *\n * @param {Element} el\n * The element to empty children from\n *\n * @return {Element}\n * The element with no children\n */\n function emptyEl(el) {\n while (el.firstChild) {\n el.removeChild(el.firstChild);\n }\n return el;\n }\n\n /**\n * This is a mixed value that describes content to be injected into the DOM\n * via some method. It can be of the following types:\n *\n * Type | Description\n * -----------|-------------\n * `string` | The value will be normalized into a text node.\n * `Element` | The value will be accepted as-is.\n * `Text` | A TextNode. The value will be accepted as-is.\n * `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).\n * `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.\n *\n * @typedef {string|Element|Text|Array|Function} ContentDescriptor\n */\n\n /**\n * Normalizes content for eventual insertion into the DOM.\n *\n * This allows a wide range of content definition methods, but helps protect\n * from falling into the trap of simply writing to `innerHTML`, which could\n * be an XSS concern.\n *\n * The content for an element can be passed in multiple types and\n * combinations, whose behavior is as follows:\n *\n * @param {ContentDescriptor} content\n * A content descriptor value.\n *\n * @return {Array}\n * All of the content that was passed in, normalized to an array of\n * elements or text nodes.\n */\n function normalizeContent(content) {\n // First, invoke content if it is a function. If it produces an array,\n // that needs to happen before normalization.\n if (typeof content === 'function') {\n content = content();\n }\n\n // Next up, normalize to an array, so one or many items can be normalized,\n // filtered, and returned.\n return (Array.isArray(content) ? content : [content]).map(value => {\n // First, invoke value if it is a function to produce a new value,\n // which will be subsequently normalized to a Node of some kind.\n if (typeof value === 'function') {\n value = value();\n }\n if (isEl(value) || isTextNode(value)) {\n return value;\n }\n if (typeof value === 'string' && /\\S/.test(value)) {\n return document.createTextNode(value);\n }\n }).filter(value => value);\n }\n\n /**\n * Normalizes and appends content to an element.\n *\n * @param {Element} el\n * Element to append normalized content to.\n *\n * @param {ContentDescriptor} content\n * A content descriptor value.\n *\n * @return {Element}\n * The element with appended normalized content.\n */\n function appendContent(el, content) {\n normalizeContent(content).forEach(node => el.appendChild(node));\n return el;\n }\n\n /**\n * Normalizes and inserts content into an element; this is identical to\n * `appendContent()`, except it empties the element first.\n *\n * @param {Element} el\n * Element to insert normalized content into.\n *\n * @param {ContentDescriptor} content\n * A content descriptor value.\n *\n * @return {Element}\n * The element with inserted normalized content.\n */\n function insertContent(el, content) {\n return appendContent(emptyEl(el), content);\n }\n\n /**\n * Check if an event was a single left click.\n *\n * @param {MouseEvent} event\n * Event object.\n *\n * @return {boolean}\n * Will be `true` if a single left click, `false` otherwise.\n */\n function isSingleLeftClick(event) {\n // Note: if you create something draggable, be sure to\n // call it on both `mousedown` and `mousemove` event,\n // otherwise `mousedown` should be enough for a button\n\n if (event.button === undefined && event.buttons === undefined) {\n // Why do we need `buttons` ?\n // Because, middle mouse sometimes have this:\n // e.button === 0 and e.buttons === 4\n // Furthermore, we want to prevent combination click, something like\n // HOLD middlemouse then left click, that would be\n // e.button === 0, e.buttons === 5\n // just `button` is not gonna work\n\n // Alright, then what this block does ?\n // this is for chrome `simulate mobile devices`\n // I want to support this as well\n\n return true;\n }\n if (event.button === 0 && event.buttons === undefined) {\n // Touch screen, sometimes on some specific device, `buttons`\n // doesn't have anything (safari on ios, blackberry...)\n\n return true;\n }\n\n // `mouseup` event on a single left click has\n // `button` and `buttons` equal to 0\n if (event.type === 'mouseup' && event.button === 0 && event.buttons === 0) {\n return true;\n }\n\n // MacOS Sonoma trackpad when \"tap to click enabled\"\n if (event.type === 'mousedown' && event.button === 0 && event.buttons === 0) {\n return true;\n }\n if (event.button !== 0 || event.buttons !== 1) {\n // This is the reason we have those if else block above\n // if any special case we can catch and let it slide\n // we do it above, when get to here, this definitely\n // is-not-left-click\n\n return false;\n }\n return true;\n }\n\n /**\n * Finds a single DOM element matching `selector` within the optional\n * `context` of another DOM element (defaulting to `document`).\n *\n * @param {string} selector\n * A valid CSS selector, which will be passed to `querySelector`.\n *\n * @param {Element|String} [context=document]\n * A DOM element within which to query. Can also be a selector\n * string in which case the first matching element will be used\n * as context. If missing (or no element matches selector), falls\n * back to `document`.\n *\n * @return {Element|null}\n * The element that was found or null.\n */\n const $ = createQuerier('querySelector');\n\n /**\n * Finds a all DOM elements matching `selector` within the optional\n * `context` of another DOM element (defaulting to `document`).\n *\n * @param {string} selector\n * A valid CSS selector, which will be passed to `querySelectorAll`.\n *\n * @param {Element|String} [context=document]\n * A DOM element within which to query. Can also be a selector\n * string in which case the first matching element will be used\n * as context. If missing (or no element matches selector), falls\n * back to `document`.\n *\n * @return {NodeList}\n * A element list of elements that were found. Will be empty if none\n * were found.\n *\n */\n const $$ = createQuerier('querySelectorAll');\n\n /**\n * A safe getComputedStyle.\n *\n * This is needed because in Firefox, if the player is loaded in an iframe with\n * `display:none`, then `getComputedStyle` returns `null`, so, we do a\n * null-check to make sure that the player doesn't break in these cases.\n *\n * @param {Element} el\n * The element you want the computed style of\n *\n * @param {string} prop\n * The property name you want\n *\n * @see https://bugzilla.mozilla.org/show_bug.cgi?id=548397\n */\n function computedStyle(el, prop) {\n if (!el || !prop) {\n return '';\n }\n if (typeof window.getComputedStyle === 'function') {\n let computedStyleValue;\n try {\n computedStyleValue = window.getComputedStyle(el);\n } catch (e) {\n return '';\n }\n return computedStyleValue ? computedStyleValue.getPropertyValue(prop) || computedStyleValue[prop] : '';\n }\n return '';\n }\n\n /**\n * Copy document style sheets to another window.\n *\n * @param {Window} win\n * The window element you want to copy the document style sheets to.\n *\n */\n function copyStyleSheetsToWindow(win) {\n [...document.styleSheets].forEach(styleSheet => {\n try {\n const cssRules = [...styleSheet.cssRules].map(rule => rule.cssText).join('');\n const style = document.createElement('style');\n style.textContent = cssRules;\n win.document.head.appendChild(style);\n } catch (e) {\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.type = styleSheet.type;\n // For older Safari this has to be the string; on other browsers setting the MediaList works\n link.media = styleSheet.media.mediaText;\n link.href = styleSheet.href;\n win.document.head.appendChild(link);\n }\n });\n }\n\n var Dom = /*#__PURE__*/Object.freeze({\n __proto__: null,\n isReal: isReal,\n isEl: isEl,\n isInFrame: isInFrame,\n createEl: createEl,\n textContent: textContent,\n prependTo: prependTo,\n hasClass: hasClass,\n addClass: addClass,\n removeClass: removeClass,\n toggleClass: toggleClass,\n setAttributes: setAttributes,\n getAttributes: getAttributes,\n getAttribute: getAttribute,\n setAttribute: setAttribute,\n removeAttribute: removeAttribute,\n blockTextSelection: blockTextSelection,\n unblockTextSelection: unblockTextSelection,\n getBoundingClientRect: getBoundingClientRect,\n findPosition: findPosition,\n getPointerPosition: getPointerPosition,\n isTextNode: isTextNode,\n emptyEl: emptyEl,\n normalizeContent: normalizeContent,\n appendContent: appendContent,\n insertContent: insertContent,\n isSingleLeftClick: isSingleLeftClick,\n $: $,\n $$: $$,\n computedStyle: computedStyle,\n copyStyleSheetsToWindow: copyStyleSheetsToWindow\n });\n\n /**\n * @file setup.js - Functions for setting up a player without\n * user interaction based on the data-setup `attribute` of the video tag.\n *\n * @module setup\n */\n let _windowLoaded = false;\n let videojs$1;\n\n /**\n * Set up any tags that have a data-setup `attribute` when the player is started.\n */\n const autoSetup = function () {\n if (videojs$1.options.autoSetup === false) {\n return;\n }\n const vids = Array.prototype.slice.call(document.getElementsByTagName('video'));\n const audios = Array.prototype.slice.call(document.getElementsByTagName('audio'));\n const divs = Array.prototype.slice.call(document.getElementsByTagName('video-js'));\n const mediaEls = vids.concat(audios, divs);\n\n // Check if any media elements exist\n if (mediaEls && mediaEls.length > 0) {\n for (let i = 0, e = mediaEls.length; i < e; i++) {\n const mediaEl = mediaEls[i];\n\n // Check if element exists, has getAttribute func.\n if (mediaEl && mediaEl.getAttribute) {\n // Make sure this player hasn't already been set up.\n if (mediaEl.player === undefined) {\n const options = mediaEl.getAttribute('data-setup');\n\n // Check if data-setup attr exists.\n // We only auto-setup if they've added the data-setup attr.\n if (options !== null) {\n // Create new video.js instance.\n videojs$1(mediaEl);\n }\n }\n\n // If getAttribute isn't defined, we need to wait for the DOM.\n } else {\n autoSetupTimeout(1);\n break;\n }\n }\n\n // No videos were found, so keep looping unless page is finished loading.\n } else if (!_windowLoaded) {\n autoSetupTimeout(1);\n }\n };\n\n /**\n * Wait until the page is loaded before running autoSetup. This will be called in\n * autoSetup if `hasLoaded` returns false.\n *\n * @param {number} wait\n * How long to wait in ms\n *\n * @param {module:videojs} [vjs]\n * The videojs library function\n */\n function autoSetupTimeout(wait, vjs) {\n // Protect against breakage in non-browser environments\n if (!isReal()) {\n return;\n }\n if (vjs) {\n videojs$1 = vjs;\n }\n window.setTimeout(autoSetup, wait);\n }\n\n /**\n * Used to set the internal tracking of window loaded state to true.\n *\n * @private\n */\n function setWindowLoaded() {\n _windowLoaded = true;\n window.removeEventListener('load', setWindowLoaded);\n }\n if (isReal()) {\n if (document.readyState === 'complete') {\n setWindowLoaded();\n } else {\n /**\n * Listen for the load event on window, and set _windowLoaded to true.\n *\n * We use a standard event listener here to avoid incrementing the GUID\n * before any players are created.\n *\n * @listens load\n */\n window.addEventListener('load', setWindowLoaded);\n }\n }\n\n /**\n * @file stylesheet.js\n * @module stylesheet\n */\n\n /**\n * Create a DOM style element given a className for it.\n *\n * @param {string} className\n * The className to add to the created style element.\n *\n * @return {Element}\n * The element that was created.\n */\n const createStyleElement = function (className) {\n const style = document.createElement('style');\n style.className = className;\n return style;\n };\n\n /**\n * Add text to a DOM element.\n *\n * @param {Element} el\n * The Element to add text content to.\n *\n * @param {string} content\n * The text to add to the element.\n */\n const setTextContent = function (el, content) {\n if (el.styleSheet) {\n el.styleSheet.cssText = content;\n } else {\n el.textContent = content;\n }\n };\n\n /**\n * @file dom-data.js\n * @module dom-data\n */\n\n /**\n * Element Data Store.\n *\n * Allows for binding data to an element without putting it directly on the\n * element. Ex. Event listeners are stored here.\n * (also from jsninja.com, slightly modified and updated for closure compiler)\n *\n * @type {Object}\n * @private\n */\n var DomData = new WeakMap();\n\n /**\n * @file guid.js\n * @module guid\n */\n\n // Default value for GUIDs. This allows us to reset the GUID counter in tests.\n //\n // The initial GUID is 3 because some users have come to rely on the first\n // default player ID ending up as `vjs_video_3`.\n //\n // See: https://github.com/videojs/video.js/pull/6216\n const _initialGuid = 3;\n\n /**\n * Unique ID for an element or function\n *\n * @type {Number}\n */\n let _guid = _initialGuid;\n\n /**\n * Get a unique auto-incrementing ID by number that has not been returned before.\n *\n * @return {number}\n * A new unique ID.\n */\n function newGUID() {\n return _guid++;\n }\n\n /**\n * @file events.js. An Event System (John Resig - Secrets of a JS Ninja http://jsninja.com/)\n * (Original book version wasn't completely usable, so fixed some things and made Closure Compiler compatible)\n * This should work very similarly to jQuery's events, however it's based off the book version which isn't as\n * robust as jquery's, so there's probably some differences.\n *\n * @file events.js\n * @module events\n */\n\n /**\n * Clean up the listener cache and dispatchers\n *\n * @param {Element|Object} elem\n * Element to clean up\n *\n * @param {string} type\n * Type of event to clean up\n */\n function _cleanUpEvents(elem, type) {\n if (!DomData.has(elem)) {\n return;\n }\n const data = DomData.get(elem);\n\n // Remove the events of a particular type if there are none left\n if (data.handlers[type].length === 0) {\n delete data.handlers[type];\n // data.handlers[type] = null;\n // Setting to null was causing an error with data.handlers\n\n // Remove the meta-handler from the element\n if (elem.removeEventListener) {\n elem.removeEventListener(type, data.dispatcher, false);\n } else if (elem.detachEvent) {\n elem.detachEvent('on' + type, data.dispatcher);\n }\n }\n\n // Remove the events object if there are no types left\n if (Object.getOwnPropertyNames(data.handlers).length <= 0) {\n delete data.handlers;\n delete data.dispatcher;\n delete data.disabled;\n }\n\n // Finally remove the element data if there is no data left\n if (Object.getOwnPropertyNames(data).length === 0) {\n DomData.delete(elem);\n }\n }\n\n /**\n * Loops through an array of event types and calls the requested method for each type.\n *\n * @param {Function} fn\n * The event method we want to use.\n *\n * @param {Element|Object} elem\n * Element or object to bind listeners to\n *\n * @param {string[]} types\n * Type of event to bind to.\n *\n * @param {Function} callback\n * Event listener.\n */\n function _handleMultipleEvents(fn, elem, types, callback) {\n types.forEach(function (type) {\n // Call the event method for each one of the types\n fn(elem, type, callback);\n });\n }\n\n /**\n * Fix a native event to have standard property values\n *\n * @param {Object} event\n * Event object to fix.\n *\n * @return {Object}\n * Fixed event object.\n */\n function fixEvent(event) {\n if (event.fixed_) {\n return event;\n }\n function returnTrue() {\n return true;\n }\n function returnFalse() {\n return false;\n }\n\n // Test if fixing up is needed\n // Used to check if !event.stopPropagation instead of isPropagationStopped\n // But native events return true for stopPropagation, but don't have\n // other expected methods like isPropagationStopped. Seems to be a problem\n // with the Javascript Ninja code. So we're just overriding all events now.\n if (!event || !event.isPropagationStopped || !event.isImmediatePropagationStopped) {\n const old = event || window.event;\n event = {};\n // Clone the old object so that we can modify the values event = {};\n // IE8 Doesn't like when you mess with native event properties\n // Firefox returns false for event.hasOwnProperty('type') and other props\n // which makes copying more difficult.\n\n // TODO: Probably best to create an allowlist of event props\n const deprecatedProps = ['layerX', 'layerY', 'keyLocation', 'path', 'webkitMovementX', 'webkitMovementY', 'mozPressure', 'mozInputSource'];\n for (const key in old) {\n // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y\n // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation\n // and webkitMovementX/Y\n // Lighthouse complains if Event.path is copied\n if (!deprecatedProps.includes(key)) {\n // Chrome 32+ warns if you try to copy deprecated returnValue, but\n // we still want to if preventDefault isn't supported (IE8).\n if (!(key === 'returnValue' && old.preventDefault)) {\n event[key] = old[key];\n }\n }\n }\n\n // The event occurred on this element\n if (!event.target) {\n event.target = event.srcElement || document;\n }\n\n // Handle which other element the event is related to\n if (!event.relatedTarget) {\n event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;\n }\n\n // Stop the default browser action\n event.preventDefault = function () {\n if (old.preventDefault) {\n old.preventDefault();\n }\n event.returnValue = false;\n old.returnValue = false;\n event.defaultPrevented = true;\n };\n event.defaultPrevented = false;\n\n // Stop the event from bubbling\n event.stopPropagation = function () {\n if (old.stopPropagation) {\n old.stopPropagation();\n }\n event.cancelBubble = true;\n old.cancelBubble = true;\n event.isPropagationStopped = returnTrue;\n };\n event.isPropagationStopped = returnFalse;\n\n // Stop the event from bubbling and executing other handlers\n event.stopImmediatePropagation = function () {\n if (old.stopImmediatePropagation) {\n old.stopImmediatePropagation();\n }\n event.isImmediatePropagationStopped = returnTrue;\n event.stopPropagation();\n };\n event.isImmediatePropagationStopped = returnFalse;\n\n // Handle mouse position\n if (event.clientX !== null && event.clientX !== undefined) {\n const doc = document.documentElement;\n const body = document.body;\n event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);\n event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);\n }\n\n // Handle key presses\n event.which = event.charCode || event.keyCode;\n\n // Fix button for mouse clicks:\n // 0 == left; 1 == middle; 2 == right\n if (event.button !== null && event.button !== undefined) {\n // The following is disabled because it does not pass videojs-standard\n // and... yikes.\n /* eslint-disable */\n event.button = event.button & 1 ? 0 : event.button & 4 ? 1 : event.button & 2 ? 2 : 0;\n /* eslint-enable */\n }\n }\n event.fixed_ = true;\n // Returns fixed-up instance\n return event;\n }\n\n /**\n * Whether passive event listeners are supported\n */\n let _supportsPassive;\n const supportsPassive = function () {\n if (typeof _supportsPassive !== 'boolean') {\n _supportsPassive = false;\n try {\n const opts = Object.defineProperty({}, 'passive', {\n get() {\n _supportsPassive = true;\n }\n });\n window.addEventListener('test', null, opts);\n window.removeEventListener('test', null, opts);\n } catch (e) {\n // disregard\n }\n }\n return _supportsPassive;\n };\n\n /**\n * Touch events Chrome expects to be passive\n */\n const passiveEvents = ['touchstart', 'touchmove'];\n\n /**\n * Add an event listener to element\n * It stores the handler function in a separate cache object\n * and adds a generic handler to the element's event,\n * along with a unique id (guid) to the element.\n *\n * @param {Element|Object} elem\n * Element or object to bind listeners to\n *\n * @param {string|string[]} type\n * Type of event to bind to.\n *\n * @param {Function} fn\n * Event listener.\n */\n function on(elem, type, fn) {\n if (Array.isArray(type)) {\n return _handleMultipleEvents(on, elem, type, fn);\n }\n if (!DomData.has(elem)) {\n DomData.set(elem, {});\n }\n const data = DomData.get(elem);\n\n // We need a place to store all our handler data\n if (!data.handlers) {\n data.handlers = {};\n }\n if (!data.handlers[type]) {\n data.handlers[type] = [];\n }\n if (!fn.guid) {\n fn.guid = newGUID();\n }\n data.handlers[type].push(fn);\n if (!data.dispatcher) {\n data.disabled = false;\n data.dispatcher = function (event, hash) {\n if (data.disabled) {\n return;\n }\n event = fixEvent(event);\n const handlers = data.handlers[event.type];\n if (handlers) {\n // Copy handlers so if handlers are added/removed during the process it doesn't throw everything off.\n const handlersCopy = handlers.slice(0);\n for (let m = 0, n = handlersCopy.length; m < n; m++) {\n if (event.isImmediatePropagationStopped()) {\n break;\n } else {\n try {\n handlersCopy[m].call(elem, event, hash);\n } catch (e) {\n log.error(e);\n }\n }\n }\n }\n };\n }\n if (data.handlers[type].length === 1) {\n if (elem.addEventListener) {\n let options = false;\n if (supportsPassive() && passiveEvents.indexOf(type) > -1) {\n options = {\n passive: true\n };\n }\n elem.addEventListener(type, data.dispatcher, options);\n } else if (elem.attachEvent) {\n elem.attachEvent('on' + type, data.dispatcher);\n }\n }\n }\n\n /**\n * Removes event listeners from an element\n *\n * @param {Element|Object} elem\n * Object to remove listeners from.\n *\n * @param {string|string[]} [type]\n * Type of listener to remove. Don't include to remove all events from element.\n *\n * @param {Function} [fn]\n * Specific listener to remove. Don't include to remove listeners for an event\n * type.\n */\n function off(elem, type, fn) {\n // Don't want to add a cache object through getElData if not needed\n if (!DomData.has(elem)) {\n return;\n }\n const data = DomData.get(elem);\n\n // If no events exist, nothing to unbind\n if (!data.handlers) {\n return;\n }\n if (Array.isArray(type)) {\n return _handleMultipleEvents(off, elem, type, fn);\n }\n\n // Utility function\n const removeType = function (el, t) {\n data.handlers[t] = [];\n _cleanUpEvents(el, t);\n };\n\n // Are we removing all bound events?\n if (type === undefined) {\n for (const t in data.handlers) {\n if (Object.prototype.hasOwnProperty.call(data.handlers || {}, t)) {\n removeType(elem, t);\n }\n }\n return;\n }\n const handlers = data.handlers[type];\n\n // If no handlers exist, nothing to unbind\n if (!handlers) {\n return;\n }\n\n // If no listener was provided, remove all listeners for type\n if (!fn) {\n removeType(elem, type);\n return;\n }\n\n // We're only removing a single handler\n if (fn.guid) {\n for (let n = 0; n < handlers.length; n++) {\n if (handlers[n].guid === fn.guid) {\n handlers.splice(n--, 1);\n }\n }\n }\n _cleanUpEvents(elem, type);\n }\n\n /**\n * Trigger an event for an element\n *\n * @param {Element|Object} elem\n * Element to trigger an event on\n *\n * @param {EventTarget~Event|string} event\n * A string (the type) or an event object with a type attribute\n *\n * @param {Object} [hash]\n * data hash to pass along with the event\n *\n * @return {boolean|undefined}\n * Returns the opposite of `defaultPrevented` if default was\n * prevented. Otherwise, returns `undefined`\n */\n function trigger(elem, event, hash) {\n // Fetches element data and a reference to the parent (for bubbling).\n // Don't want to add a data object to cache for every parent,\n // so checking hasElData first.\n const elemData = DomData.has(elem) ? DomData.get(elem) : {};\n const parent = elem.parentNode || elem.ownerDocument;\n // type = event.type || event,\n // handler;\n\n // If an event name was passed as a string, creates an event out of it\n if (typeof event === 'string') {\n event = {\n type: event,\n target: elem\n };\n } else if (!event.target) {\n event.target = elem;\n }\n\n // Normalizes the event properties.\n event = fixEvent(event);\n\n // If the passed element has a dispatcher, executes the established handlers.\n if (elemData.dispatcher) {\n elemData.dispatcher.call(elem, event, hash);\n }\n\n // Unless explicitly stopped or the event does not bubble (e.g. media events)\n // recursively calls this function to bubble the event up the DOM.\n if (parent && !event.isPropagationStopped() && event.bubbles === true) {\n trigger.call(null, parent, event, hash);\n\n // If at the top of the DOM, triggers the default action unless disabled.\n } else if (!parent && !event.defaultPrevented && event.target && event.target[event.type]) {\n if (!DomData.has(event.target)) {\n DomData.set(event.target, {});\n }\n const targetData = DomData.get(event.target);\n\n // Checks if the target has a default action for this event.\n if (event.target[event.type]) {\n // Temporarily disables event dispatching on the target as we have already executed the handler.\n targetData.disabled = true;\n // Executes the default action.\n if (typeof event.target[event.type] === 'function') {\n event.target[event.type]();\n }\n // Re-enables event dispatching.\n targetData.disabled = false;\n }\n }\n\n // Inform the triggerer if the default was prevented by returning false\n return !event.defaultPrevented;\n }\n\n /**\n * Trigger a listener only once for an event.\n *\n * @param {Element|Object} elem\n * Element or object to bind to.\n *\n * @param {string|string[]} type\n * Name/type of event\n *\n * @param {Event~EventListener} fn\n * Event listener function\n */\n function one(elem, type, fn) {\n if (Array.isArray(type)) {\n return _handleMultipleEvents(one, elem, type, fn);\n }\n const func = function () {\n off(elem, type, func);\n fn.apply(this, arguments);\n };\n\n // copy the guid to the new function so it can removed using the original function's ID\n func.guid = fn.guid = fn.guid || newGUID();\n on(elem, type, func);\n }\n\n /**\n * Trigger a listener only once and then turn if off for all\n * configured events\n *\n * @param {Element|Object} elem\n * Element or object to bind to.\n *\n * @param {string|string[]} type\n * Name/type of event\n *\n * @param {Event~EventListener} fn\n * Event listener function\n */\n function any(elem, type, fn) {\n const func = function () {\n off(elem, type, func);\n fn.apply(this, arguments);\n };\n\n // copy the guid to the new function so it can removed using the original function's ID\n func.guid = fn.guid = fn.guid || newGUID();\n\n // multiple ons, but one off for everything\n on(elem, type, func);\n }\n\n var Events = /*#__PURE__*/Object.freeze({\n __proto__: null,\n fixEvent: fixEvent,\n on: on,\n off: off,\n trigger: trigger,\n one: one,\n any: any\n });\n\n /**\n * @file fn.js\n * @module fn\n */\n const UPDATE_REFRESH_INTERVAL = 30;\n\n /**\n * A private, internal-only function for changing the context of a function.\n *\n * It also stores a unique id on the function so it can be easily removed from\n * events.\n *\n * @private\n * @function\n * @param {*} context\n * The object to bind as scope.\n *\n * @param {Function} fn\n * The function to be bound to a scope.\n *\n * @param {number} [uid]\n * An optional unique ID for the function to be set\n *\n * @return {Function}\n * The new function that will be bound into the context given\n */\n const bind_ = function (context, fn, uid) {\n // Make sure the function has a unique ID\n if (!fn.guid) {\n fn.guid = newGUID();\n }\n\n // Create the new function that changes the context\n const bound = fn.bind(context);\n\n // Allow for the ability to individualize this function\n // Needed in the case where multiple objects might share the same prototype\n // IF both items add an event listener with the same function, then you try to remove just one\n // it will remove both because they both have the same guid.\n // when using this, you need to use the bind method when you remove the listener as well.\n // currently used in text tracks\n bound.guid = uid ? uid + '_' + fn.guid : fn.guid;\n return bound;\n };\n\n /**\n * Wraps the given function, `fn`, with a new function that only invokes `fn`\n * at most once per every `wait` milliseconds.\n *\n * @function\n * @param {Function} fn\n * The function to be throttled.\n *\n * @param {number} wait\n * The number of milliseconds by which to throttle.\n *\n * @return {Function}\n */\n const throttle = function (fn, wait) {\n let last = window.performance.now();\n const throttled = function (...args) {\n const now = window.performance.now();\n if (now - last >= wait) {\n fn(...args);\n last = now;\n }\n };\n return throttled;\n };\n\n /**\n * Creates a debounced function that delays invoking `func` until after `wait`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked.\n *\n * Inspired by lodash and underscore implementations.\n *\n * @function\n * @param {Function} func\n * The function to wrap with debounce behavior.\n *\n * @param {number} wait\n * The number of milliseconds to wait after the last invocation.\n *\n * @param {boolean} [immediate]\n * Whether or not to invoke the function immediately upon creation.\n *\n * @param {Object} [context=window]\n * The \"context\" in which the debounced function should debounce. For\n * example, if this function should be tied to a Video.js player,\n * the player can be passed here. Alternatively, defaults to the\n * global `window` object.\n *\n * @return {Function}\n * A debounced function.\n */\n const debounce = function (func, wait, immediate, context = window) {\n let timeout;\n const cancel = () => {\n context.clearTimeout(timeout);\n timeout = null;\n };\n\n /* eslint-disable consistent-this */\n const debounced = function () {\n const self = this;\n const args = arguments;\n let later = function () {\n timeout = null;\n later = null;\n if (!immediate) {\n func.apply(self, args);\n }\n };\n if (!timeout && immediate) {\n func.apply(self, args);\n }\n context.clearTimeout(timeout);\n timeout = context.setTimeout(later, wait);\n };\n /* eslint-enable consistent-this */\n\n debounced.cancel = cancel;\n return debounced;\n };\n\n var Fn = /*#__PURE__*/Object.freeze({\n __proto__: null,\n UPDATE_REFRESH_INTERVAL: UPDATE_REFRESH_INTERVAL,\n bind_: bind_,\n throttle: throttle,\n debounce: debounce\n });\n\n /**\n * @file src/js/event-target.js\n */\n let EVENT_MAP;\n\n /**\n * `EventTarget` is a class that can have the same API as the DOM `EventTarget`. It\n * adds shorthand functions that wrap around lengthy functions. For example:\n * the `on` function is a wrapper around `addEventListener`.\n *\n * @see [EventTarget Spec]{@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget}\n * @class EventTarget\n */\n class EventTarget {\n /**\n * Adds an `event listener` to an instance of an `EventTarget`. An `event listener` is a\n * function that will get called when an event with a certain name gets triggered.\n *\n * @param {string|string[]} type\n * An event name or an array of event names.\n *\n * @param {Function} fn\n * The function to call with `EventTarget`s\n */\n on(type, fn) {\n // Remove the addEventListener alias before calling Events.on\n // so we don't get into an infinite type loop\n const ael = this.addEventListener;\n this.addEventListener = () => {};\n on(this, type, fn);\n this.addEventListener = ael;\n }\n /**\n * Removes an `event listener` for a specific event from an instance of `EventTarget`.\n * This makes it so that the `event listener` will no longer get called when the\n * named event happens.\n *\n * @param {string|string[]} type\n * An event name or an array of event names.\n *\n * @param {Function} fn\n * The function to remove.\n */\n off(type, fn) {\n off(this, type, fn);\n }\n /**\n * This function will add an `event listener` that gets triggered only once. After the\n * first trigger it will get removed. This is like adding an `event listener`\n * with {@link EventTarget#on} that calls {@link EventTarget#off} on itself.\n *\n * @param {string|string[]} type\n * An event name or an array of event names.\n *\n * @param {Function} fn\n * The function to be called once for each event name.\n */\n one(type, fn) {\n // Remove the addEventListener aliasing Events.on\n // so we don't get into an infinite type loop\n const ael = this.addEventListener;\n this.addEventListener = () => {};\n one(this, type, fn);\n this.addEventListener = ael;\n }\n /**\n * This function will add an `event listener` that gets triggered only once and is\n * removed from all events. This is like adding an array of `event listener`s\n * with {@link EventTarget#on} that calls {@link EventTarget#off} on all events the\n * first time it is triggered.\n *\n * @param {string|string[]} type\n * An event name or an array of event names.\n *\n * @param {Function} fn\n * The function to be called once for each event name.\n */\n any(type, fn) {\n // Remove the addEventListener aliasing Events.on\n // so we don't get into an infinite type loop\n const ael = this.addEventListener;\n this.addEventListener = () => {};\n any(this, type, fn);\n this.addEventListener = ael;\n }\n /**\n * This function causes an event to happen. This will then cause any `event listeners`\n * that are waiting for that event, to get called. If there are no `event listeners`\n * for an event then nothing will happen.\n *\n * If the name of the `Event` that is being triggered is in `EventTarget.allowedEvents_`.\n * Trigger will also call the `on` + `uppercaseEventName` function.\n *\n * Example:\n * 'click' is in `EventTarget.allowedEvents_`, so, trigger will attempt to call\n * `onClick` if it exists.\n *\n * @param {string|EventTarget~Event|Object} event\n * The name of the event, an `Event`, or an object with a key of type set to\n * an event name.\n */\n trigger(event) {\n const type = event.type || event;\n\n // deprecation\n // In a future version we should default target to `this`\n // similar to how we default the target to `elem` in\n // `Events.trigger`. Right now the default `target` will be\n // `document` due to the `Event.fixEvent` call.\n if (typeof event === 'string') {\n event = {\n type\n };\n }\n event = fixEvent(event);\n if (this.allowedEvents_[type] && this['on' + type]) {\n this['on' + type](event);\n }\n trigger(this, event);\n }\n queueTrigger(event) {\n // only set up EVENT_MAP if it'll be used\n if (!EVENT_MAP) {\n EVENT_MAP = new Map();\n }\n const type = event.type || event;\n let map = EVENT_MAP.get(this);\n if (!map) {\n map = new Map();\n EVENT_MAP.set(this, map);\n }\n const oldTimeout = map.get(type);\n map.delete(type);\n window.clearTimeout(oldTimeout);\n const timeout = window.setTimeout(() => {\n map.delete(type);\n // if we cleared out all timeouts for the current target, delete its map\n if (map.size === 0) {\n map = null;\n EVENT_MAP.delete(this);\n }\n this.trigger(event);\n }, 0);\n map.set(type, timeout);\n }\n }\n\n /**\n * A Custom DOM event.\n *\n * @typedef {CustomEvent} Event\n * @see [Properties]{@link https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent}\n */\n\n /**\n * All event listeners should follow the following format.\n *\n * @callback EventListener\n * @this {EventTarget}\n *\n * @param {Event} event\n * the event that triggered this function\n *\n * @param {Object} [hash]\n * hash of data sent during the event\n */\n\n /**\n * An object containing event names as keys and booleans as values.\n *\n * > NOTE: If an event name is set to a true value here {@link EventTarget#trigger}\n * will have extra functionality. See that function for more information.\n *\n * @property EventTarget.prototype.allowedEvents_\n * @protected\n */\n EventTarget.prototype.allowedEvents_ = {};\n\n /**\n * An alias of {@link EventTarget#on}. Allows `EventTarget` to mimic\n * the standard DOM API.\n *\n * @function\n * @see {@link EventTarget#on}\n */\n EventTarget.prototype.addEventListener = EventTarget.prototype.on;\n\n /**\n * An alias of {@link EventTarget#off}. Allows `EventTarget` to mimic\n * the standard DOM API.\n *\n * @function\n * @see {@link EventTarget#off}\n */\n EventTarget.prototype.removeEventListener = EventTarget.prototype.off;\n\n /**\n * An alias of {@link EventTarget#trigger}. Allows `EventTarget` to mimic\n * the standard DOM API.\n *\n * @function\n * @see {@link EventTarget#trigger}\n */\n EventTarget.prototype.dispatchEvent = EventTarget.prototype.trigger;\n\n /**\n * @file mixins/evented.js\n * @module evented\n */\n const objName = obj => {\n if (typeof obj.name === 'function') {\n return obj.name();\n }\n if (typeof obj.name === 'string') {\n return obj.name;\n }\n if (obj.name_) {\n return obj.name_;\n }\n if (obj.constructor && obj.constructor.name) {\n return obj.constructor.name;\n }\n return typeof obj;\n };\n\n /**\n * Returns whether or not an object has had the evented mixin applied.\n *\n * @param {Object} object\n * An object to test.\n *\n * @return {boolean}\n * Whether or not the object appears to be evented.\n */\n const isEvented = object => object instanceof EventTarget || !!object.eventBusEl_ && ['on', 'one', 'off', 'trigger'].every(k => typeof object[k] === 'function');\n\n /**\n * Adds a callback to run after the evented mixin applied.\n *\n * @param {Object} target\n * An object to Add\n * @param {Function} callback\n * The callback to run.\n */\n const addEventedCallback = (target, callback) => {\n if (isEvented(target)) {\n callback();\n } else {\n if (!target.eventedCallbacks) {\n target.eventedCallbacks = [];\n }\n target.eventedCallbacks.push(callback);\n }\n };\n\n /**\n * Whether a value is a valid event type - non-empty string or array.\n *\n * @private\n * @param {string|Array} type\n * The type value to test.\n *\n * @return {boolean}\n * Whether or not the type is a valid event type.\n */\n const isValidEventType = type =>\n // The regex here verifies that the `type` contains at least one non-\n // whitespace character.\n typeof type === 'string' && /\\S/.test(type) || Array.isArray(type) && !!type.length;\n\n /**\n * Validates a value to determine if it is a valid event target. Throws if not.\n *\n * @private\n * @throws {Error}\n * If the target does not appear to be a valid event target.\n *\n * @param {Object} target\n * The object to test.\n *\n * @param {Object} obj\n * The evented object we are validating for\n *\n * @param {string} fnName\n * The name of the evented mixin function that called this.\n */\n const validateTarget = (target, obj, fnName) => {\n if (!target || !target.nodeName && !isEvented(target)) {\n throw new Error(`Invalid target for ${objName(obj)}#${fnName}; must be a DOM node or evented object.`);\n }\n };\n\n /**\n * Validates a value to determine if it is a valid event target. Throws if not.\n *\n * @private\n * @throws {Error}\n * If the type does not appear to be a valid event type.\n *\n * @param {string|Array} type\n * The type to test.\n *\n * @param {Object} obj\n * The evented object we are validating for\n *\n * @param {string} fnName\n * The name of the evented mixin function that called this.\n */\n const validateEventType = (type, obj, fnName) => {\n if (!isValidEventType(type)) {\n throw new Error(`Invalid event type for ${objName(obj)}#${fnName}; must be a non-empty string or array.`);\n }\n };\n\n /**\n * Validates a value to determine if it is a valid listener. Throws if not.\n *\n * @private\n * @throws {Error}\n * If the listener is not a function.\n *\n * @param {Function} listener\n * The listener to test.\n *\n * @param {Object} obj\n * The evented object we are validating for\n *\n * @param {string} fnName\n * The name of the evented mixin function that called this.\n */\n const validateListener = (listener, obj, fnName) => {\n if (typeof listener !== 'function') {\n throw new Error(`Invalid listener for ${objName(obj)}#${fnName}; must be a function.`);\n }\n };\n\n /**\n * Takes an array of arguments given to `on()` or `one()`, validates them, and\n * normalizes them into an object.\n *\n * @private\n * @param {Object} self\n * The evented object on which `on()` or `one()` was called. This\n * object will be bound as the `this` value for the listener.\n *\n * @param {Array} args\n * An array of arguments passed to `on()` or `one()`.\n *\n * @param {string} fnName\n * The name of the evented mixin function that called this.\n *\n * @return {Object}\n * An object containing useful values for `on()` or `one()` calls.\n */\n const normalizeListenArgs = (self, args, fnName) => {\n // If the number of arguments is less than 3, the target is always the\n // evented object itself.\n const isTargetingSelf = args.length < 3 || args[0] === self || args[0] === self.eventBusEl_;\n let target;\n let type;\n let listener;\n if (isTargetingSelf) {\n target = self.eventBusEl_;\n\n // Deal with cases where we got 3 arguments, but we are still listening to\n // the evented object itself.\n if (args.length >= 3) {\n args.shift();\n }\n [type, listener] = args;\n } else {\n // This was `[target, type, listener] = args;` but this block needs more than\n // one statement to produce minified output compatible with Chrome 53.\n // See https://github.com/videojs/video.js/pull/8810\n target = args[0];\n type = args[1];\n listener = args[2];\n }\n validateTarget(target, self, fnName);\n validateEventType(type, self, fnName);\n validateListener(listener, self, fnName);\n listener = bind_(self, listener);\n return {\n isTargetingSelf,\n target,\n type,\n listener\n };\n };\n\n /**\n * Adds the listener to the event type(s) on the target, normalizing for\n * the type of target.\n *\n * @private\n * @param {Element|Object} target\n * A DOM node or evented object.\n *\n * @param {string} method\n * The event binding method to use (\"on\" or \"one\").\n *\n * @param {string|Array} type\n * One or more event type(s).\n *\n * @param {Function} listener\n * A listener function.\n */\n const listen = (target, method, type, listener) => {\n validateTarget(target, target, method);\n if (target.nodeName) {\n Events[method](target, type, listener);\n } else {\n target[method](type, listener);\n }\n };\n\n /**\n * Contains methods that provide event capabilities to an object which is passed\n * to {@link module:evented|evented}.\n *\n * @mixin EventedMixin\n */\n const EventedMixin = {\n /**\n * Add a listener to an event (or events) on this object or another evented\n * object.\n *\n * @param {string|Array|Element|Object} targetOrType\n * If this is a string or array, it represents the event type(s)\n * that will trigger the listener.\n *\n * Another evented object can be passed here instead, which will\n * cause the listener to listen for events on _that_ object.\n *\n * In either case, the listener's `this` value will be bound to\n * this object.\n *\n * @param {string|Array|Function} typeOrListener\n * If the first argument was a string or array, this should be the\n * listener function. Otherwise, this is a string or array of event\n * type(s).\n *\n * @param {Function} [listener]\n * If the first argument was another evented object, this will be\n * the listener function.\n */\n on(...args) {\n const {\n isTargetingSelf,\n target,\n type,\n listener\n } = normalizeListenArgs(this, args, 'on');\n listen(target, 'on', type, listener);\n\n // If this object is listening to another evented object.\n if (!isTargetingSelf) {\n // If this object is disposed, remove the listener.\n const removeListenerOnDispose = () => this.off(target, type, listener);\n\n // Use the same function ID as the listener so we can remove it later it\n // using the ID of the original listener.\n removeListenerOnDispose.guid = listener.guid;\n\n // Add a listener to the target's dispose event as well. This ensures\n // that if the target is disposed BEFORE this object, we remove the\n // removal listener that was just added. Otherwise, we create a memory leak.\n const removeRemoverOnTargetDispose = () => this.off('dispose', removeListenerOnDispose);\n\n // Use the same function ID as the listener so we can remove it later\n // it using the ID of the original listener.\n removeRemoverOnTargetDispose.guid = listener.guid;\n listen(this, 'on', 'dispose', removeListenerOnDispose);\n listen(target, 'on', 'dispose', removeRemoverOnTargetDispose);\n }\n },\n /**\n * Add a listener to an event (or events) on this object or another evented\n * object. The listener will be called once per event and then removed.\n *\n * @param {string|Array|Element|Object} targetOrType\n * If this is a string or array, it represents the event type(s)\n * that will trigger the listener.\n *\n * Another evented object can be passed here instead, which will\n * cause the listener to listen for events on _that_ object.\n *\n * In either case, the listener's `this` value will be bound to\n * this object.\n *\n * @param {string|Array|Function} typeOrListener\n * If the first argument was a string or array, this should be the\n * listener function. Otherwise, this is a string or array of event\n * type(s).\n *\n * @param {Function} [listener]\n * If the first argument was another evented object, this will be\n * the listener function.\n */\n one(...args) {\n const {\n isTargetingSelf,\n target,\n type,\n listener\n } = normalizeListenArgs(this, args, 'one');\n\n // Targeting this evented object.\n if (isTargetingSelf) {\n listen(target, 'one', type, listener);\n\n // Targeting another evented object.\n } else {\n // TODO: This wrapper is incorrect! It should only\n // remove the wrapper for the event type that called it.\n // Instead all listeners are removed on the first trigger!\n // see https://github.com/videojs/video.js/issues/5962\n const wrapper = (...largs) => {\n this.off(target, type, wrapper);\n listener.apply(null, largs);\n };\n\n // Use the same function ID as the listener so we can remove it later\n // it using the ID of the original listener.\n wrapper.guid = listener.guid;\n listen(target, 'one', type, wrapper);\n }\n },\n /**\n * Add a listener to an event (or events) on this object or another evented\n * object. The listener will only be called once for the first event that is triggered\n * then removed.\n *\n * @param {string|Array|Element|Object} targetOrType\n * If this is a string or array, it represents the event type(s)\n * that will trigger the listener.\n *\n * Another evented object can be passed here instead, which will\n * cause the listener to listen for events on _that_ object.\n *\n * In either case, the listener's `this` value will be bound to\n * this object.\n *\n * @param {string|Array|Function} typeOrListener\n * If the first argument was a string or array, this should be the\n * listener function. Otherwise, this is a string or array of event\n * type(s).\n *\n * @param {Function} [listener]\n * If the first argument was another evented object, this will be\n * the listener function.\n */\n any(...args) {\n const {\n isTargetingSelf,\n target,\n type,\n listener\n } = normalizeListenArgs(this, args, 'any');\n\n // Targeting this evented object.\n if (isTargetingSelf) {\n listen(target, 'any', type, listener);\n\n // Targeting another evented object.\n } else {\n const wrapper = (...largs) => {\n this.off(target, type, wrapper);\n listener.apply(null, largs);\n };\n\n // Use the same function ID as the listener so we can remove it later\n // it using the ID of the original listener.\n wrapper.guid = listener.guid;\n listen(target, 'any', type, wrapper);\n }\n },\n /**\n * Removes listener(s) from event(s) on an evented object.\n *\n * @param {string|Array|Element|Object} [targetOrType]\n * If this is a string or array, it represents the event type(s).\n *\n * Another evented object can be passed here instead, in which case\n * ALL 3 arguments are _required_.\n *\n * @param {string|Array|Function} [typeOrListener]\n * If the first argument was a string or array, this may be the\n * listener function. Otherwise, this is a string or array of event\n * type(s).\n *\n * @param {Function} [listener]\n * If the first argument was another evented object, this will be\n * the listener function; otherwise, _all_ listeners bound to the\n * event type(s) will be removed.\n */\n off(targetOrType, typeOrListener, listener) {\n // Targeting this evented object.\n if (!targetOrType || isValidEventType(targetOrType)) {\n off(this.eventBusEl_, targetOrType, typeOrListener);\n\n // Targeting another evented object.\n } else {\n const target = targetOrType;\n const type = typeOrListener;\n\n // Fail fast and in a meaningful way!\n validateTarget(target, this, 'off');\n validateEventType(type, this, 'off');\n validateListener(listener, this, 'off');\n\n // Ensure there's at least a guid, even if the function hasn't been used\n listener = bind_(this, listener);\n\n // Remove the dispose listener on this evented object, which was given\n // the same guid as the event listener in on().\n this.off('dispose', listener);\n if (target.nodeName) {\n off(target, type, listener);\n off(target, 'dispose', listener);\n } else if (isEvented(target)) {\n target.off(type, listener);\n target.off('dispose', listener);\n }\n }\n },\n /**\n * Fire an event on this evented object, causing its listeners to be called.\n *\n * @param {string|Object} event\n * An event type or an object with a type property.\n *\n * @param {Object} [hash]\n * An additional object to pass along to listeners.\n *\n * @return {boolean}\n * Whether or not the default behavior was prevented.\n */\n trigger(event, hash) {\n validateTarget(this.eventBusEl_, this, 'trigger');\n const type = event && typeof event !== 'string' ? event.type : event;\n if (!isValidEventType(type)) {\n throw new Error(`Invalid event type for ${objName(this)}#trigger; ` + 'must be a non-empty string or object with a type key that has a non-empty value.');\n }\n return trigger(this.eventBusEl_, event, hash);\n }\n };\n\n /**\n * Applies {@link module:evented~EventedMixin|EventedMixin} to a target object.\n *\n * @param {Object} target\n * The object to which to add event methods.\n *\n * @param {Object} [options={}]\n * Options for customizing the mixin behavior.\n *\n * @param {string} [options.eventBusKey]\n * By default, adds a `eventBusEl_` DOM element to the target object,\n * which is used as an event bus. If the target object already has a\n * DOM element that should be used, pass its key here.\n *\n * @return {Object}\n * The target object.\n */\n function evented(target, options = {}) {\n const {\n eventBusKey\n } = options;\n\n // Set or create the eventBusEl_.\n if (eventBusKey) {\n if (!target[eventBusKey].nodeName) {\n throw new Error(`The eventBusKey \"${eventBusKey}\" does not refer to an element.`);\n }\n target.eventBusEl_ = target[eventBusKey];\n } else {\n target.eventBusEl_ = createEl('span', {\n className: 'vjs-event-bus'\n });\n }\n Object.assign(target, EventedMixin);\n if (target.eventedCallbacks) {\n target.eventedCallbacks.forEach(callback => {\n callback();\n });\n }\n\n // When any evented object is disposed, it removes all its listeners.\n target.on('dispose', () => {\n target.off();\n [target, target.el_, target.eventBusEl_].forEach(function (val) {\n if (val && DomData.has(val)) {\n DomData.delete(val);\n }\n });\n window.setTimeout(() => {\n target.eventBusEl_ = null;\n }, 0);\n });\n return target;\n }\n\n /**\n * @file mixins/stateful.js\n * @module stateful\n */\n\n /**\n * Contains methods that provide statefulness to an object which is passed\n * to {@link module:stateful}.\n *\n * @mixin StatefulMixin\n */\n const StatefulMixin = {\n /**\n * A hash containing arbitrary keys and values representing the state of\n * the object.\n *\n * @type {Object}\n */\n state: {},\n /**\n * Set the state of an object by mutating its\n * {@link module:stateful~StatefulMixin.state|state} object in place.\n *\n * @fires module:stateful~StatefulMixin#statechanged\n * @param {Object|Function} stateUpdates\n * A new set of properties to shallow-merge into the plugin state.\n * Can be a plain object or a function returning a plain object.\n *\n * @return {Object|undefined}\n * An object containing changes that occurred. If no changes\n * occurred, returns `undefined`.\n */\n setState(stateUpdates) {\n // Support providing the `stateUpdates` state as a function.\n if (typeof stateUpdates === 'function') {\n stateUpdates = stateUpdates();\n }\n let changes;\n each(stateUpdates, (value, key) => {\n // Record the change if the value is different from what's in the\n // current state.\n if (this.state[key] !== value) {\n changes = changes || {};\n changes[key] = {\n from: this.state[key],\n to: value\n };\n }\n this.state[key] = value;\n });\n\n // Only trigger \"statechange\" if there were changes AND we have a trigger\n // function. This allows us to not require that the target object be an\n // evented object.\n if (changes && isEvented(this)) {\n /**\n * An event triggered on an object that is both\n * {@link module:stateful|stateful} and {@link module:evented|evented}\n * indicating that its state has changed.\n *\n * @event module:stateful~StatefulMixin#statechanged\n * @type {Object}\n * @property {Object} changes\n * A hash containing the properties that were changed and\n * the values they were changed `from` and `to`.\n */\n this.trigger({\n changes,\n type: 'statechanged'\n });\n }\n return changes;\n }\n };\n\n /**\n * Applies {@link module:stateful~StatefulMixin|StatefulMixin} to a target\n * object.\n *\n * If the target object is {@link module:evented|evented} and has a\n * `handleStateChanged` method, that method will be automatically bound to the\n * `statechanged` event on itself.\n *\n * @param {Object} target\n * The object to be made stateful.\n *\n * @param {Object} [defaultState]\n * A default set of properties to populate the newly-stateful object's\n * `state` property.\n *\n * @return {Object}\n * Returns the `target`.\n */\n function stateful(target, defaultState) {\n Object.assign(target, StatefulMixin);\n\n // This happens after the mixing-in because we need to replace the `state`\n // added in that step.\n target.state = Object.assign({}, target.state, defaultState);\n\n // Auto-bind the `handleStateChanged` method of the target object if it exists.\n if (typeof target.handleStateChanged === 'function' && isEvented(target)) {\n target.on('statechanged', target.handleStateChanged);\n }\n return target;\n }\n\n /**\n * @file str.js\n * @module to-lower-case\n */\n\n /**\n * Lowercase the first letter of a string.\n *\n * @param {string} string\n * String to be lowercased\n *\n * @return {string}\n * The string with a lowercased first letter\n */\n const toLowerCase = function (string) {\n if (typeof string !== 'string') {\n return string;\n }\n return string.replace(/./, w => w.toLowerCase());\n };\n\n /**\n * Uppercase the first letter of a string.\n *\n * @param {string} string\n * String to be uppercased\n *\n * @return {string}\n * The string with an uppercased first letter\n */\n const toTitleCase = function (string) {\n if (typeof string !== 'string') {\n return string;\n }\n return string.replace(/./, w => w.toUpperCase());\n };\n\n /**\n * Compares the TitleCase versions of the two strings for equality.\n *\n * @param {string} str1\n * The first string to compare\n *\n * @param {string} str2\n * The second string to compare\n *\n * @return {boolean}\n * Whether the TitleCase versions of the strings are equal\n */\n const titleCaseEquals = function (str1, str2) {\n return toTitleCase(str1) === toTitleCase(str2);\n };\n\n var Str = /*#__PURE__*/Object.freeze({\n __proto__: null,\n toLowerCase: toLowerCase,\n toTitleCase: toTitleCase,\n titleCaseEquals: titleCaseEquals\n });\n\n /**\n * Player Component - Base class for all UI objects\n *\n * @file component.js\n */\n\n /** @import Player from './player' */\n\n /**\n * A callback to be called if and when the component is ready.\n * `this` will be the Component instance.\n *\n * @callback ReadyCallback\n * @returns {void}\n */\n\n /**\n * Base class for all UI Components.\n * Components are UI objects which represent both a javascript object and an element\n * in the DOM. They can be children of other components, and can have\n * children themselves.\n *\n * Components can also use methods from {@link EventTarget}\n */\n class Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of component options.\n *\n * @param {Object[]} [options.children]\n * An array of children objects to initialize this component with. Children objects have\n * a name property that will be used if more than one component of the same type needs to be\n * added.\n *\n * @param {string} [options.className]\n * A class or space separated list of classes to add the component\n *\n * @param {ReadyCallback} [ready]\n * Function that gets called when the `Component` is ready.\n */\n constructor(player, options, ready) {\n // The component might be the player itself and we can't pass `this` to super\n if (!player && this.play) {\n this.player_ = player = this; // eslint-disable-line\n } else {\n this.player_ = player;\n }\n this.isDisposed_ = false;\n\n // Hold the reference to the parent component via `addChild` method\n this.parentComponent_ = null;\n\n // Make a copy of prototype.options_ to protect against overriding defaults\n this.options_ = merge({}, this.options_);\n\n // Updated options with supplied options\n options = this.options_ = merge(this.options_, options);\n\n // Get ID from options or options element if one is supplied\n this.id_ = options.id || options.el && options.el.id;\n\n // If there was no ID from the options, generate one\n if (!this.id_) {\n // Don't require the player ID function in the case of mock players\n const id = player && player.id && player.id() || 'no_player';\n this.id_ = `${id}_component_${newGUID()}`;\n }\n this.name_ = options.name || null;\n\n // Create element if one wasn't provided in options\n if (options.el) {\n this.el_ = options.el;\n } else if (options.createEl !== false) {\n this.el_ = this.createEl();\n }\n if (options.className && this.el_) {\n options.className.split(' ').forEach(c => this.addClass(c));\n }\n\n // Remove the placeholder event methods. If the component is evented, the\n // real methods are added next\n ['on', 'off', 'one', 'any', 'trigger'].forEach(fn => {\n this[fn] = undefined;\n });\n\n // if evented is anything except false, we want to mixin in evented\n if (options.evented !== false) {\n // Make this an evented object and use `el_`, if available, as its event bus\n evented(this, {\n eventBusKey: this.el_ ? 'el_' : null\n });\n this.handleLanguagechange = this.handleLanguagechange.bind(this);\n this.on(this.player_, 'languagechange', this.handleLanguagechange);\n }\n stateful(this, this.constructor.defaultState);\n this.children_ = [];\n this.childIndex_ = {};\n this.childNameIndex_ = {};\n this.setTimeoutIds_ = new Set();\n this.setIntervalIds_ = new Set();\n this.rafIds_ = new Set();\n this.namedRafs_ = new Map();\n this.clearingTimersOnDispose_ = false;\n\n // Add any child components in options\n if (options.initChildren !== false) {\n this.initChildren();\n }\n\n // Don't want to trigger ready here or it will go before init is actually\n // finished for all children that run this constructor\n this.ready(ready);\n if (options.reportTouchActivity !== false) {\n this.enableTouchActivity();\n }\n }\n\n // `on`, `off`, `one`, `any` and `trigger` are here so tsc includes them in definitions.\n // They are replaced or removed in the constructor\n\n /**\n * Adds an `event listener` to an instance of an `EventTarget`. An `event listener` is a\n * function that will get called when an event with a certain name gets triggered.\n *\n * @param {string|string[]} type\n * An event name or an array of event names.\n *\n * @param {Function} fn\n * The function to call with `EventTarget`s\n */\n\n /**\n * Removes an `event listener` for a specific event from an instance of `EventTarget`.\n * This makes it so that the `event listener` will no longer get called when the\n * named event happens.\n *\n * @param {string|string[]} type\n * An event name or an array of event names.\n *\n * @param {Function} [fn]\n * The function to remove. If not specified, all listeners managed by Video.js will be removed.\n */\n\n /**\n * This function will add an `event listener` that gets triggered only once. After the\n * first trigger it will get removed. This is like adding an `event listener`\n * with {@link EventTarget#on} that calls {@link EventTarget#off} on itself.\n *\n * @param {string|string[]} type\n * An event name or an array of event names.\n *\n * @param {Function} fn\n * The function to be called once for each event name.\n */\n\n /**\n * This function will add an `event listener` that gets triggered only once and is\n * removed from all events. This is like adding an array of `event listener`s\n * with {@link EventTarget#on} that calls {@link EventTarget#off} on all events the\n * first time it is triggered.\n *\n * @param {string|string[]} type\n * An event name or an array of event names.\n *\n * @param {Function} fn\n * The function to be called once for each event name.\n */\n\n /**\n * This function causes an event to happen. This will then cause any `event listeners`\n * that are waiting for that event, to get called. If there are no `event listeners`\n * for an event then nothing will happen.\n *\n * If the name of the `Event` that is being triggered is in `EventTarget.allowedEvents_`.\n * Trigger will also call the `on` + `uppercaseEventName` function.\n *\n * Example:\n * 'click' is in `EventTarget.allowedEvents_`, so, trigger will attempt to call\n * `onClick` if it exists.\n *\n * @param {string|Event|Object} event\n * The name of the event, an `Event`, or an object with a key of type set to\n * an event name.\n *\n * @param {Object} [hash]\n * Optionally extra argument to pass through to an event listener\n */\n\n /**\n * Dispose of the `Component` and all child components.\n *\n * @fires Component#dispose\n *\n * @param {Object} options\n * @param {Element} options.originalEl element with which to replace player element\n */\n dispose(options = {}) {\n // Bail out if the component has already been disposed.\n if (this.isDisposed_) {\n return;\n }\n if (this.readyQueue_) {\n this.readyQueue_.length = 0;\n }\n\n /**\n * Triggered when a `Component` is disposed.\n *\n * @event Component#dispose\n * @type {Event}\n *\n * @property {boolean} [bubbles=false]\n * set to false so that the dispose event does not\n * bubble up\n */\n this.trigger({\n type: 'dispose',\n bubbles: false\n });\n this.isDisposed_ = true;\n\n // Dispose all children.\n if (this.children_) {\n for (let i = this.children_.length - 1; i >= 0; i--) {\n if (this.children_[i].dispose) {\n this.children_[i].dispose();\n }\n }\n }\n\n // Delete child references\n this.children_ = null;\n this.childIndex_ = null;\n this.childNameIndex_ = null;\n this.parentComponent_ = null;\n if (this.el_) {\n // Remove element from DOM\n if (this.el_.parentNode) {\n if (options.restoreEl) {\n this.el_.parentNode.replaceChild(options.restoreEl, this.el_);\n } else {\n this.el_.parentNode.removeChild(this.el_);\n }\n }\n this.el_ = null;\n }\n\n // remove reference to the player after disposing of the element\n this.player_ = null;\n }\n\n /**\n * Determine whether or not this component has been disposed.\n *\n * @return {boolean}\n * If the component has been disposed, will be `true`. Otherwise, `false`.\n */\n isDisposed() {\n return Boolean(this.isDisposed_);\n }\n\n /**\n * Return the {@link Player} that the `Component` has attached to.\n *\n * @return {Player}\n * The player that this `Component` has attached to.\n */\n player() {\n return this.player_;\n }\n\n /**\n * Deep merge of options objects with new options.\n * > Note: When both `obj` and `options` contain properties whose values are objects.\n * The two properties get merged using {@link module:obj.merge}\n *\n * @param {Object} obj\n * The object that contains new options.\n *\n * @return {Object}\n * A new object of `this.options_` and `obj` merged together.\n */\n options(obj) {\n if (!obj) {\n return this.options_;\n }\n this.options_ = merge(this.options_, obj);\n return this.options_;\n }\n\n /**\n * Get the `Component`s DOM element\n *\n * @return {Element}\n * The DOM element for this `Component`.\n */\n el() {\n return this.el_;\n }\n\n /**\n * Create the `Component`s DOM element.\n *\n * @param {string} [tagName]\n * Element's DOM node type. e.g. 'div'\n *\n * @param {Object} [properties]\n * An object of properties that should be set.\n *\n * @param {Object} [attributes]\n * An object of attributes that should be set.\n *\n * @return {Element}\n * The element that gets created.\n */\n createEl(tagName, properties, attributes) {\n return createEl(tagName, properties, attributes);\n }\n\n /**\n * Localize a string given the string in english.\n *\n * If tokens are provided, it'll try and run a simple token replacement on the provided string.\n * The tokens it looks for look like `{1}` with the index being 1-indexed into the tokens array.\n *\n * If a `defaultValue` is provided, it'll use that over `string`,\n * if a value isn't found in provided language files.\n * This is useful if you want to have a descriptive key for token replacement\n * but have a succinct localized string and not require `en.json` to be included.\n *\n * Currently, it is used for the progress bar timing.\n * ```js\n * {\n * \"progress bar timing: currentTime={1} duration={2}\": \"{1} of {2}\"\n * }\n * ```\n * It is then used like so:\n * ```js\n * this.localize('progress bar timing: currentTime={1} duration{2}',\n * [this.player_.currentTime(), this.player_.duration()],\n * '{1} of {2}');\n * ```\n *\n * Which outputs something like: `01:23 of 24:56`.\n *\n *\n * @param {string} string\n * The string to localize and the key to lookup in the language files.\n * @param {string[]} [tokens]\n * If the current item has token replacements, provide the tokens here.\n * @param {string} [defaultValue]\n * Defaults to `string`. Can be a default value to use for token replacement\n * if the lookup key is needed to be separate.\n *\n * @return {string}\n * The localized string or if no localization exists the english string.\n */\n localize(string, tokens, defaultValue = string) {\n const code = this.player_.language && this.player_.language();\n const languages = this.player_.languages && this.player_.languages();\n const language = languages && languages[code];\n const primaryCode = code && code.split('-')[0];\n const primaryLang = languages && languages[primaryCode];\n let localizedString = defaultValue;\n if (language && language[string]) {\n localizedString = language[string];\n } else if (primaryLang && primaryLang[string]) {\n localizedString = primaryLang[string];\n }\n if (tokens) {\n localizedString = localizedString.replace(/\\{(\\d+)\\}/g, function (match, index) {\n const value = tokens[index - 1];\n let ret = value;\n if (typeof value === 'undefined') {\n ret = match;\n }\n return ret;\n });\n }\n return localizedString;\n }\n\n /**\n * Handles language change for the player in components. Should be overridden by sub-components.\n *\n * @abstract\n */\n handleLanguagechange() {}\n\n /**\n * Return the `Component`s DOM element. This is where children get inserted.\n * This will usually be the the same as the element returned in {@link Component#el}.\n *\n * @return {Element}\n * The content element for this `Component`.\n */\n contentEl() {\n return this.contentEl_ || this.el_;\n }\n\n /**\n * Get this `Component`s ID\n *\n * @return {string}\n * The id of this `Component`\n */\n id() {\n return this.id_;\n }\n\n /**\n * Get the `Component`s name. The name gets used to reference the `Component`\n * and is set during registration.\n *\n * @return {string}\n * The name of this `Component`.\n */\n name() {\n return this.name_;\n }\n\n /**\n * Get an array of all child components\n *\n * @return {Array}\n * The children\n */\n children() {\n return this.children_;\n }\n\n /**\n * Returns the child `Component` with the given `id`.\n *\n * @param {string} id\n * The id of the child `Component` to get.\n *\n * @return {Component|undefined}\n * The child `Component` with the given `id` or undefined.\n */\n getChildById(id) {\n return this.childIndex_[id];\n }\n\n /**\n * Returns the child `Component` with the given `name`.\n *\n * @param {string} name\n * The name of the child `Component` to get.\n *\n * @return {Component|undefined}\n * The child `Component` with the given `name` or undefined.\n */\n getChild(name) {\n if (!name) {\n return;\n }\n return this.childNameIndex_[name];\n }\n\n /**\n * Returns the descendant `Component` following the givent\n * descendant `names`. For instance ['foo', 'bar', 'baz'] would\n * try to get 'foo' on the current component, 'bar' on the 'foo'\n * component and 'baz' on the 'bar' component and return undefined\n * if any of those don't exist.\n *\n * @param {...string[]|...string} names\n * The name of the child `Component` to get.\n *\n * @return {Component|undefined}\n * The descendant `Component` following the given descendant\n * `names` or undefined.\n */\n getDescendant(...names) {\n // flatten array argument into the main array\n names = names.reduce((acc, n) => acc.concat(n), []);\n let currentChild = this;\n for (let i = 0; i < names.length; i++) {\n currentChild = currentChild.getChild(names[i]);\n if (!currentChild || !currentChild.getChild) {\n return;\n }\n }\n return currentChild;\n }\n\n /**\n * Adds an SVG icon element to another element or component.\n *\n * @param {string} iconName\n * The name of icon. A list of all the icon names can be found at 'sandbox/svg-icons.html'\n *\n * @param {Element} [el=this.el()]\n * Element to set the title on. Defaults to the current Component's element.\n *\n * @return {Element}\n * The newly created icon element.\n */\n setIcon(iconName, el = this.el()) {\n // TODO: In v9 of video.js, we will want to remove font icons entirely.\n // This means this check, as well as the others throughout the code, and\n // the unecessary CSS for font icons, will need to be removed.\n // See https://github.com/videojs/video.js/pull/8260 as to which components\n // need updating.\n if (!this.player_.options_.experimentalSvgIcons) {\n return;\n }\n const xmlnsURL = 'http://www.w3.org/2000/svg';\n\n // The below creates an element in the format of:\n // <span><svg><use>....</use></svg></span>\n const iconContainer = createEl('span', {\n className: 'vjs-icon-placeholder vjs-svg-icon'\n }, {\n 'aria-hidden': 'true'\n });\n const svgEl = document.createElementNS(xmlnsURL, 'svg');\n svgEl.setAttributeNS(null, 'viewBox', '0 0 512 512');\n const useEl = document.createElementNS(xmlnsURL, 'use');\n svgEl.appendChild(useEl);\n useEl.setAttributeNS(null, 'href', `#vjs-icon-${iconName}`);\n iconContainer.appendChild(svgEl);\n\n // Replace a pre-existing icon if one exists.\n if (this.iconIsSet_) {\n el.replaceChild(iconContainer, el.querySelector('.vjs-icon-placeholder'));\n } else {\n el.appendChild(iconContainer);\n }\n this.iconIsSet_ = true;\n return iconContainer;\n }\n\n /**\n * Add a child `Component` inside the current `Component`.\n *\n * @param {string|Component} child\n * The name or instance of a child to add.\n *\n * @param {Object} [options={}]\n * The key/value store of options that will get passed to children of\n * the child.\n *\n * @param {number} [index=this.children_.length]\n * The index to attempt to add a child into.\n *\n *\n * @return {Component}\n * The `Component` that gets added as a child. When using a string the\n * `Component` will get created by this process.\n */\n addChild(child, options = {}, index = this.children_.length) {\n let component;\n let componentName;\n\n // If child is a string, create component with options\n if (typeof child === 'string') {\n componentName = toTitleCase(child);\n const componentClassName = options.componentClass || componentName;\n\n // Set name through options\n options.name = componentName;\n\n // Create a new object & element for this controls set\n // If there's no .player_, this is a player\n const ComponentClass = Component.getComponent(componentClassName);\n if (!ComponentClass) {\n throw new Error(`Component ${componentClassName} does not exist`);\n }\n\n // data stored directly on the videojs object may be\n // misidentified as a component to retain\n // backwards-compatibility with 4.x. check to make sure the\n // component class can be instantiated.\n if (typeof ComponentClass !== 'function') {\n return null;\n }\n component = new ComponentClass(this.player_ || this, options);\n\n // child is a component instance\n } else {\n component = child;\n }\n if (component.parentComponent_) {\n component.parentComponent_.removeChild(component);\n }\n this.children_.splice(index, 0, component);\n component.parentComponent_ = this;\n if (typeof component.id === 'function') {\n this.childIndex_[component.id()] = component;\n }\n\n // If a name wasn't used to create the component, check if we can use the\n // name function of the component\n componentName = componentName || component.name && toTitleCase(component.name());\n if (componentName) {\n this.childNameIndex_[componentName] = component;\n this.childNameIndex_[toLowerCase(componentName)] = component;\n }\n\n // Add the UI object's element to the container div (box)\n // Having an element is not required\n if (typeof component.el === 'function' && component.el()) {\n // If inserting before a component, insert before that component's element\n let refNode = null;\n if (this.children_[index + 1]) {\n // Most children are components, but the video tech is an HTML element\n if (this.children_[index + 1].el_) {\n refNode = this.children_[index + 1].el_;\n } else if (isEl(this.children_[index + 1])) {\n refNode = this.children_[index + 1];\n }\n }\n this.contentEl().insertBefore(component.el(), refNode);\n }\n\n // Return so it can stored on parent object if desired.\n return component;\n }\n\n /**\n * Remove a child `Component` from this `Component`s list of children. Also removes\n * the child `Component`s element from this `Component`s element.\n *\n * @param {Component} component\n * The child `Component` to remove.\n */\n removeChild(component) {\n if (typeof component === 'string') {\n component = this.getChild(component);\n }\n if (!component || !this.children_) {\n return;\n }\n let childFound = false;\n for (let i = this.children_.length - 1; i >= 0; i--) {\n if (this.children_[i] === component) {\n childFound = true;\n this.children_.splice(i, 1);\n break;\n }\n }\n if (!childFound) {\n return;\n }\n component.parentComponent_ = null;\n this.childIndex_[component.id()] = null;\n this.childNameIndex_[toTitleCase(component.name())] = null;\n this.childNameIndex_[toLowerCase(component.name())] = null;\n const compEl = component.el();\n if (compEl && compEl.parentNode === this.contentEl()) {\n this.contentEl().removeChild(component.el());\n }\n }\n\n /**\n * Add and initialize default child `Component`s based upon options.\n */\n initChildren() {\n const children = this.options_.children;\n if (children) {\n // `this` is `parent`\n const parentOptions = this.options_;\n const handleAdd = child => {\n const name = child.name;\n let opts = child.opts;\n\n // Allow options for children to be set at the parent options\n // e.g. videojs(id, { controlBar: false });\n // instead of videojs(id, { children: { controlBar: false });\n if (parentOptions[name] !== undefined) {\n opts = parentOptions[name];\n }\n\n // Allow for disabling default components\n // e.g. options['children']['posterImage'] = false\n if (opts === false) {\n return;\n }\n\n // Allow options to be passed as a simple boolean if no configuration\n // is necessary.\n if (opts === true) {\n opts = {};\n }\n\n // We also want to pass the original player options\n // to each component as well so they don't need to\n // reach back into the player for options later.\n opts.playerOptions = this.options_.playerOptions;\n\n // Create and add the child component.\n // Add a direct reference to the child by name on the parent instance.\n // If two of the same component are used, different names should be supplied\n // for each\n const newChild = this.addChild(name, opts);\n if (newChild) {\n this[name] = newChild;\n }\n };\n\n // Allow for an array of children details to passed in the options\n let workingChildren;\n const Tech = Component.getComponent('Tech');\n if (Array.isArray(children)) {\n workingChildren = children;\n } else {\n workingChildren = Object.keys(children);\n }\n workingChildren\n // children that are in this.options_ but also in workingChildren would\n // give us extra children we do not want. So, we want to filter them out.\n .concat(Object.keys(this.options_).filter(function (child) {\n return !workingChildren.some(function (wchild) {\n if (typeof wchild === 'string') {\n return child === wchild;\n }\n return child === wchild.name;\n });\n })).map(child => {\n let name;\n let opts;\n if (typeof child === 'string') {\n name = child;\n opts = children[name] || this.options_[name] || {};\n } else {\n name = child.name;\n opts = child;\n }\n return {\n name,\n opts\n };\n }).filter(child => {\n // we have to make sure that child.name isn't in the techOrder since\n // techs are registered as Components but can't aren't compatible\n // See https://github.com/videojs/video.js/issues/2772\n const c = Component.getComponent(child.opts.componentClass || toTitleCase(child.name));\n return c && !Tech.isTech(c);\n }).forEach(handleAdd);\n }\n }\n\n /**\n * Builds the default DOM class name. Should be overridden by sub-components.\n *\n * @return {string}\n * The DOM class name for this object.\n *\n * @abstract\n */\n buildCSSClass() {\n // Child classes can include a function that does:\n // return 'CLASS NAME' + this._super();\n return '';\n }\n\n /**\n * Bind a listener to the component's ready state.\n * Different from event listeners in that if the ready event has already happened\n * it will trigger the function immediately.\n *\n * @param {ReadyCallback} fn\n * Function that gets called when the `Component` is ready.\n */\n ready(fn, sync = false) {\n if (!fn) {\n return;\n }\n if (!this.isReady_) {\n this.readyQueue_ = this.readyQueue_ || [];\n this.readyQueue_.push(fn);\n return;\n }\n if (sync) {\n fn.call(this);\n } else {\n // Call the function asynchronously by default for consistency\n this.setTimeout(fn, 1);\n }\n }\n\n /**\n * Trigger all the ready listeners for this `Component`.\n *\n * @fires Component#ready\n */\n triggerReady() {\n this.isReady_ = true;\n\n // Ensure ready is triggered asynchronously\n this.setTimeout(function () {\n const readyQueue = this.readyQueue_;\n\n // Reset Ready Queue\n this.readyQueue_ = [];\n if (readyQueue && readyQueue.length > 0) {\n readyQueue.forEach(function (fn) {\n fn.call(this);\n }, this);\n }\n\n // Allow for using event listeners also\n /**\n * Triggered when a `Component` is ready.\n *\n * @event Component#ready\n * @type {Event}\n */\n this.trigger('ready');\n }, 1);\n }\n\n /**\n * Find a single DOM element matching a `selector`. This can be within the `Component`s\n * `contentEl()` or another custom context.\n *\n * @param {string} selector\n * A valid CSS selector, which will be passed to `querySelector`.\n *\n * @param {Element|string} [context=this.contentEl()]\n * A DOM element within which to query. Can also be a selector string in\n * which case the first matching element will get used as context. If\n * missing `this.contentEl()` gets used. If `this.contentEl()` returns\n * nothing it falls back to `document`.\n *\n * @return {Element|null}\n * the dom element that was found, or null\n *\n * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)\n */\n $(selector, context) {\n return $(selector, context || this.contentEl());\n }\n\n /**\n * Finds all DOM element matching a `selector`. This can be within the `Component`s\n * `contentEl()` or another custom context.\n *\n * @param {string} selector\n * A valid CSS selector, which will be passed to `querySelectorAll`.\n *\n * @param {Element|string} [context=this.contentEl()]\n * A DOM element within which to query. Can also be a selector string in\n * which case the first matching element will get used as context. If\n * missing `this.contentEl()` gets used. If `this.contentEl()` returns\n * nothing it falls back to `document`.\n *\n * @return {NodeList}\n * a list of dom elements that were found\n *\n * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)\n */\n $$(selector, context) {\n return $$(selector, context || this.contentEl());\n }\n\n /**\n * Check if a component's element has a CSS class name.\n *\n * @param {string} classToCheck\n * CSS class name to check.\n *\n * @return {boolean}\n * - True if the `Component` has the class.\n * - False if the `Component` does not have the class`\n */\n hasClass(classToCheck) {\n return hasClass(this.el_, classToCheck);\n }\n\n /**\n * Add a CSS class name to the `Component`s element.\n *\n * @param {...string} classesToAdd\n * One or more CSS class name to add.\n */\n addClass(...classesToAdd) {\n addClass(this.el_, ...classesToAdd);\n }\n\n /**\n * Remove a CSS class name from the `Component`s element.\n *\n * @param {...string} classesToRemove\n * One or more CSS class name to remove.\n */\n removeClass(...classesToRemove) {\n removeClass(this.el_, ...classesToRemove);\n }\n\n /**\n * Add or remove a CSS class name from the component's element.\n * - `classToToggle` gets added when {@link Component#hasClass} would return false.\n * - `classToToggle` gets removed when {@link Component#hasClass} would return true.\n *\n * @param {string} classToToggle\n * The class to add or remove. Passed to DOMTokenList's toggle()\n *\n * @param {boolean|Dom.PredicateCallback} [predicate]\n * A boolean or function that returns a boolean. Passed to DOMTokenList's toggle().\n */\n toggleClass(classToToggle, predicate) {\n toggleClass(this.el_, classToToggle, predicate);\n }\n\n /**\n * Show the `Component`s element if it is hidden by removing the\n * 'vjs-hidden' class name from it.\n */\n show() {\n this.removeClass('vjs-hidden');\n }\n\n /**\n * Hide the `Component`s element if it is currently showing by adding the\n * 'vjs-hidden` class name to it.\n */\n hide() {\n this.addClass('vjs-hidden');\n }\n\n /**\n * Lock a `Component`s element in its visible state by adding the 'vjs-lock-showing'\n * class name to it. Used during fadeIn/fadeOut.\n *\n * @private\n */\n lockShowing() {\n this.addClass('vjs-lock-showing');\n }\n\n /**\n * Unlock a `Component`s element from its visible state by removing the 'vjs-lock-showing'\n * class name from it. Used during fadeIn/fadeOut.\n *\n * @private\n */\n unlockShowing() {\n this.removeClass('vjs-lock-showing');\n }\n\n /**\n * Get the value of an attribute on the `Component`s element.\n *\n * @param {string} attribute\n * Name of the attribute to get the value from.\n *\n * @return {string|null}\n * - The value of the attribute that was asked for.\n * - Can be an empty string on some browsers if the attribute does not exist\n * or has no value\n * - Most browsers will return null if the attribute does not exist or has\n * no value.\n *\n * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute}\n */\n getAttribute(attribute) {\n return getAttribute(this.el_, attribute);\n }\n\n /**\n * Set the value of an attribute on the `Component`'s element\n *\n * @param {string} attribute\n * Name of the attribute to set.\n *\n * @param {string} value\n * Value to set the attribute to.\n *\n * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute}\n */\n setAttribute(attribute, value) {\n setAttribute(this.el_, attribute, value);\n }\n\n /**\n * Remove an attribute from the `Component`s element.\n *\n * @param {string} attribute\n * Name of the attribute to remove.\n *\n * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute}\n */\n removeAttribute(attribute) {\n removeAttribute(this.el_, attribute);\n }\n\n /**\n * Get or set the width of the component based upon the CSS styles.\n * See {@link Component#dimension} for more detailed information.\n *\n * @param {number|string} [num]\n * The width that you want to set postfixed with '%', 'px' or nothing.\n *\n * @param {boolean} [skipListeners]\n * Skip the componentresize event trigger\n *\n * @return {number|undefined}\n * The width when getting, zero if there is no width\n */\n width(num, skipListeners) {\n return this.dimension('width', num, skipListeners);\n }\n\n /**\n * Get or set the height of the component based upon the CSS styles.\n * See {@link Component#dimension} for more detailed information.\n *\n * @param {number|string} [num]\n * The height that you want to set postfixed with '%', 'px' or nothing.\n *\n * @param {boolean} [skipListeners]\n * Skip the componentresize event trigger\n *\n * @return {number|undefined}\n * The height when getting, zero if there is no height\n */\n height(num, skipListeners) {\n return this.dimension('height', num, skipListeners);\n }\n\n /**\n * Set both the width and height of the `Component` element at the same time.\n *\n * @param {number|string} width\n * Width to set the `Component`s element to.\n *\n * @param {number|string} height\n * Height to set the `Component`s element to.\n */\n dimensions(width, height) {\n // Skip componentresize listeners on width for optimization\n this.width(width, true);\n this.height(height);\n }\n\n /**\n * Get or set width or height of the `Component` element. This is the shared code\n * for the {@link Component#width} and {@link Component#height}.\n *\n * Things to know:\n * - If the width or height in an number this will return the number postfixed with 'px'.\n * - If the width/height is a percent this will return the percent postfixed with '%'\n * - Hidden elements have a width of 0 with `window.getComputedStyle`. This function\n * defaults to the `Component`s `style.width` and falls back to `window.getComputedStyle`.\n * See [this]{@link http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/}\n * for more information\n * - If you want the computed style of the component, use {@link Component#currentWidth}\n * and {@link {Component#currentHeight}\n *\n * @fires Component#componentresize\n *\n * @param {string} widthOrHeight\n 8 'width' or 'height'\n *\n * @param {number|string} [num]\n 8 New dimension\n *\n * @param {boolean} [skipListeners]\n * Skip componentresize event trigger\n *\n * @return {number|undefined}\n * The dimension when getting or 0 if unset\n */\n dimension(widthOrHeight, num, skipListeners) {\n if (num !== undefined) {\n // Set to zero if null or literally NaN (NaN !== NaN)\n if (num === null || num !== num) {\n num = 0;\n }\n\n // Check if using css width/height (% or px) and adjust\n if (('' + num).indexOf('%') !== -1 || ('' + num).indexOf('px') !== -1) {\n this.el_.style[widthOrHeight] = num;\n } else if (num === 'auto') {\n this.el_.style[widthOrHeight] = '';\n } else {\n this.el_.style[widthOrHeight] = num + 'px';\n }\n\n // skipListeners allows us to avoid triggering the resize event when setting both width and height\n if (!skipListeners) {\n /**\n * Triggered when a component is resized.\n *\n * @event Component#componentresize\n * @type {Event}\n */\n this.trigger('componentresize');\n }\n return;\n }\n\n // Not setting a value, so getting it\n // Make sure element exists\n if (!this.el_) {\n return 0;\n }\n\n // Get dimension value from style\n const val = this.el_.style[widthOrHeight];\n const pxIndex = val.indexOf('px');\n if (pxIndex !== -1) {\n // Return the pixel value with no 'px'\n return parseInt(val.slice(0, pxIndex), 10);\n }\n\n // No px so using % or no style was set, so falling back to offsetWidth/height\n // If component has display:none, offset will return 0\n // TODO: handle display:none and no dimension style using px\n return parseInt(this.el_['offset' + toTitleCase(widthOrHeight)], 10);\n }\n\n /**\n * Get the computed width or the height of the component's element.\n *\n * Uses `window.getComputedStyle`.\n *\n * @param {string} widthOrHeight\n * A string containing 'width' or 'height'. Whichever one you want to get.\n *\n * @return {number}\n * The dimension that gets asked for or 0 if nothing was set\n * for that dimension.\n */\n currentDimension(widthOrHeight) {\n let computedWidthOrHeight = 0;\n if (widthOrHeight !== 'width' && widthOrHeight !== 'height') {\n throw new Error('currentDimension only accepts width or height value');\n }\n computedWidthOrHeight = computedStyle(this.el_, widthOrHeight);\n\n // remove 'px' from variable and parse as integer\n computedWidthOrHeight = parseFloat(computedWidthOrHeight);\n\n // if the computed value is still 0, it's possible that the browser is lying\n // and we want to check the offset values.\n // This code also runs wherever getComputedStyle doesn't exist.\n if (computedWidthOrHeight === 0 || isNaN(computedWidthOrHeight)) {\n const rule = `offset${toTitleCase(widthOrHeight)}`;\n computedWidthOrHeight = this.el_[rule];\n }\n return computedWidthOrHeight;\n }\n\n /**\n * An object that contains width and height values of the `Component`s\n * computed style. Uses `window.getComputedStyle`.\n *\n * @typedef {Object} Component~DimensionObject\n *\n * @property {number} width\n * The width of the `Component`s computed style.\n *\n * @property {number} height\n * The height of the `Component`s computed style.\n */\n\n /**\n * Get an object that contains computed width and height values of the\n * component's element.\n *\n * Uses `window.getComputedStyle`.\n *\n * @return {Component~DimensionObject}\n * The computed dimensions of the component's element.\n */\n currentDimensions() {\n return {\n width: this.currentDimension('width'),\n height: this.currentDimension('height')\n };\n }\n\n /**\n * Get the computed width of the component's element.\n *\n * Uses `window.getComputedStyle`.\n *\n * @return {number}\n * The computed width of the component's element.\n */\n currentWidth() {\n return this.currentDimension('width');\n }\n\n /**\n * Get the computed height of the component's element.\n *\n * Uses `window.getComputedStyle`.\n *\n * @return {number}\n * The computed height of the component's element.\n */\n currentHeight() {\n return this.currentDimension('height');\n }\n\n /**\n * Retrieves the position and size information of the component's element.\n *\n * @return {Object} An object with `boundingClientRect` and `center` properties.\n * - `boundingClientRect`: An object with properties `x`, `y`, `width`,\n * `height`, `top`, `right`, `bottom`, and `left`, representing\n * the bounding rectangle of the element.\n * - `center`: An object with properties `x` and `y`, representing\n * the center point of the element. `width` and `height` are set to 0.\n */\n getPositions() {\n const rect = this.el_.getBoundingClientRect();\n\n // Creating objects that mirror DOMRectReadOnly for boundingClientRect and center\n const boundingClientRect = {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n left: rect.left\n };\n\n // Calculating the center position\n const center = {\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n width: 0,\n height: 0,\n top: rect.top + rect.height / 2,\n right: rect.left + rect.width / 2,\n bottom: rect.top + rect.height / 2,\n left: rect.left + rect.width / 2\n };\n return {\n boundingClientRect,\n center\n };\n }\n\n /**\n * Set the focus to this component\n */\n focus() {\n this.el_.focus();\n }\n\n /**\n * Remove the focus from this component\n */\n blur() {\n this.el_.blur();\n }\n\n /**\n * When this Component receives a `keydown` event which it does not process,\n * it passes the event to the Player for handling.\n *\n * @param {KeyboardEvent} event\n * The `keydown` event that caused this function to be called.\n */\n handleKeyDown(event) {\n if (this.player_) {\n // We only stop propagation here because we want unhandled events to fall\n // back to the browser. Exclude Tab for focus trapping, exclude also when spatialNavigation is enabled.\n if (event.key !== 'Tab' && !(this.player_.options_.playerOptions.spatialNavigation && this.player_.options_.playerOptions.spatialNavigation.enabled)) {\n event.stopPropagation();\n }\n this.player_.handleKeyDown(event);\n }\n }\n\n /**\n * Many components used to have a `handleKeyPress` method, which was poorly\n * named because it listened to a `keydown` event. This method name now\n * delegates to `handleKeyDown`. This means anyone calling `handleKeyPress`\n * will not see their method calls stop working.\n *\n * @param {KeyboardEvent} event\n * The event that caused this function to be called.\n */\n handleKeyPress(event) {\n this.handleKeyDown(event);\n }\n\n /**\n * Emit a 'tap' events when touch event support gets detected. This gets used to\n * support toggling the controls through a tap on the video. They get enabled\n * because every sub-component would have extra overhead otherwise.\n *\n * @protected\n * @fires Component#tap\n * @listens Component#touchstart\n * @listens Component#touchmove\n * @listens Component#touchleave\n * @listens Component#touchcancel\n * @listens Component#touchend\n */\n emitTapEvents() {\n // Track the start time so we can determine how long the touch lasted\n let touchStart = 0;\n let firstTouch = null;\n\n // Maximum movement allowed during a touch event to still be considered a tap\n // Other popular libs use anywhere from 2 (hammer.js) to 15,\n // so 10 seems like a nice, round number.\n const tapMovementThreshold = 10;\n\n // The maximum length a touch can be while still being considered a tap\n const touchTimeThreshold = 200;\n let couldBeTap;\n this.on('touchstart', function (event) {\n // If more than one finger, don't consider treating this as a click\n if (event.touches.length === 1) {\n // Copy pageX/pageY from the object\n firstTouch = {\n pageX: event.touches[0].pageX,\n pageY: event.touches[0].pageY\n };\n // Record start time so we can detect a tap vs. \"touch and hold\"\n touchStart = window.performance.now();\n // Reset couldBeTap tracking\n couldBeTap = true;\n }\n });\n this.on('touchmove', function (event) {\n // If more than one finger, don't consider treating this as a click\n if (event.touches.length > 1) {\n couldBeTap = false;\n } else if (firstTouch) {\n // Some devices will throw touchmoves for all but the slightest of taps.\n // So, if we moved only a small distance, this could still be a tap\n const xdiff = event.touches[0].pageX - firstTouch.pageX;\n const ydiff = event.touches[0].pageY - firstTouch.pageY;\n const touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);\n if (touchDistance > tapMovementThreshold) {\n couldBeTap = false;\n }\n }\n });\n const noTap = function () {\n couldBeTap = false;\n };\n\n // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s\n this.on('touchleave', noTap);\n this.on('touchcancel', noTap);\n\n // When the touch ends, measure how long it took and trigger the appropriate\n // event\n this.on('touchend', function (event) {\n firstTouch = null;\n // Proceed only if the touchmove/leave/cancel event didn't happen\n if (couldBeTap === true) {\n // Measure how long the touch lasted\n const touchTime = window.performance.now() - touchStart;\n\n // Make sure the touch was less than the threshold to be considered a tap\n if (touchTime < touchTimeThreshold) {\n // Don't let browser turn this into a click\n event.preventDefault();\n /**\n * Triggered when a `Component` is tapped.\n *\n * @event Component#tap\n * @type {MouseEvent}\n */\n this.trigger('tap');\n // It may be good to copy the touchend event object and change the\n // type to tap, if the other event properties aren't exact after\n // Events.fixEvent runs (e.g. event.target)\n }\n }\n });\n }\n\n /**\n * This function reports user activity whenever touch events happen. This can get\n * turned off by any sub-components that wants touch events to act another way.\n *\n * Report user touch activity when touch events occur. User activity gets used to\n * determine when controls should show/hide. It is simple when it comes to mouse\n * events, because any mouse event should show the controls. So we capture mouse\n * events that bubble up to the player and report activity when that happens.\n * With touch events it isn't as easy as `touchstart` and `touchend` toggle player\n * controls. So touch events can't help us at the player level either.\n *\n * User activity gets checked asynchronously. So what could happen is a tap event\n * on the video turns the controls off. Then the `touchend` event bubbles up to\n * the player. Which, if it reported user activity, would turn the controls right\n * back on. We also don't want to completely block touch events from bubbling up.\n * Furthermore a `touchmove` event and anything other than a tap, should not turn\n * controls back on.\n *\n * @listens Component#touchstart\n * @listens Component#touchmove\n * @listens Component#touchend\n * @listens Component#touchcancel\n */\n enableTouchActivity() {\n // Don't continue if the root player doesn't support reporting user activity\n if (!this.player() || !this.player().reportUserActivity) {\n return;\n }\n\n // listener for reporting that the user is active\n const report = bind_(this.player(), this.player().reportUserActivity);\n let touchHolding;\n this.on('touchstart', function () {\n report();\n // For as long as the they are touching the device or have their mouse down,\n // we consider them active even if they're not moving their finger or mouse.\n // So we want to continue to update that they are active\n this.clearInterval(touchHolding);\n // report at the same interval as activityCheck\n touchHolding = this.setInterval(report, 250);\n });\n const touchEnd = function (event) {\n report();\n // stop the interval that maintains activity if the touch is holding\n this.clearInterval(touchHolding);\n };\n this.on('touchmove', report);\n this.on('touchend', touchEnd);\n this.on('touchcancel', touchEnd);\n }\n\n /**\n * A callback that has no parameters and is bound into `Component`s context.\n *\n * @callback Component~GenericCallback\n * @this Component\n */\n\n /**\n * Creates a function that runs after an `x` millisecond timeout. This function is a\n * wrapper around `window.setTimeout`. There are a few reasons to use this one\n * instead though:\n * 1. It gets cleared via {@link Component#clearTimeout} when\n * {@link Component#dispose} gets called.\n * 2. The function callback will gets turned into a {@link Component~GenericCallback}\n *\n * > Note: You can't use `window.clearTimeout` on the id returned by this function. This\n * will cause its dispose listener not to get cleaned up! Please use\n * {@link Component#clearTimeout} or {@link Component#dispose} instead.\n *\n * @param {Component~GenericCallback} fn\n * The function that will be run after `timeout`.\n *\n * @param {number} timeout\n * Timeout in milliseconds to delay before executing the specified function.\n *\n * @return {number}\n * Returns a timeout ID that gets used to identify the timeout. It can also\n * get used in {@link Component#clearTimeout} to clear the timeout that\n * was set.\n *\n * @listens Component#dispose\n * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout}\n */\n setTimeout(fn, timeout) {\n // declare as variables so they are properly available in timeout function\n // eslint-disable-next-line\n var timeoutId;\n fn = bind_(this, fn);\n this.clearTimersOnDispose_();\n timeoutId = window.setTimeout(() => {\n if (this.setTimeoutIds_.has(timeoutId)) {\n this.setTimeoutIds_.delete(timeoutId);\n }\n fn();\n }, timeout);\n this.setTimeoutIds_.add(timeoutId);\n return timeoutId;\n }\n\n /**\n * Clears a timeout that gets created via `window.setTimeout` or\n * {@link Component#setTimeout}. If you set a timeout via {@link Component#setTimeout}\n * use this function instead of `window.clearTimout`. If you don't your dispose\n * listener will not get cleaned up until {@link Component#dispose}!\n *\n * @param {number} timeoutId\n * The id of the timeout to clear. The return value of\n * {@link Component#setTimeout} or `window.setTimeout`.\n *\n * @return {number}\n * Returns the timeout id that was cleared.\n *\n * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout}\n */\n clearTimeout(timeoutId) {\n if (this.setTimeoutIds_.has(timeoutId)) {\n this.setTimeoutIds_.delete(timeoutId);\n window.clearTimeout(timeoutId);\n }\n return timeoutId;\n }\n\n /**\n * Creates a function that gets run every `x` milliseconds. This function is a wrapper\n * around `window.setInterval`. There are a few reasons to use this one instead though.\n * 1. It gets cleared via {@link Component#clearInterval} when\n * {@link Component#dispose} gets called.\n * 2. The function callback will be a {@link Component~GenericCallback}\n *\n * @param {Component~GenericCallback} fn\n * The function to run every `x` seconds.\n *\n * @param {number} interval\n * Execute the specified function every `x` milliseconds.\n *\n * @return {number}\n * Returns an id that can be used to identify the interval. It can also be be used in\n * {@link Component#clearInterval} to clear the interval.\n *\n * @listens Component#dispose\n * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval}\n */\n setInterval(fn, interval) {\n fn = bind_(this, fn);\n this.clearTimersOnDispose_();\n const intervalId = window.setInterval(fn, interval);\n this.setIntervalIds_.add(intervalId);\n return intervalId;\n }\n\n /**\n * Clears an interval that gets created via `window.setInterval` or\n * {@link Component#setInterval}. If you set an interval via {@link Component#setInterval}\n * use this function instead of `window.clearInterval`. If you don't your dispose\n * listener will not get cleaned up until {@link Component#dispose}!\n *\n * @param {number} intervalId\n * The id of the interval to clear. The return value of\n * {@link Component#setInterval} or `window.setInterval`.\n *\n * @return {number}\n * Returns the interval id that was cleared.\n *\n * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval}\n */\n clearInterval(intervalId) {\n if (this.setIntervalIds_.has(intervalId)) {\n this.setIntervalIds_.delete(intervalId);\n window.clearInterval(intervalId);\n }\n return intervalId;\n }\n\n /**\n * Queues up a callback to be passed to requestAnimationFrame (rAF), but\n * with a few extra bonuses:\n *\n * - Supports browsers that do not support rAF by falling back to\n * {@link Component#setTimeout}.\n *\n * - The callback is turned into a {@link Component~GenericCallback} (i.e.\n * bound to the component).\n *\n * - Automatic cancellation of the rAF callback is handled if the component\n * is disposed before it is called.\n *\n * @param {Component~GenericCallback} fn\n * A function that will be bound to this component and executed just\n * before the browser's next repaint.\n *\n * @return {number}\n * Returns an rAF ID that gets used to identify the timeout. It can\n * also be used in {@link Component#cancelAnimationFrame} to cancel\n * the animation frame callback.\n *\n * @listens Component#dispose\n * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame}\n */\n requestAnimationFrame(fn) {\n this.clearTimersOnDispose_();\n\n // declare as variables so they are properly available in rAF function\n // eslint-disable-next-line\n var id;\n fn = bind_(this, fn);\n id = window.requestAnimationFrame(() => {\n if (this.rafIds_.has(id)) {\n this.rafIds_.delete(id);\n }\n fn();\n });\n this.rafIds_.add(id);\n return id;\n }\n\n /**\n * Request an animation frame, but only one named animation\n * frame will be queued. Another will never be added until\n * the previous one finishes.\n *\n * @param {string} name\n * The name to give this requestAnimationFrame\n *\n * @param {Component~GenericCallback} fn\n * A function that will be bound to this component and executed just\n * before the browser's next repaint.\n */\n requestNamedAnimationFrame(name, fn) {\n if (this.namedRafs_.has(name)) {\n this.cancelNamedAnimationFrame(name);\n }\n this.clearTimersOnDispose_();\n fn = bind_(this, fn);\n const id = this.requestAnimationFrame(() => {\n fn();\n if (this.namedRafs_.has(name)) {\n this.namedRafs_.delete(name);\n }\n });\n this.namedRafs_.set(name, id);\n return name;\n }\n\n /**\n * Cancels a current named animation frame if it exists.\n *\n * @param {string} name\n * The name of the requestAnimationFrame to cancel.\n */\n cancelNamedAnimationFrame(name) {\n if (!this.namedRafs_.has(name)) {\n return;\n }\n this.cancelAnimationFrame(this.namedRafs_.get(name));\n this.namedRafs_.delete(name);\n }\n\n /**\n * Cancels a queued callback passed to {@link Component#requestAnimationFrame}\n * (rAF).\n *\n * If you queue an rAF callback via {@link Component#requestAnimationFrame},\n * use this function instead of `window.cancelAnimationFrame`. If you don't,\n * your dispose listener will not get cleaned up until {@link Component#dispose}!\n *\n * @param {number} id\n * The rAF ID to clear. The return value of {@link Component#requestAnimationFrame}.\n *\n * @return {number}\n * Returns the rAF ID that was cleared.\n *\n * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/window/cancelAnimationFrame}\n */\n cancelAnimationFrame(id) {\n if (this.rafIds_.has(id)) {\n this.rafIds_.delete(id);\n window.cancelAnimationFrame(id);\n }\n return id;\n }\n\n /**\n * A function to setup `requestAnimationFrame`, `setTimeout`,\n * and `setInterval`, clearing on dispose.\n *\n * > Previously each timer added and removed dispose listeners on it's own.\n * For better performance it was decided to batch them all, and use `Set`s\n * to track outstanding timer ids.\n *\n * @private\n */\n clearTimersOnDispose_() {\n if (this.clearingTimersOnDispose_) {\n return;\n }\n this.clearingTimersOnDispose_ = true;\n this.one('dispose', () => {\n [['namedRafs_', 'cancelNamedAnimationFrame'], ['rafIds_', 'cancelAnimationFrame'], ['setTimeoutIds_', 'clearTimeout'], ['setIntervalIds_', 'clearInterval']].forEach(([idName, cancelName]) => {\n // for a `Set` key will actually be the value again\n // so forEach((val, val) =>` but for maps we want to use\n // the key.\n this[idName].forEach((val, key) => this[cancelName](key));\n });\n this.clearingTimersOnDispose_ = false;\n });\n }\n\n /**\n * Decide whether an element is actually disabled or not.\n *\n * @function isActuallyDisabled\n * @param element {Node}\n * @return {boolean}\n *\n * @see {@link https://html.spec.whatwg.org/multipage/semantics-other.html#concept-element-disabled}\n */\n getIsDisabled() {\n return Boolean(this.el_.disabled);\n }\n\n /**\n * Decide whether the element is expressly inert or not.\n *\n * @see {@link https://html.spec.whatwg.org/multipage/interaction.html#expressly-inert}\n * @function isExpresslyInert\n * @param element {Node}\n * @return {boolean}\n */\n getIsExpresslyInert() {\n return this.el_.inert && !this.el_.ownerDocument.documentElement.inert;\n }\n\n /**\n * Determine whether or not this component can be considered as focusable component.\n *\n * @param {HTMLElement} el - The HTML element representing the component.\n * @return {boolean}\n * If the component can be focused, will be `true`. Otherwise, `false`.\n */\n getIsFocusable(el) {\n const element = el || this.el_;\n return element.tabIndex >= 0 && !(this.getIsDisabled() || this.getIsExpresslyInert());\n }\n\n /**\n * Determine whether or not this component is currently visible/enabled/etc...\n *\n * @param {HTMLElement} el - The HTML element representing the component.\n * @return {boolean}\n * If the component can is currently visible & enabled, will be `true`. Otherwise, `false`.\n */\n getIsAvailableToBeFocused(el) {\n /**\n * Decide the style property of this element is specified whether it's visible or not.\n *\n * @function isVisibleStyleProperty\n * @param element {CSSStyleDeclaration}\n * @return {boolean}\n */\n function isVisibleStyleProperty(element) {\n const elementStyle = window.getComputedStyle(element, null);\n const thisVisibility = elementStyle.getPropertyValue('visibility');\n const thisDisplay = elementStyle.getPropertyValue('display');\n const invisibleStyle = ['hidden', 'collapse'];\n return thisDisplay !== 'none' && !invisibleStyle.includes(thisVisibility);\n }\n\n /**\n * Decide whether the element is being rendered or not.\n * 1. If an element has the style as \"visibility: hidden | collapse\" or \"display: none\", it is not being rendered.\n * 2. If an element has the style as \"opacity: 0\", it is not being rendered.(that is, invisible).\n * 3. If width and height of an element are explicitly set to 0, it is not being rendered.\n * 4. If a parent element is hidden, an element itself is not being rendered.\n * (CSS visibility property and display property are inherited.)\n *\n * @see {@link https://html.spec.whatwg.org/multipage/rendering.html#being-rendered}\n * @function isBeingRendered\n * @param element {Node}\n * @return {boolean}\n */\n function isBeingRendered(element) {\n if (!isVisibleStyleProperty(element.parentElement)) {\n return false;\n }\n if (!isVisibleStyleProperty(element) || element.style.opacity === '0' || window.getComputedStyle(element).height === '0px' || window.getComputedStyle(element).width === '0px') {\n return false;\n }\n return true;\n }\n\n /**\n * Determine if the element is visible for the user or not.\n * 1. If an element sum of its offsetWidth, offsetHeight, height and width is less than 1 is not visible.\n * 2. If elementCenter.x is less than is not visible.\n * 3. If elementCenter.x is more than the document's width is not visible.\n * 4. If elementCenter.y is less than 0 is not visible.\n * 5. If elementCenter.y is the document's height is not visible.\n *\n * @function isVisible\n * @param element {Node}\n * @return {boolean}\n */\n function isVisible(element) {\n if (element.offsetWidth + element.offsetHeight + element.getBoundingClientRect().height + element.getBoundingClientRect().width === 0) {\n return false;\n }\n\n // Define elementCenter object with props of x and y\n // x: Left position relative to the viewport plus element's width (no margin) divided between 2.\n // y: Top position relative to the viewport plus element's height (no margin) divided between 2.\n const elementCenter = {\n x: element.getBoundingClientRect().left + element.offsetWidth / 2,\n y: element.getBoundingClientRect().top + element.offsetHeight / 2\n };\n if (elementCenter.x < 0) {\n return false;\n }\n if (elementCenter.x > (document.documentElement.clientWidth || window.innerWidth)) {\n return false;\n }\n if (elementCenter.y < 0) {\n return false;\n }\n if (elementCenter.y > (document.documentElement.clientHeight || window.innerHeight)) {\n return false;\n }\n let pointContainer = document.elementFromPoint(elementCenter.x, elementCenter.y);\n while (pointContainer) {\n if (pointContainer === element) {\n return true;\n }\n if (pointContainer.parentNode) {\n pointContainer = pointContainer.parentNode;\n } else {\n return false;\n }\n }\n }\n\n // If no DOM element was passed as argument use this component's element.\n if (!el) {\n el = this.el();\n }\n\n // If element is visible, is being rendered & either does not have a parent element or its tabIndex is not negative.\n if (isVisible(el) && isBeingRendered(el) && (!el.parentElement || el.tabIndex >= 0)) {\n return true;\n }\n return false;\n }\n\n /**\n * Register a `Component` with `videojs` given the name and the component.\n *\n * > NOTE: {@link Tech}s should not be registered as a `Component`. {@link Tech}s\n * should be registered using {@link Tech.registerTech} or\n * {@link videojs:videojs.registerTech}.\n *\n * > NOTE: This function can also be seen on videojs as\n * {@link videojs:videojs.registerComponent}.\n *\n * @param {string} name\n * The name of the `Component` to register.\n *\n * @param {Component} ComponentToRegister\n * The `Component` class to register.\n *\n * @return {Component}\n * The `Component` that was registered.\n */\n static registerComponent(name, ComponentToRegister) {\n if (typeof name !== 'string' || !name) {\n throw new Error(`Illegal component name, \"${name}\"; must be a non-empty string.`);\n }\n const Tech = Component.getComponent('Tech');\n\n // We need to make sure this check is only done if Tech has been registered.\n const isTech = Tech && Tech.isTech(ComponentToRegister);\n const isComp = Component === ComponentToRegister || Component.prototype.isPrototypeOf(ComponentToRegister.prototype);\n if (isTech || !isComp) {\n let reason;\n if (isTech) {\n reason = 'techs must be registered using Tech.registerTech()';\n } else {\n reason = 'must be a Component subclass';\n }\n throw new Error(`Illegal component, \"${name}\"; ${reason}.`);\n }\n name = toTitleCase(name);\n if (!Component.components_) {\n Component.components_ = {};\n }\n const Player = Component.getComponent('Player');\n if (name === 'Player' && Player && Player.players) {\n const players = Player.players;\n const playerNames = Object.keys(players);\n\n // If we have players that were disposed, then their name will still be\n // in Players.players. So, we must loop through and verify that the value\n // for each item is null. This allows registration of the Player component\n // after all players have been disposed or before any were created.\n if (players && playerNames.length > 0) {\n for (let i = 0; i < playerNames.length; i++) {\n if (players[playerNames[i]] !== null) {\n throw new Error('Can not register Player component after player has been created.');\n }\n }\n }\n }\n Component.components_[name] = ComponentToRegister;\n Component.components_[toLowerCase(name)] = ComponentToRegister;\n return ComponentToRegister;\n }\n\n /**\n * Get a `Component` based on the name it was registered with.\n *\n * @param {string} name\n * The Name of the component to get.\n *\n * @return {typeof Component}\n * The `Component` that got registered under the given name.\n */\n static getComponent(name) {\n if (!name || !Component.components_) {\n return;\n }\n return Component.components_[name];\n }\n }\n Component.registerComponent('Component', Component);\n\n /**\n * @file time.js\n * @module time\n */\n\n /**\n * Returns the time for the specified index at the start or end\n * of a TimeRange object.\n *\n * @typedef {Function} TimeRangeIndex\n *\n * @param {number} [index=0]\n * The range number to return the time for.\n *\n * @return {number}\n * The time offset at the specified index.\n *\n * @deprecated The index argument must be provided.\n * In the future, leaving it out will throw an error.\n */\n\n /**\n * An object that contains ranges of time, which mimics {@link TimeRanges}.\n *\n * @typedef {Object} TimeRange\n *\n * @property {number} length\n * The number of time ranges represented by this object.\n *\n * @property {module:time~TimeRangeIndex} start\n * Returns the time offset at which a specified time range begins.\n *\n * @property {module:time~TimeRangeIndex} end\n * Returns the time offset at which a specified time range ends.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges\n */\n\n /**\n * Check if any of the time ranges are over the maximum index.\n *\n * @private\n * @param {string} fnName\n * The function name to use for logging\n *\n * @param {number} index\n * The index to check\n *\n * @param {number} maxIndex\n * The maximum possible index\n *\n * @throws {Error} if the timeRanges provided are over the maxIndex\n */\n function rangeCheck(fnName, index, maxIndex) {\n if (typeof index !== 'number' || index < 0 || index > maxIndex) {\n throw new Error(`Failed to execute '${fnName}' on 'TimeRanges': The index provided (${index}) is non-numeric or out of bounds (0-${maxIndex}).`);\n }\n }\n\n /**\n * Get the time for the specified index at the start or end\n * of a TimeRange object.\n *\n * @private\n * @param {string} fnName\n * The function name to use for logging\n *\n * @param {string} valueIndex\n * The property that should be used to get the time. should be\n * 'start' or 'end'\n *\n * @param {Array} ranges\n * An array of time ranges\n *\n * @param {Array} [rangeIndex=0]\n * The index to start the search at\n *\n * @return {number}\n * The time that offset at the specified index.\n *\n * @deprecated rangeIndex must be set to a value, in the future this will throw an error.\n * @throws {Error} if rangeIndex is more than the length of ranges\n */\n function getRange(fnName, valueIndex, ranges, rangeIndex) {\n rangeCheck(fnName, rangeIndex, ranges.length - 1);\n return ranges[rangeIndex][valueIndex];\n }\n\n /**\n * Create a time range object given ranges of time.\n *\n * @private\n * @param {Array} [ranges]\n * An array of time ranges.\n *\n * @return {TimeRange}\n */\n function createTimeRangesObj(ranges) {\n let timeRangesObj;\n if (ranges === undefined || ranges.length === 0) {\n timeRangesObj = {\n length: 0,\n start() {\n throw new Error('This TimeRanges object is empty');\n },\n end() {\n throw new Error('This TimeRanges object is empty');\n }\n };\n } else {\n timeRangesObj = {\n length: ranges.length,\n start: getRange.bind(null, 'start', 0, ranges),\n end: getRange.bind(null, 'end', 1, ranges)\n };\n }\n if (window.Symbol && window.Symbol.iterator) {\n timeRangesObj[window.Symbol.iterator] = () => (ranges || []).values();\n }\n return timeRangesObj;\n }\n\n /**\n * Create a `TimeRange` object which mimics an\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges|HTML5 TimeRanges instance}.\n *\n * @param {number|Array[]} start\n * The start of a single range (a number) or an array of ranges (an\n * array of arrays of two numbers each).\n *\n * @param {number} end\n * The end of a single range. Cannot be used with the array form of\n * the `start` argument.\n *\n * @return {TimeRange}\n */\n function createTimeRanges(start, end) {\n if (Array.isArray(start)) {\n return createTimeRangesObj(start);\n } else if (start === undefined || end === undefined) {\n return createTimeRangesObj();\n }\n return createTimeRangesObj([[start, end]]);\n }\n\n /**\n * Format seconds as a time string, H:MM:SS or M:SS. Supplying a guide (in\n * seconds) will force a number of leading zeros to cover the length of the\n * guide.\n *\n * @private\n * @param {number} seconds\n * Number of seconds to be turned into a string\n *\n * @param {number} guide\n * Number (in seconds) to model the string after\n *\n * @return {string}\n * Time formatted as H:MM:SS or M:SS\n */\n const defaultImplementation = function (seconds, guide) {\n seconds = seconds < 0 ? 0 : seconds;\n let s = Math.floor(seconds % 60);\n let m = Math.floor(seconds / 60 % 60);\n let h = Math.floor(seconds / 3600);\n const gm = Math.floor(guide / 60 % 60);\n const gh = Math.floor(guide / 3600);\n\n // handle invalid times\n if (isNaN(seconds) || seconds === Infinity) {\n // '-' is false for all relational operators (e.g. <, >=) so this setting\n // will add the minimum number of fields specified by the guide\n h = m = s = '-';\n }\n\n // Check if we need to show hours\n h = h > 0 || gh > 0 ? h + ':' : '';\n\n // If hours are showing, we may need to add a leading zero.\n // Always show at least one digit of minutes.\n m = ((h || gm >= 10) && m < 10 ? '0' + m : m) + ':';\n\n // Check if leading zero is need for seconds\n s = s < 10 ? '0' + s : s;\n return h + m + s;\n };\n\n // Internal pointer to the current implementation.\n let implementation = defaultImplementation;\n\n /**\n * Replaces the default formatTime implementation with a custom implementation.\n *\n * @param {Function} customImplementation\n * A function which will be used in place of the default formatTime\n * implementation. Will receive the current time in seconds and the\n * guide (in seconds) as arguments.\n */\n function setFormatTime(customImplementation) {\n implementation = customImplementation;\n }\n\n /**\n * Resets formatTime to the default implementation.\n */\n function resetFormatTime() {\n implementation = defaultImplementation;\n }\n\n /**\n * Delegates to either the default time formatting function or a custom\n * function supplied via `setFormatTime`.\n *\n * Formats seconds as a time string (H:MM:SS or M:SS). Supplying a\n * guide (in seconds) will force a number of leading zeros to cover the\n * length of the guide.\n *\n * @example formatTime(125, 600) === \"02:05\"\n * @param {number} seconds\n * Number of seconds to be turned into a string\n *\n * @param {number} guide\n * Number (in seconds) to model the string after\n *\n * @return {string}\n * Time formatted as H:MM:SS or M:SS\n */\n function formatTime(seconds, guide = seconds) {\n return implementation(seconds, guide);\n }\n\n var Time = /*#__PURE__*/Object.freeze({\n __proto__: null,\n createTimeRanges: createTimeRanges,\n createTimeRange: createTimeRanges,\n setFormatTime: setFormatTime,\n resetFormatTime: resetFormatTime,\n formatTime: formatTime\n });\n\n /**\n * @file buffer.js\n * @module buffer\n */\n\n /** @import { TimeRange } from './time' */\n\n /**\n * Compute the percentage of the media that has been buffered.\n *\n * @param {TimeRange} buffered\n * The current `TimeRanges` object representing buffered time ranges\n *\n * @param {number} duration\n * Total duration of the media\n *\n * @return {number}\n * Percent buffered of the total duration in decimal form.\n */\n function bufferedPercent(buffered, duration) {\n let bufferedDuration = 0;\n let start;\n let end;\n if (!duration) {\n return 0;\n }\n if (!buffered || !buffered.length) {\n buffered = createTimeRanges(0, 0);\n }\n for (let i = 0; i < buffered.length; i++) {\n start = buffered.start(i);\n end = buffered.end(i);\n\n // buffered end can be bigger than duration by a very small fraction\n if (end > duration) {\n end = duration;\n }\n bufferedDuration += end - start;\n }\n return bufferedDuration / duration;\n }\n\n /**\n * @file media-error.js\n */\n\n /**\n * A Custom `MediaError` class which mimics the standard HTML5 `MediaError` class.\n *\n * @param {number|string|Object|MediaError} value\n * This can be of multiple types:\n * - number: should be a standard error code\n * - string: an error message (the code will be 0)\n * - Object: arbitrary properties\n * - `MediaError` (native): used to populate a video.js `MediaError` object\n * - `MediaError` (video.js): will return itself if it's already a\n * video.js `MediaError` object.\n *\n * @see [MediaError Spec]{@link https://dev.w3.org/html5/spec-author-view/video.html#mediaerror}\n * @see [Encrypted MediaError Spec]{@link https://www.w3.org/TR/2013/WD-encrypted-media-20130510/#error-codes}\n *\n * @class MediaError\n */\n function MediaError(value) {\n // Allow redundant calls to this constructor to avoid having `instanceof`\n // checks peppered around the code.\n if (value instanceof MediaError) {\n return value;\n }\n if (typeof value === 'number') {\n this.code = value;\n } else if (typeof value === 'string') {\n // default code is zero, so this is a custom error\n this.message = value;\n } else if (isObject(value)) {\n // We assign the `code` property manually because native `MediaError` objects\n // do not expose it as an own/enumerable property of the object.\n if (typeof value.code === 'number') {\n this.code = value.code;\n }\n Object.assign(this, value);\n }\n if (!this.message) {\n this.message = MediaError.defaultMessages[this.code] || '';\n }\n }\n\n /**\n * The error code that refers two one of the defined `MediaError` types\n *\n * @type {Number}\n */\n MediaError.prototype.code = 0;\n\n /**\n * An optional message that to show with the error. Message is not part of the HTML5\n * video spec but allows for more informative custom errors.\n *\n * @type {String}\n */\n MediaError.prototype.message = '';\n\n /**\n * An optional status code that can be set by plugins to allow even more detail about\n * the error. For example a plugin might provide a specific HTTP status code and an\n * error message for that code. Then when the plugin gets that error this class will\n * know how to display an error message for it. This allows a custom message to show\n * up on the `Player` error overlay.\n *\n * @type {Array}\n */\n MediaError.prototype.status = null;\n\n /**\n * An object containing an error type, as well as other information regarding the error.\n *\n * @typedef {{errorType: string, [key: string]: any}} ErrorMetadata\n */\n\n /**\n * An optional object to give more detail about the error. This can be used to give\n * a higher level of specificity to an error versus the more generic MediaError codes.\n * `metadata` expects an `errorType` string that should align with the values from videojs.Error.\n *\n * @type {ErrorMetadata}\n */\n MediaError.prototype.metadata = null;\n\n /**\n * Errors indexed by the W3C standard. The order **CANNOT CHANGE**! See the\n * specification listed under {@link MediaError} for more information.\n *\n * @enum {array}\n * @readonly\n * @property {string} 0 - MEDIA_ERR_CUSTOM\n * @property {string} 1 - MEDIA_ERR_ABORTED\n * @property {string} 2 - MEDIA_ERR_NETWORK\n * @property {string} 3 - MEDIA_ERR_DECODE\n * @property {string} 4 - MEDIA_ERR_SRC_NOT_SUPPORTED\n * @property {string} 5 - MEDIA_ERR_ENCRYPTED\n */\n MediaError.errorTypes = ['MEDIA_ERR_CUSTOM', 'MEDIA_ERR_ABORTED', 'MEDIA_ERR_NETWORK', 'MEDIA_ERR_DECODE', 'MEDIA_ERR_SRC_NOT_SUPPORTED', 'MEDIA_ERR_ENCRYPTED'];\n\n /**\n * The default `MediaError` messages based on the {@link MediaError.errorTypes}.\n *\n * @type {Array}\n * @constant\n */\n MediaError.defaultMessages = {\n 1: 'You aborted the media playback',\n 2: 'A network error caused the media download to fail part-way.',\n 3: 'The media playback was aborted due to a corruption problem or because the media used features your browser did not support.',\n 4: 'The media could not be loaded, either because the server or network failed or because the format is not supported.',\n 5: 'The media is encrypted and we do not have the keys to decrypt it.'\n };\n\n /**\n * W3C error code for any custom error.\n *\n * @member MediaError#MEDIA_ERR_CUSTOM\n * @constant {number}\n * @default 0\n */\n MediaError.MEDIA_ERR_CUSTOM = 0;\n\n /**\n * W3C error code for any custom error.\n *\n * @member MediaError.MEDIA_ERR_CUSTOM\n * @constant {number}\n * @default 0\n */\n MediaError.prototype.MEDIA_ERR_CUSTOM = 0;\n\n /**\n * W3C error code for media error aborted.\n *\n * @member MediaError#MEDIA_ERR_ABORTED\n * @constant {number}\n * @default 1\n */\n MediaError.MEDIA_ERR_ABORTED = 1;\n\n /**\n * W3C error code for media error aborted.\n *\n * @member MediaError.MEDIA_ERR_ABORTED\n * @constant {number}\n * @default 1\n */\n MediaError.prototype.MEDIA_ERR_ABORTED = 1;\n\n /**\n * W3C error code for any network error.\n *\n * @member MediaError#MEDIA_ERR_NETWORK\n * @constant {number}\n * @default 2\n */\n MediaError.MEDIA_ERR_NETWORK = 2;\n\n /**\n * W3C error code for any network error.\n *\n * @member MediaError.MEDIA_ERR_NETWORK\n * @constant {number}\n * @default 2\n */\n MediaError.prototype.MEDIA_ERR_NETWORK = 2;\n\n /**\n * W3C error code for any decoding error.\n *\n * @member MediaError#MEDIA_ERR_DECODE\n * @constant {number}\n * @default 3\n */\n MediaError.MEDIA_ERR_DECODE = 3;\n\n /**\n * W3C error code for any decoding error.\n *\n * @member MediaError.MEDIA_ERR_DECODE\n * @constant {number}\n * @default 3\n */\n MediaError.prototype.MEDIA_ERR_DECODE = 3;\n\n /**\n * W3C error code for any time that a source is not supported.\n *\n * @member MediaError#MEDIA_ERR_SRC_NOT_SUPPORTED\n * @constant {number}\n * @default 4\n */\n MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = 4;\n\n /**\n * W3C error code for any time that a source is not supported.\n *\n * @member MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED\n * @constant {number}\n * @default 4\n */\n MediaError.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED = 4;\n\n /**\n * W3C error code for any time that a source is encrypted.\n *\n * @member MediaError#MEDIA_ERR_ENCRYPTED\n * @constant {number}\n * @default 5\n */\n MediaError.MEDIA_ERR_ENCRYPTED = 5;\n\n /**\n * W3C error code for any time that a source is encrypted.\n *\n * @member MediaError.MEDIA_ERR_ENCRYPTED\n * @constant {number}\n * @default 5\n */\n MediaError.prototype.MEDIA_ERR_ENCRYPTED = 5;\n\n /**\n * Returns whether an object is `Promise`-like (i.e. has a `then` method).\n *\n * @param {Object} value\n * An object that may or may not be `Promise`-like.\n *\n * @return {boolean}\n * Whether or not the object is `Promise`-like.\n */\n function isPromise(value) {\n return value !== undefined && value !== null && typeof value.then === 'function';\n }\n\n /**\n * Silence a Promise-like object.\n *\n * This is useful for avoiding non-harmful, but potentially confusing \"uncaught\n * play promise\" rejection error messages.\n *\n * @param {Object} value\n * An object that may or may not be `Promise`-like.\n */\n function silencePromise(value) {\n if (isPromise(value)) {\n value.then(null, e => {});\n }\n }\n\n /**\n * @file text-track-list-converter.js Utilities for capturing text track state and\n * re-creating tracks based on a capture.\n *\n * @module text-track-list-converter\n */\n\n /** @import Tech from '../tech/tech' */\n\n /**\n * Examine a single {@link TextTrack} and return a JSON-compatible javascript object that\n * represents the {@link TextTrack}'s state.\n *\n * @param {TextTrack} track\n * The text track to query.\n *\n * @return {Object}\n * A serializable javascript representation of the TextTrack.\n * @private\n */\n const trackToJson = function (track) {\n const ret = ['kind', 'label', 'language', 'id', 'inBandMetadataTrackDispatchType', 'mode', 'src'].reduce((acc, prop, i) => {\n if (track[prop]) {\n acc[prop] = track[prop];\n }\n return acc;\n }, {\n cues: track.cues && Array.prototype.map.call(track.cues, function (cue) {\n return {\n startTime: cue.startTime,\n endTime: cue.endTime,\n text: cue.text,\n id: cue.id\n };\n })\n });\n return ret;\n };\n\n /**\n * Examine a {@link Tech} and return a JSON-compatible javascript array that represents the\n * state of all {@link TextTrack}s currently configured. The return array is compatible with\n * {@link text-track-list-converter:jsonToTextTracks}.\n *\n * @param {Tech} tech\n * The tech object to query\n *\n * @return {Array}\n * A serializable javascript representation of the {@link Tech}s\n * {@link TextTrackList}.\n */\n const textTracksToJson = function (tech) {\n const trackEls = tech.$$('track');\n const trackObjs = Array.prototype.map.call(trackEls, t => t.track);\n const tracks = Array.prototype.map.call(trackEls, function (trackEl) {\n const json = trackToJson(trackEl.track);\n if (trackEl.src) {\n json.src = trackEl.src;\n }\n return json;\n });\n return tracks.concat(Array.prototype.filter.call(tech.textTracks(), function (track) {\n return trackObjs.indexOf(track) === -1;\n }).map(trackToJson));\n };\n\n /**\n * Create a set of remote {@link TextTrack}s on a {@link Tech} based on an array of javascript\n * object {@link TextTrack} representations.\n *\n * @param {Array} json\n * An array of `TextTrack` representation objects, like those that would be\n * produced by `textTracksToJson`.\n *\n * @param {Tech} tech\n * The `Tech` to create the `TextTrack`s on.\n */\n const jsonToTextTracks = function (json, tech) {\n json.forEach(function (track) {\n const addedTrack = tech.addRemoteTextTrack(track).track;\n if (!track.src && track.cues) {\n track.cues.forEach(cue => addedTrack.addCue(cue));\n }\n });\n return tech.textTracks();\n };\n var textTrackConverter = {\n textTracksToJson,\n jsonToTextTracks,\n trackToJson\n };\n\n /**\n * @file modal-dialog.js\n */\n\n /** @import Player from './player' */\n /** @import { ContentDescriptor } from './utils/dom' */\n\n const MODAL_CLASS_NAME = 'vjs-modal-dialog';\n\n /**\n * The `ModalDialog` displays over the video and its controls, which blocks\n * interaction with the player until it is closed.\n *\n * Modal dialogs include a \"Close\" button and will close when that button\n * is activated - or when ESC is pressed anywhere.\n *\n * @extends Component\n */\n class ModalDialog extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {ContentDescriptor} [options.content=undefined]\n * Provide customized content for this modal.\n *\n * @param {string} [options.description]\n * A text description for the modal, primarily for accessibility.\n *\n * @param {boolean} [options.fillAlways=false]\n * Normally, modals are automatically filled only the first time\n * they open. This tells the modal to refresh its content\n * every time it opens.\n *\n * @param {string} [options.label]\n * A text label for the modal, primarily for accessibility.\n *\n * @param {boolean} [options.pauseOnOpen=true]\n * If `true`, playback will will be paused if playing when\n * the modal opens, and resumed when it closes.\n *\n * @param {boolean} [options.temporary=true]\n * If `true`, the modal can only be opened once; it will be\n * disposed as soon as it's closed.\n *\n * @param {boolean} [options.uncloseable=false]\n * If `true`, the user will not be able to close the modal\n * through the UI in the normal ways. Programmatic closing is\n * still possible.\n */\n constructor(player, options) {\n super(player, options);\n this.handleKeyDown_ = e => this.handleKeyDown(e);\n this.close_ = e => this.close(e);\n this.opened_ = this.hasBeenOpened_ = this.hasBeenFilled_ = false;\n this.closeable(!this.options_.uncloseable);\n this.content(this.options_.content);\n\n // Make sure the contentEl is defined AFTER any children are initialized\n // because we only want the contents of the modal in the contentEl\n // (not the UI elements like the close button).\n this.contentEl_ = createEl('div', {\n className: `${MODAL_CLASS_NAME}-content`\n }, {\n role: 'document'\n });\n this.descEl_ = createEl('p', {\n className: `${MODAL_CLASS_NAME}-description vjs-control-text`,\n id: this.el().getAttribute('aria-describedby')\n });\n textContent(this.descEl_, this.description());\n this.el_.appendChild(this.descEl_);\n this.el_.appendChild(this.contentEl_);\n }\n\n /**\n * Create the `ModalDialog`'s DOM element\n *\n * @return {Element}\n * The DOM element that gets created.\n */\n createEl() {\n return super.createEl('div', {\n className: this.buildCSSClass(),\n tabIndex: -1\n }, {\n 'aria-describedby': `${this.id()}_description`,\n 'aria-hidden': 'true',\n 'aria-label': this.label(),\n 'role': 'dialog',\n 'aria-live': 'polite'\n });\n }\n dispose() {\n this.contentEl_ = null;\n this.descEl_ = null;\n this.previouslyActiveEl_ = null;\n super.dispose();\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `${MODAL_CLASS_NAME} vjs-hidden ${super.buildCSSClass()}`;\n }\n\n /**\n * Returns the label string for this modal. Primarily used for accessibility.\n *\n * @return {string}\n * the localized or raw label of this modal.\n */\n label() {\n return this.localize(this.options_.label || 'Modal Window');\n }\n\n /**\n * Returns the description string for this modal. Primarily used for\n * accessibility.\n *\n * @return {string}\n * The localized or raw description of this modal.\n */\n description() {\n let desc = this.options_.description || this.localize('This is a modal window.');\n\n // Append a universal closeability message if the modal is closeable.\n if (this.closeable()) {\n desc += ' ' + this.localize('This modal can be closed by pressing the Escape key or activating the close button.');\n }\n return desc;\n }\n\n /**\n * Opens the modal.\n *\n * @fires ModalDialog#beforemodalopen\n * @fires ModalDialog#modalopen\n */\n open() {\n if (this.opened_) {\n if (this.options_.fillAlways) {\n this.fill();\n }\n return;\n }\n const player = this.player();\n\n /**\n * Fired just before a `ModalDialog` is opened.\n *\n * @event ModalDialog#beforemodalopen\n * @type {Event}\n */\n this.trigger('beforemodalopen');\n this.opened_ = true;\n\n // Fill content if the modal has never opened before and\n // never been filled.\n if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) {\n this.fill();\n }\n\n // If the player was playing, pause it and take note of its previously\n // playing state.\n this.wasPlaying_ = !player.paused();\n if (this.options_.pauseOnOpen && this.wasPlaying_) {\n player.pause();\n }\n this.on('keydown', this.handleKeyDown_);\n\n // Hide controls and note if they were enabled.\n this.hadControls_ = player.controls();\n player.controls(false);\n this.show();\n this.conditionalFocus_();\n this.el().setAttribute('aria-hidden', 'false');\n\n /**\n * Fired just after a `ModalDialog` is opened.\n *\n * @event ModalDialog#modalopen\n * @type {Event}\n */\n this.trigger('modalopen');\n this.hasBeenOpened_ = true;\n }\n\n /**\n * If the `ModalDialog` is currently open or closed.\n *\n * @param {boolean} [value]\n * If given, it will open (`true`) or close (`false`) the modal.\n *\n * @return {boolean}\n * the current open state of the modaldialog\n */\n opened(value) {\n if (typeof value === 'boolean') {\n this[value ? 'open' : 'close']();\n }\n return this.opened_;\n }\n\n /**\n * Closes the modal, does nothing if the `ModalDialog` is\n * not open.\n *\n * @fires ModalDialog#beforemodalclose\n * @fires ModalDialog#modalclose\n */\n close() {\n if (!this.opened_) {\n return;\n }\n const player = this.player();\n\n /**\n * Fired just before a `ModalDialog` is closed.\n *\n * @event ModalDialog#beforemodalclose\n * @type {Event}\n */\n this.trigger('beforemodalclose');\n this.opened_ = false;\n if (this.wasPlaying_ && this.options_.pauseOnOpen) {\n player.play();\n }\n this.off('keydown', this.handleKeyDown_);\n if (this.hadControls_) {\n player.controls(true);\n }\n this.hide();\n this.el().setAttribute('aria-hidden', 'true');\n\n /**\n * Fired just after a `ModalDialog` is closed.\n *\n * @event ModalDialog#modalclose\n * @type {Event}\n *\n * @property {boolean} [bubbles=true]\n */\n this.trigger({\n type: 'modalclose',\n bubbles: true\n });\n this.conditionalBlur_();\n if (this.options_.temporary) {\n this.dispose();\n }\n }\n\n /**\n * Check to see if the `ModalDialog` is closeable via the UI.\n *\n * @param {boolean} [value]\n * If given as a boolean, it will set the `closeable` option.\n *\n * @return {boolean}\n * Returns the final value of the closable option.\n */\n closeable(value) {\n if (typeof value === 'boolean') {\n const closeable = this.closeable_ = !!value;\n let close = this.getChild('closeButton');\n\n // If this is being made closeable and has no close button, add one.\n if (closeable && !close) {\n // The close button should be a child of the modal - not its\n // content element, so temporarily change the content element.\n const temp = this.contentEl_;\n this.contentEl_ = this.el_;\n close = this.addChild('closeButton', {\n controlText: 'Close Modal Dialog'\n });\n this.contentEl_ = temp;\n this.on(close, 'close', this.close_);\n }\n\n // If this is being made uncloseable and has a close button, remove it.\n if (!closeable && close) {\n this.off(close, 'close', this.close_);\n this.removeChild(close);\n close.dispose();\n }\n }\n return this.closeable_;\n }\n\n /**\n * Fill the modal's content element with the modal's \"content\" option.\n * The content element will be emptied before this change takes place.\n */\n fill() {\n this.fillWith(this.content());\n }\n\n /**\n * Fill the modal's content element with arbitrary content.\n * The content element will be emptied before this change takes place.\n *\n * @fires ModalDialog#beforemodalfill\n * @fires ModalDialog#modalfill\n *\n * @param {ContentDescriptor} [content]\n * The same rules apply to this as apply to the `content` option.\n */\n fillWith(content) {\n const contentEl = this.contentEl();\n const parentEl = contentEl.parentNode;\n const nextSiblingEl = contentEl.nextSibling;\n\n /**\n * Fired just before a `ModalDialog` is filled with content.\n *\n * @event ModalDialog#beforemodalfill\n * @type {Event}\n */\n this.trigger('beforemodalfill');\n this.hasBeenFilled_ = true;\n\n // Detach the content element from the DOM before performing\n // manipulation to avoid modifying the live DOM multiple times.\n parentEl.removeChild(contentEl);\n this.empty();\n insertContent(contentEl, content);\n /**\n * Fired just after a `ModalDialog` is filled with content.\n *\n * @event ModalDialog#modalfill\n * @type {Event}\n */\n this.trigger('modalfill');\n\n // Re-inject the re-filled content element.\n if (nextSiblingEl) {\n parentEl.insertBefore(contentEl, nextSiblingEl);\n } else {\n parentEl.appendChild(contentEl);\n }\n\n // make sure that the close button is last in the dialog DOM\n const closeButton = this.getChild('closeButton');\n if (closeButton) {\n parentEl.appendChild(closeButton.el_);\n }\n\n /**\n * Fired after `ModalDialog` is re-filled with content & close button is appended.\n *\n * @event ModalDialog#aftermodalfill\n * @type {Event}\n */\n this.trigger('aftermodalfill');\n }\n\n /**\n * Empties the content element. This happens anytime the modal is filled.\n *\n * @fires ModalDialog#beforemodalempty\n * @fires ModalDialog#modalempty\n */\n empty() {\n /**\n * Fired just before a `ModalDialog` is emptied.\n *\n * @event ModalDialog#beforemodalempty\n * @type {Event}\n */\n this.trigger('beforemodalempty');\n emptyEl(this.contentEl());\n\n /**\n * Fired just after a `ModalDialog` is emptied.\n *\n * @event ModalDialog#modalempty\n * @type {Event}\n */\n this.trigger('modalempty');\n }\n\n /**\n * Gets or sets the modal content, which gets normalized before being\n * rendered into the DOM.\n *\n * This does not update the DOM or fill the modal, but it is called during\n * that process.\n *\n * @param {ContentDescriptor} [value]\n * If defined, sets the internal content value to be used on the\n * next call(s) to `fill`. This value is normalized before being\n * inserted. To \"clear\" the internal content value, pass `null`.\n *\n * @return {ContentDescriptor}\n * The current content of the modal dialog\n */\n content(value) {\n if (typeof value !== 'undefined') {\n this.content_ = value;\n }\n return this.content_;\n }\n\n /**\n * conditionally focus the modal dialog if focus was previously on the player.\n *\n * @private\n */\n conditionalFocus_() {\n const activeEl = document.activeElement;\n const playerEl = this.player_.el_;\n this.previouslyActiveEl_ = null;\n if (playerEl.contains(activeEl) || playerEl === activeEl) {\n this.previouslyActiveEl_ = activeEl;\n this.focus();\n }\n }\n\n /**\n * conditionally blur the element and refocus the last focused element\n *\n * @private\n */\n conditionalBlur_() {\n if (this.previouslyActiveEl_) {\n this.previouslyActiveEl_.focus();\n this.previouslyActiveEl_ = null;\n }\n }\n\n /**\n * Keydown handler. Attached when modal is focused.\n *\n * @listens keydown\n */\n handleKeyDown(event) {\n /**\n * Fired a custom keyDown event that bubbles.\n *\n * @event ModalDialog#modalKeydown\n * @type {Event}\n */\n this.trigger({\n type: 'modalKeydown',\n originalEvent: event,\n target: this,\n bubbles: true\n });\n // Do not allow keydowns to reach out of the modal dialog.\n event.stopPropagation();\n if (event.key === 'Escape' && this.closeable()) {\n event.preventDefault();\n this.close();\n return;\n }\n\n // exit early if it isn't a tab key\n if (event.key !== 'Tab') {\n return;\n }\n const focusableEls = this.focusableEls_();\n const activeEl = this.el_.querySelector(':focus');\n let focusIndex;\n for (let i = 0; i < focusableEls.length; i++) {\n if (activeEl === focusableEls[i]) {\n focusIndex = i;\n break;\n }\n }\n if (document.activeElement === this.el_) {\n focusIndex = 0;\n }\n if (event.shiftKey && focusIndex === 0) {\n focusableEls[focusableEls.length - 1].focus();\n event.preventDefault();\n } else if (!event.shiftKey && focusIndex === focusableEls.length - 1) {\n focusableEls[0].focus();\n event.preventDefault();\n }\n }\n\n /**\n * get all focusable elements\n *\n * @private\n */\n focusableEls_() {\n const allChildren = this.el_.querySelectorAll('*');\n return Array.prototype.filter.call(allChildren, child => {\n return (child instanceof window.HTMLAnchorElement || child instanceof window.HTMLAreaElement) && child.hasAttribute('href') || (child instanceof window.HTMLInputElement || child instanceof window.HTMLSelectElement || child instanceof window.HTMLTextAreaElement || child instanceof window.HTMLButtonElement) && !child.hasAttribute('disabled') || child instanceof window.HTMLIFrameElement || child instanceof window.HTMLObjectElement || child instanceof window.HTMLEmbedElement || child.hasAttribute('tabindex') && child.getAttribute('tabindex') !== -1 || child.hasAttribute('contenteditable');\n });\n }\n }\n\n /**\n * Default options for `ModalDialog` default options.\n *\n * @type {Object}\n * @private\n */\n ModalDialog.prototype.options_ = {\n pauseOnOpen: true,\n temporary: true\n };\n Component.registerComponent('ModalDialog', ModalDialog);\n\n /**\n * @file track-list.js\n */\n\n /** @import Track from './track' */\n\n /**\n * Common functionaliy between {@link TextTrackList}, {@link AudioTrackList}, and\n * {@link VideoTrackList}\n *\n * @extends EventTarget\n */\n class TrackList extends EventTarget {\n /**\n * Create an instance of this class\n *\n * @param { Track[] } tracks\n * A list of tracks to initialize the list with.\n *\n * @abstract\n */\n constructor(tracks = []) {\n super();\n this.tracks_ = [];\n\n /**\n * @memberof TrackList\n * @member {number} length\n * The current number of `Track`s in the this Trackist.\n * @instance\n */\n Object.defineProperty(this, 'length', {\n get() {\n return this.tracks_.length;\n }\n });\n for (let i = 0; i < tracks.length; i++) {\n this.addTrack(tracks[i]);\n }\n }\n\n /**\n * Add a {@link Track} to the `TrackList`\n *\n * @param {Track} track\n * The audio, video, or text track to add to the list.\n *\n * @fires TrackList#addtrack\n */\n addTrack(track) {\n const index = this.tracks_.length;\n if (!('' + index in this)) {\n Object.defineProperty(this, index, {\n get() {\n return this.tracks_[index];\n }\n });\n }\n\n // Do not add duplicate tracks\n if (this.tracks_.indexOf(track) === -1) {\n this.tracks_.push(track);\n /**\n * Triggered when a track is added to a track list.\n *\n * @event TrackList#addtrack\n * @type {Event}\n * @property {Track} track\n * A reference to track that was added.\n */\n this.trigger({\n track,\n type: 'addtrack',\n target: this\n });\n }\n\n /**\n * Triggered when a track label is changed.\n *\n * @event TrackList#addtrack\n * @type {Event}\n * @property {Track} track\n * A reference to track that was added.\n */\n track.labelchange_ = () => {\n this.trigger({\n track,\n type: 'labelchange',\n target: this\n });\n };\n if (isEvented(track)) {\n track.addEventListener('labelchange', track.labelchange_);\n }\n }\n\n /**\n * Remove a {@link Track} from the `TrackList`\n *\n * @param {Track} rtrack\n * The audio, video, or text track to remove from the list.\n *\n * @fires TrackList#removetrack\n */\n removeTrack(rtrack) {\n let track;\n for (let i = 0, l = this.length; i < l; i++) {\n if (this[i] === rtrack) {\n track = this[i];\n if (track.off) {\n track.off();\n }\n this.tracks_.splice(i, 1);\n break;\n }\n }\n if (!track) {\n return;\n }\n\n /**\n * Triggered when a track is removed from track list.\n *\n * @event TrackList#removetrack\n * @type {Event}\n * @property {Track} track\n * A reference to track that was removed.\n */\n this.trigger({\n track,\n type: 'removetrack',\n target: this\n });\n }\n\n /**\n * Get a Track from the TrackList by a tracks id\n *\n * @param {string} id - the id of the track to get\n * @method getTrackById\n * @return {Track}\n * @private\n */\n getTrackById(id) {\n let result = null;\n for (let i = 0, l = this.length; i < l; i++) {\n const track = this[i];\n if (track.id === id) {\n result = track;\n break;\n }\n }\n return result;\n }\n }\n\n /**\n * Triggered when a different track is selected/enabled.\n *\n * @event TrackList#change\n * @type {Event}\n */\n\n /**\n * Events that can be called with on + eventName. See {@link EventHandler}.\n *\n * @property {Object} TrackList#allowedEvents_\n * @protected\n */\n TrackList.prototype.allowedEvents_ = {\n change: 'change',\n addtrack: 'addtrack',\n removetrack: 'removetrack',\n labelchange: 'labelchange'\n };\n\n // emulate attribute EventHandler support to allow for feature detection\n for (const event in TrackList.prototype.allowedEvents_) {\n TrackList.prototype['on' + event] = null;\n }\n\n /**\n * @file audio-track-list.js\n */\n\n /** @import AudioTrack from './audio-track' */\n\n /**\n * Anywhere we call this function we diverge from the spec\n * as we only support one enabled audiotrack at a time\n *\n * @param {AudioTrackList} list\n * list to work on\n *\n * @param {AudioTrack} track\n * The track to skip\n *\n * @private\n */\n const disableOthers$1 = function (list, track) {\n for (let i = 0; i < list.length; i++) {\n if (!Object.keys(list[i]).length || track.id === list[i].id) {\n continue;\n }\n // another audio track is enabled, disable it\n list[i].enabled = false;\n }\n };\n\n /**\n * The current list of {@link AudioTrack} for a media file.\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist}\n * @extends TrackList\n */\n class AudioTrackList extends TrackList {\n /**\n * Create an instance of this class.\n *\n * @param {AudioTrack[]} [tracks=[]]\n * A list of `AudioTrack` to instantiate the list with.\n */\n constructor(tracks = []) {\n // make sure only 1 track is enabled\n // sorted from last index to first index\n for (let i = tracks.length - 1; i >= 0; i--) {\n if (tracks[i].enabled) {\n disableOthers$1(tracks, tracks[i]);\n break;\n }\n }\n super(tracks);\n this.changing_ = false;\n }\n\n /**\n * Add an {@link AudioTrack} to the `AudioTrackList`.\n *\n * @param {AudioTrack} track\n * The AudioTrack to add to the list\n *\n * @fires TrackList#addtrack\n */\n addTrack(track) {\n if (track.enabled) {\n disableOthers$1(this, track);\n }\n super.addTrack(track);\n // native tracks don't have this\n if (!track.addEventListener) {\n return;\n }\n track.enabledChange_ = () => {\n // when we are disabling other tracks (since we don't support\n // more than one track at a time) we will set changing_\n // to true so that we don't trigger additional change events\n if (this.changing_) {\n return;\n }\n this.changing_ = true;\n disableOthers$1(this, track);\n this.changing_ = false;\n this.trigger('change');\n };\n\n /**\n * @listens AudioTrack#enabledchange\n * @fires TrackList#change\n */\n track.addEventListener('enabledchange', track.enabledChange_);\n }\n removeTrack(rtrack) {\n super.removeTrack(rtrack);\n if (rtrack.removeEventListener && rtrack.enabledChange_) {\n rtrack.removeEventListener('enabledchange', rtrack.enabledChange_);\n rtrack.enabledChange_ = null;\n }\n }\n }\n\n /**\n * @file video-track-list.js\n */\n\n /** @import VideoTrack from './video-track' */\n\n /**\n * Un-select all other {@link VideoTrack}s that are selected.\n *\n * @param {VideoTrackList} list\n * list to work on\n *\n * @param {VideoTrack} track\n * The track to skip\n *\n * @private\n */\n const disableOthers = function (list, track) {\n for (let i = 0; i < list.length; i++) {\n if (!Object.keys(list[i]).length || track.id === list[i].id) {\n continue;\n }\n // another video track is enabled, disable it\n list[i].selected = false;\n }\n };\n\n /**\n * The current list of {@link VideoTrack} for a video.\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist}\n * @extends TrackList\n */\n class VideoTrackList extends TrackList {\n /**\n * Create an instance of this class.\n *\n * @param {VideoTrack[]} [tracks=[]]\n * A list of `VideoTrack` to instantiate the list with.\n */\n constructor(tracks = []) {\n // make sure only 1 track is enabled\n // sorted from last index to first index\n for (let i = tracks.length - 1; i >= 0; i--) {\n if (tracks[i].selected) {\n disableOthers(tracks, tracks[i]);\n break;\n }\n }\n super(tracks);\n this.changing_ = false;\n\n /**\n * @member {number} VideoTrackList#selectedIndex\n * The current index of the selected {@link VideoTrack`}.\n */\n Object.defineProperty(this, 'selectedIndex', {\n get() {\n for (let i = 0; i < this.length; i++) {\n if (this[i].selected) {\n return i;\n }\n }\n return -1;\n },\n set() {}\n });\n }\n\n /**\n * Add a {@link VideoTrack} to the `VideoTrackList`.\n *\n * @param {VideoTrack} track\n * The VideoTrack to add to the list\n *\n * @fires TrackList#addtrack\n */\n addTrack(track) {\n if (track.selected) {\n disableOthers(this, track);\n }\n super.addTrack(track);\n // native tracks don't have this\n if (!track.addEventListener) {\n return;\n }\n track.selectedChange_ = () => {\n if (this.changing_) {\n return;\n }\n this.changing_ = true;\n disableOthers(this, track);\n this.changing_ = false;\n this.trigger('change');\n };\n\n /**\n * @listens VideoTrack#selectedchange\n * @fires TrackList#change\n */\n track.addEventListener('selectedchange', track.selectedChange_);\n }\n removeTrack(rtrack) {\n super.removeTrack(rtrack);\n if (rtrack.removeEventListener && rtrack.selectedChange_) {\n rtrack.removeEventListener('selectedchange', rtrack.selectedChange_);\n rtrack.selectedChange_ = null;\n }\n }\n }\n\n /**\n * @file text-track-list.js\n */\n\n /** @import TextTrack from './text-track' */\n\n /**\n * The current list of {@link TextTrack} for a media file.\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist}\n * @extends TrackList\n */\n class TextTrackList extends TrackList {\n /**\n * Add a {@link TextTrack} to the `TextTrackList`\n *\n * @param {TextTrack} track\n * The text track to add to the list.\n *\n * @fires TrackList#addtrack\n */\n addTrack(track) {\n super.addTrack(track);\n if (!this.queueChange_) {\n this.queueChange_ = () => this.queueTrigger('change');\n }\n if (!this.triggerSelectedlanguagechange) {\n this.triggerSelectedlanguagechange_ = () => this.trigger('selectedlanguagechange');\n }\n\n /**\n * @listens TextTrack#modechange\n * @fires TrackList#change\n */\n track.addEventListener('modechange', this.queueChange_);\n const nonLanguageTextTrackKind = ['metadata', 'chapters'];\n if (nonLanguageTextTrackKind.indexOf(track.kind) === -1) {\n track.addEventListener('modechange', this.triggerSelectedlanguagechange_);\n }\n }\n removeTrack(rtrack) {\n super.removeTrack(rtrack);\n\n // manually remove the event handlers we added\n if (rtrack.removeEventListener) {\n if (this.queueChange_) {\n rtrack.removeEventListener('modechange', this.queueChange_);\n }\n if (this.selectedlanguagechange_) {\n rtrack.removeEventListener('modechange', this.triggerSelectedlanguagechange_);\n }\n }\n }\n\n /**\n * Creates a serializable array of objects that contains serialized copies\n * of each text track.\n *\n * @return {Object[]} A serializable list of objects for the text track list\n */\n toJSON() {\n return this.tracks_.map(track => track.toJSON());\n }\n }\n\n /**\n * @file html-track-element-list.js\n */\n\n /**\n * The current list of {@link HtmlTrackElement}s.\n */\n class HtmlTrackElementList {\n /**\n * Create an instance of this class.\n *\n * @param {HtmlTrackElement[]} [tracks=[]]\n * A list of `HtmlTrackElement` to instantiate the list with.\n */\n constructor(trackElements = []) {\n this.trackElements_ = [];\n\n /**\n * @memberof HtmlTrackElementList\n * @member {number} length\n * The current number of `Track`s in the this Trackist.\n * @instance\n */\n Object.defineProperty(this, 'length', {\n get() {\n return this.trackElements_.length;\n }\n });\n for (let i = 0, length = trackElements.length; i < length; i++) {\n this.addTrackElement_(trackElements[i]);\n }\n }\n\n /**\n * Add an {@link HtmlTrackElement} to the `HtmlTrackElementList`\n *\n * @param {HtmlTrackElement} trackElement\n * The track element to add to the list.\n *\n * @private\n */\n addTrackElement_(trackElement) {\n const index = this.trackElements_.length;\n if (!('' + index in this)) {\n Object.defineProperty(this, index, {\n get() {\n return this.trackElements_[index];\n }\n });\n }\n\n // Do not add duplicate elements\n if (this.trackElements_.indexOf(trackElement) === -1) {\n this.trackElements_.push(trackElement);\n }\n }\n\n /**\n * Get an {@link HtmlTrackElement} from the `HtmlTrackElementList` given an\n * {@link TextTrack}.\n *\n * @param {TextTrack} track\n * The track associated with a track element.\n *\n * @return {HtmlTrackElement|undefined}\n * The track element that was found or undefined.\n *\n * @private\n */\n getTrackElementByTrack_(track) {\n let trackElement_;\n for (let i = 0, length = this.trackElements_.length; i < length; i++) {\n if (track === this.trackElements_[i].track) {\n trackElement_ = this.trackElements_[i];\n break;\n }\n }\n return trackElement_;\n }\n\n /**\n * Remove a {@link HtmlTrackElement} from the `HtmlTrackElementList`\n *\n * @param {HtmlTrackElement} trackElement\n * The track element to remove from the list.\n *\n * @private\n */\n removeTrackElement_(trackElement) {\n for (let i = 0, length = this.trackElements_.length; i < length; i++) {\n if (trackElement === this.trackElements_[i]) {\n if (this.trackElements_[i].track && typeof this.trackElements_[i].track.off === 'function') {\n this.trackElements_[i].track.off();\n }\n if (typeof this.trackElements_[i].off === 'function') {\n this.trackElements_[i].off();\n }\n this.trackElements_.splice(i, 1);\n break;\n }\n }\n }\n }\n\n /**\n * @file text-track-cue-list.js\n */\n\n /**\n * @typedef {Object} TextTrackCueList~TextTrackCue\n *\n * @property {string} id\n * The unique id for this text track cue\n *\n * @property {number} startTime\n * The start time for this text track cue\n *\n * @property {number} endTime\n * The end time for this text track cue\n *\n * @property {boolean} pauseOnExit\n * Pause when the end time is reached if true.\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcue}\n */\n\n /**\n * A List of TextTrackCues.\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist}\n */\n class TextTrackCueList {\n /**\n * Create an instance of this class..\n *\n * @param {Array} cues\n * A list of cues to be initialized with\n */\n constructor(cues) {\n TextTrackCueList.prototype.setCues_.call(this, cues);\n\n /**\n * @memberof TextTrackCueList\n * @member {number} length\n * The current number of `TextTrackCue`s in the TextTrackCueList.\n * @instance\n */\n Object.defineProperty(this, 'length', {\n get() {\n return this.length_;\n }\n });\n }\n\n /**\n * A setter for cues in this list. Creates getters\n * an an index for the cues.\n *\n * @param {Array} cues\n * An array of cues to set\n *\n * @private\n */\n setCues_(cues) {\n const oldLength = this.length || 0;\n let i = 0;\n const l = cues.length;\n this.cues_ = cues;\n this.length_ = cues.length;\n const defineProp = function (index) {\n if (!('' + index in this)) {\n Object.defineProperty(this, '' + index, {\n get() {\n return this.cues_[index];\n }\n });\n }\n };\n if (oldLength < l) {\n i = oldLength;\n for (; i < l; i++) {\n defineProp.call(this, i);\n }\n }\n }\n\n /**\n * Get a `TextTrackCue` that is currently in the `TextTrackCueList` by id.\n *\n * @param {string} id\n * The id of the cue that should be searched for.\n *\n * @return {TextTrackCueList~TextTrackCue|null}\n * A single cue or null if none was found.\n */\n getCueById(id) {\n let result = null;\n for (let i = 0, l = this.length; i < l; i++) {\n const cue = this[i];\n if (cue.id === id) {\n result = cue;\n break;\n }\n }\n return result;\n }\n }\n\n /**\n * @file track-kinds.js\n */\n\n /**\n * All possible `VideoTrackKind`s\n *\n * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-videotrack-kind\n * @typedef VideoTrack~Kind\n * @enum\n */\n const VideoTrackKind = {\n alternative: 'alternative',\n captions: 'captions',\n main: 'main',\n sign: 'sign',\n subtitles: 'subtitles',\n commentary: 'commentary'\n };\n\n /**\n * All possible `AudioTrackKind`s\n *\n * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-audiotrack-kind\n * @typedef AudioTrack~Kind\n * @enum\n */\n const AudioTrackKind = {\n 'alternative': 'alternative',\n 'descriptions': 'descriptions',\n 'main': 'main',\n 'main-desc': 'main-desc',\n 'translation': 'translation',\n 'commentary': 'commentary'\n };\n\n /**\n * All possible `TextTrackKind`s\n *\n * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-texttrack-kind\n * @typedef TextTrack~Kind\n * @enum\n */\n const TextTrackKind = {\n subtitles: 'subtitles',\n captions: 'captions',\n descriptions: 'descriptions',\n chapters: 'chapters',\n metadata: 'metadata'\n };\n\n /**\n * All possible `TextTrackMode`s\n *\n * @see https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode\n * @typedef TextTrack~Mode\n * @enum\n */\n const TextTrackMode = {\n disabled: 'disabled',\n hidden: 'hidden',\n showing: 'showing'\n };\n\n /**\n * @file track.js\n */\n\n /**\n * A Track class that contains all of the common functionality for {@link AudioTrack},\n * {@link VideoTrack}, and {@link TextTrack}.\n *\n * > Note: This class should not be used directly\n *\n * @see {@link https://html.spec.whatwg.org/multipage/embedded-content.html}\n * @extends EventTarget\n * @abstract\n */\n class Track extends EventTarget {\n /**\n * Create an instance of this class.\n *\n * @param {Object} [options={}]\n * Object of option names and values\n *\n * @param {string} [options.kind='']\n * A valid kind for the track type you are creating.\n *\n * @param {string} [options.id='vjs_track_' + Guid.newGUID()]\n * A unique id for this AudioTrack.\n *\n * @param {string} [options.label='']\n * The menu label for this track.\n *\n * @param {string} [options.language='']\n * A valid two character language code.\n *\n * @abstract\n */\n constructor(options = {}) {\n super();\n const trackProps = {\n id: options.id || 'vjs_track_' + newGUID(),\n kind: options.kind || '',\n language: options.language || ''\n };\n let label = options.label || '';\n\n /**\n * @memberof Track\n * @member {string} id\n * The id of this track. Cannot be changed after creation.\n * @instance\n *\n * @readonly\n */\n\n /**\n * @memberof Track\n * @member {string} kind\n * The kind of track that this is. Cannot be changed after creation.\n * @instance\n *\n * @readonly\n */\n\n /**\n * @memberof Track\n * @member {string} language\n * The two letter language code for this track. Cannot be changed after\n * creation.\n * @instance\n *\n * @readonly\n */\n\n for (const key in trackProps) {\n Object.defineProperty(this, key, {\n get() {\n return trackProps[key];\n },\n set() {}\n });\n }\n\n /**\n * @memberof Track\n * @member {string} label\n * The label of this track. Cannot be changed after creation.\n * @instance\n *\n * @fires Track#labelchange\n */\n Object.defineProperty(this, 'label', {\n get() {\n return label;\n },\n set(newLabel) {\n if (newLabel !== label) {\n label = newLabel;\n\n /**\n * An event that fires when label changes on this track.\n *\n * > Note: This is not part of the spec!\n *\n * @event Track#labelchange\n * @type {Event}\n */\n this.trigger('labelchange');\n }\n }\n });\n }\n }\n\n /**\n * @file url.js\n * @module url\n */\n\n /**\n * Resolve and parse the elements of a URL.\n *\n * @function\n * @param {string} url\n * The url to parse\n *\n * @return {URL}\n * An object of url details\n */\n const parseUrl = function (url) {\n return new URL(url, document.baseURI);\n };\n\n /**\n * Get absolute version of relative URL.\n *\n * @function\n * @param {string} url\n * URL to make absolute\n *\n * @return {string}\n * Absolute URL\n */\n const getAbsoluteURL = function (url) {\n return new URL(url, document.baseURI).href;\n };\n\n /**\n * Returns the extension of the passed file name. It will return an empty string\n * if passed an invalid path.\n *\n * @function\n * @param {string} path\n * The fileName path like '/path/to/file.mp4'\n *\n * @return {string}\n * The extension in lower case or an empty string if no\n * extension could be found.\n */\n const getFileExtension = function (path) {\n if (typeof path === 'string') {\n const cleanPath = path.split('?')[0].replace(/\\/+$/, '');\n const match = cleanPath.match(/\\.([^.\\/]+)$/);\n return match ? match[1].toLowerCase() : '';\n }\n return '';\n };\n\n /**\n * Returns whether the url passed is a cross domain request or not.\n *\n * @function\n * @param {string} url\n * The url to check.\n *\n * @param {URL} [winLoc]\n * the domain to check the url against, defaults to window.location\n *\n * @return {boolean}\n * Whether it is a cross domain request or not.\n */\n const isCrossOrigin = function (url, winLoc = window.location) {\n return parseUrl(url).origin !== winLoc.origin;\n };\n\n var Url = /*#__PURE__*/Object.freeze({\n __proto__: null,\n parseUrl: parseUrl,\n getAbsoluteURL: getAbsoluteURL,\n getFileExtension: getFileExtension,\n isCrossOrigin: isCrossOrigin\n });\n\n var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof __webpack_require__.g !== 'undefined' ? __webpack_require__.g : typeof self !== 'undefined' ? self : {};\n\n function unwrapExports (x) {\n \treturn x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;\n }\n\n function createCommonjsModule(fn, module) {\n \treturn module = { exports: {} }, fn(module, module.exports), module.exports;\n }\n\n var win;\n if (typeof window !== \"undefined\") {\n win = window;\n } else if (typeof commonjsGlobal !== \"undefined\") {\n win = commonjsGlobal;\n } else if (typeof self !== \"undefined\") {\n win = self;\n } else {\n win = {};\n }\n var window_1 = win;\n\n var _extends_1 = createCommonjsModule(function (module) {\n function _extends() {\n return (module.exports = _extends = Object.assign ? Object.assign.bind() : function (n) {\n for (var e = 1; e < arguments.length; e++) {\n var t = arguments[e];\n for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);\n }\n return n;\n }, module.exports.__esModule = true, module.exports[\"default\"] = module.exports), _extends.apply(null, arguments);\n }\n module.exports = _extends, module.exports.__esModule = true, module.exports[\"default\"] = module.exports;\n });\n unwrapExports(_extends_1);\n\n var isFunction_1 = isFunction;\n var toString = Object.prototype.toString;\n function isFunction(fn) {\n if (!fn) {\n return false;\n }\n var string = toString.call(fn);\n return string === '[object Function]' || typeof fn === 'function' && string !== '[object RegExp]' || typeof window !== 'undefined' && (\n // IE8 and below\n fn === window.setTimeout || fn === window.alert || fn === window.confirm || fn === window.prompt);\n }\n\n function _createForOfIteratorHelperLoose(o, allowArrayLike) {\n var it = typeof Symbol !== \"undefined\" && o[Symbol.iterator] || o[\"@@iterator\"];\n if (it) return (it = it.call(o)).next.bind(it);\n if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === \"number\") {\n if (it) o = it;\n var i = 0;\n return function () {\n if (i >= o.length) return {\n done: true\n };\n return {\n done: false,\n value: o[i++]\n };\n };\n }\n throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n }\n function _unsupportedIterableToArray(o, minLen) {\n if (!o) return;\n if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n var n = Object.prototype.toString.call(o).slice(8, -1);\n if (n === \"Object\" && o.constructor) n = o.constructor.name;\n if (n === \"Map\" || n === \"Set\") return Array.from(o);\n if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n }\n function _arrayLikeToArray(arr, len) {\n if (len == null || len > arr.length) len = arr.length;\n for (var i = 0, arr2 = new Array(len); i < len; i++) {\n arr2[i] = arr[i];\n }\n return arr2;\n }\n var InterceptorsStorage = /*#__PURE__*/function () {\n function InterceptorsStorage() {\n this.typeToInterceptorsMap_ = new Map();\n this.enabled_ = false;\n }\n var _proto = InterceptorsStorage.prototype;\n _proto.getIsEnabled = function getIsEnabled() {\n return this.enabled_;\n };\n _proto.enable = function enable() {\n this.enabled_ = true;\n };\n _proto.disable = function disable() {\n this.enabled_ = false;\n };\n _proto.reset = function reset() {\n this.typeToInterceptorsMap_ = new Map();\n this.enabled_ = false;\n };\n _proto.addInterceptor = function addInterceptor(type, interceptor) {\n if (!this.typeToInterceptorsMap_.has(type)) {\n this.typeToInterceptorsMap_.set(type, new Set());\n }\n var interceptorsSet = this.typeToInterceptorsMap_.get(type);\n if (interceptorsSet.has(interceptor)) {\n // already have this interceptor\n return false;\n }\n interceptorsSet.add(interceptor);\n return true;\n };\n _proto.removeInterceptor = function removeInterceptor(type, interceptor) {\n var interceptorsSet = this.typeToInterceptorsMap_.get(type);\n if (interceptorsSet && interceptorsSet.has(interceptor)) {\n interceptorsSet.delete(interceptor);\n return true;\n }\n return false;\n };\n _proto.clearInterceptorsByType = function clearInterceptorsByType(type) {\n var interceptorsSet = this.typeToInterceptorsMap_.get(type);\n if (!interceptorsSet) {\n return false;\n }\n this.typeToInterceptorsMap_.delete(type);\n this.typeToInterceptorsMap_.set(type, new Set());\n return true;\n };\n _proto.clear = function clear() {\n if (!this.typeToInterceptorsMap_.size) {\n return false;\n }\n this.typeToInterceptorsMap_ = new Map();\n return true;\n };\n _proto.getForType = function getForType(type) {\n return this.typeToInterceptorsMap_.get(type) || new Set();\n };\n _proto.execute = function execute(type, payload) {\n var interceptors = this.getForType(type);\n for (var _iterator = _createForOfIteratorHelperLoose(interceptors), _step; !(_step = _iterator()).done;) {\n var interceptor = _step.value;\n try {\n payload = interceptor(payload);\n } catch (e) {//ignore\n }\n }\n return payload;\n };\n return InterceptorsStorage;\n }();\n var interceptors = InterceptorsStorage;\n\n var RetryManager = /*#__PURE__*/function () {\n function RetryManager() {\n this.maxAttempts_ = 1;\n this.delayFactor_ = 0.1;\n this.fuzzFactor_ = 0.1;\n this.initialDelay_ = 1000;\n this.enabled_ = false;\n }\n var _proto = RetryManager.prototype;\n _proto.getIsEnabled = function getIsEnabled() {\n return this.enabled_;\n };\n _proto.enable = function enable() {\n this.enabled_ = true;\n };\n _proto.disable = function disable() {\n this.enabled_ = false;\n };\n _proto.reset = function reset() {\n this.maxAttempts_ = 1;\n this.delayFactor_ = 0.1;\n this.fuzzFactor_ = 0.1;\n this.initialDelay_ = 1000;\n this.enabled_ = false;\n };\n _proto.getMaxAttempts = function getMaxAttempts() {\n return this.maxAttempts_;\n };\n _proto.setMaxAttempts = function setMaxAttempts(maxAttempts) {\n this.maxAttempts_ = maxAttempts;\n };\n _proto.getDelayFactor = function getDelayFactor() {\n return this.delayFactor_;\n };\n _proto.setDelayFactor = function setDelayFactor(delayFactor) {\n this.delayFactor_ = delayFactor;\n };\n _proto.getFuzzFactor = function getFuzzFactor() {\n return this.fuzzFactor_;\n };\n _proto.setFuzzFactor = function setFuzzFactor(fuzzFactor) {\n this.fuzzFactor_ = fuzzFactor;\n };\n _proto.getInitialDelay = function getInitialDelay() {\n return this.initialDelay_;\n };\n _proto.setInitialDelay = function setInitialDelay(initialDelay) {\n this.initialDelay_ = initialDelay;\n };\n _proto.createRetry = function createRetry(_temp) {\n var _ref = _temp === void 0 ? {} : _temp,\n maxAttempts = _ref.maxAttempts,\n delayFactor = _ref.delayFactor,\n fuzzFactor = _ref.fuzzFactor,\n initialDelay = _ref.initialDelay;\n return new Retry({\n maxAttempts: maxAttempts || this.maxAttempts_,\n delayFactor: delayFactor || this.delayFactor_,\n fuzzFactor: fuzzFactor || this.fuzzFactor_,\n initialDelay: initialDelay || this.initialDelay_\n });\n };\n return RetryManager;\n }();\n var Retry = /*#__PURE__*/function () {\n function Retry(options) {\n this.maxAttempts_ = options.maxAttempts;\n this.delayFactor_ = options.delayFactor;\n this.fuzzFactor_ = options.fuzzFactor;\n this.currentDelay_ = options.initialDelay;\n this.currentAttempt_ = 1;\n }\n var _proto2 = Retry.prototype;\n _proto2.moveToNextAttempt = function moveToNextAttempt() {\n this.currentAttempt_++;\n var delayDelta = this.currentDelay_ * this.delayFactor_;\n this.currentDelay_ = this.currentDelay_ + delayDelta;\n };\n _proto2.shouldRetry = function shouldRetry() {\n return this.currentAttempt_ < this.maxAttempts_;\n };\n _proto2.getCurrentDelay = function getCurrentDelay() {\n return this.currentDelay_;\n };\n _proto2.getCurrentMinPossibleDelay = function getCurrentMinPossibleDelay() {\n return (1 - this.fuzzFactor_) * this.currentDelay_;\n };\n _proto2.getCurrentMaxPossibleDelay = function getCurrentMaxPossibleDelay() {\n return (1 + this.fuzzFactor_) * this.currentDelay_;\n }\n /**\n * For example fuzzFactor is 0.1\n * This means ±10% deviation\n * So if we have delay as 1000\n * This function can generate any value from 900 to 1100\n */;\n _proto2.getCurrentFuzzedDelay = function getCurrentFuzzedDelay() {\n var lowValue = this.getCurrentMinPossibleDelay();\n var highValue = this.getCurrentMaxPossibleDelay();\n return lowValue + Math.random() * (highValue - lowValue);\n };\n return Retry;\n }();\n var retry = RetryManager;\n\n var httpResponseHandler = function httpResponseHandler(callback, decodeResponseBody) {\n if (decodeResponseBody === void 0) {\n decodeResponseBody = false;\n }\n return function (err, response, responseBody) {\n // if the XHR failed, return that error\n if (err) {\n callback(err);\n return;\n } // if the HTTP status code is 4xx or 5xx, the request also failed\n\n if (response.statusCode >= 400 && response.statusCode <= 599) {\n var cause = responseBody;\n if (decodeResponseBody) {\n if (window_1.TextDecoder) {\n var charset = getCharset(response.headers && response.headers['content-type']);\n try {\n cause = new TextDecoder(charset).decode(responseBody);\n } catch (e) {}\n } else {\n cause = String.fromCharCode.apply(null, new Uint8Array(responseBody));\n }\n }\n callback({\n cause: cause\n });\n return;\n } // otherwise, request succeeded\n\n callback(null, responseBody);\n };\n };\n function getCharset(contentTypeHeader) {\n if (contentTypeHeader === void 0) {\n contentTypeHeader = '';\n }\n return contentTypeHeader.toLowerCase().split(';').reduce(function (charset, contentType) {\n var _contentType$split = contentType.split('='),\n type = _contentType$split[0],\n value = _contentType$split[1];\n if (type.trim() === 'charset') {\n return value.trim();\n }\n return charset;\n }, 'utf-8');\n }\n var httpHandler = httpResponseHandler;\n\n createXHR.httpHandler = httpHandler;\n createXHR.requestInterceptorsStorage = new interceptors();\n createXHR.responseInterceptorsStorage = new interceptors();\n createXHR.retryManager = new retry();\n /**\n * @license\n * slighly modified parse-headers 2.0.2 <https://github.com/kesla/parse-headers/>\n * Copyright (c) 2014 David Björklund\n * Available under the MIT license\n * <https://github.com/kesla/parse-headers/blob/master/LICENCE>\n */\n\n var parseHeaders = function parseHeaders(headers) {\n var result = {};\n if (!headers) {\n return result;\n }\n headers.trim().split('\\n').forEach(function (row) {\n var index = row.indexOf(':');\n var key = row.slice(0, index).trim().toLowerCase();\n var value = row.slice(index + 1).trim();\n if (typeof result[key] === 'undefined') {\n result[key] = value;\n } else if (Array.isArray(result[key])) {\n result[key].push(value);\n } else {\n result[key] = [result[key], value];\n }\n });\n return result;\n };\n var lib = createXHR; // Allow use of default import syntax in TypeScript\n\n var default_1 = createXHR;\n createXHR.XMLHttpRequest = window_1.XMLHttpRequest || noop;\n createXHR.XDomainRequest = \"withCredentials\" in new createXHR.XMLHttpRequest() ? createXHR.XMLHttpRequest : window_1.XDomainRequest;\n forEachArray([\"get\", \"put\", \"post\", \"patch\", \"head\", \"delete\"], function (method) {\n createXHR[method === \"delete\" ? \"del\" : method] = function (uri, options, callback) {\n options = initParams(uri, options, callback);\n options.method = method.toUpperCase();\n return _createXHR(options);\n };\n });\n function forEachArray(array, iterator) {\n for (var i = 0; i < array.length; i++) {\n iterator(array[i]);\n }\n }\n function isEmpty(obj) {\n for (var i in obj) {\n if (obj.hasOwnProperty(i)) return false;\n }\n return true;\n }\n function initParams(uri, options, callback) {\n var params = uri;\n if (isFunction_1(options)) {\n callback = options;\n if (typeof uri === \"string\") {\n params = {\n uri: uri\n };\n }\n } else {\n params = _extends_1({}, options, {\n uri: uri\n });\n }\n params.callback = callback;\n return params;\n }\n function createXHR(uri, options, callback) {\n options = initParams(uri, options, callback);\n return _createXHR(options);\n }\n function _createXHR(options) {\n if (typeof options.callback === \"undefined\") {\n throw new Error(\"callback argument missing\");\n } // call all registered request interceptors for a given request type:\n\n if (options.requestType && createXHR.requestInterceptorsStorage.getIsEnabled()) {\n var requestInterceptorPayload = {\n uri: options.uri || options.url,\n headers: options.headers || {},\n body: options.body,\n metadata: options.metadata || {},\n retry: options.retry,\n timeout: options.timeout\n };\n var updatedPayload = createXHR.requestInterceptorsStorage.execute(options.requestType, requestInterceptorPayload);\n options.uri = updatedPayload.uri;\n options.headers = updatedPayload.headers;\n options.body = updatedPayload.body;\n options.metadata = updatedPayload.metadata;\n options.retry = updatedPayload.retry;\n options.timeout = updatedPayload.timeout;\n }\n var called = false;\n var callback = function cbOnce(err, response, body) {\n if (!called) {\n called = true;\n options.callback(err, response, body);\n }\n };\n function readystatechange() {\n // do not call load 2 times when response interceptors are enabled\n // why do we even need this 2nd load?\n if (xhr.readyState === 4 && !createXHR.responseInterceptorsStorage.getIsEnabled()) {\n setTimeout(loadFunc, 0);\n }\n }\n function getBody() {\n // Chrome with requestType=blob throws errors arround when even testing access to responseText\n var body = undefined;\n if (xhr.response) {\n body = xhr.response;\n } else {\n body = xhr.responseText || getXml(xhr);\n }\n if (isJson) {\n try {\n body = JSON.parse(body);\n } catch (e) {}\n }\n return body;\n }\n function errorFunc(evt) {\n clearTimeout(timeoutTimer);\n clearTimeout(options.retryTimeout);\n if (!(evt instanceof Error)) {\n evt = new Error(\"\" + (evt || \"Unknown XMLHttpRequest Error\"));\n }\n evt.statusCode = 0; // we would like to retry on error:\n\n if (!aborted && createXHR.retryManager.getIsEnabled() && options.retry && options.retry.shouldRetry()) {\n options.retryTimeout = setTimeout(function () {\n options.retry.moveToNextAttempt(); // we want to re-use the same options and the same xhr object:\n\n options.xhr = xhr;\n _createXHR(options);\n }, options.retry.getCurrentFuzzedDelay());\n return;\n } // call all registered response interceptors for a given request type:\n\n if (options.requestType && createXHR.responseInterceptorsStorage.getIsEnabled()) {\n var responseInterceptorPayload = {\n headers: failureResponse.headers || {},\n body: failureResponse.body,\n responseUrl: xhr.responseURL,\n responseType: xhr.responseType\n };\n var _updatedPayload = createXHR.responseInterceptorsStorage.execute(options.requestType, responseInterceptorPayload);\n failureResponse.body = _updatedPayload.body;\n failureResponse.headers = _updatedPayload.headers;\n }\n return callback(evt, failureResponse);\n } // will load the data & process the response in a special response object\n\n function loadFunc() {\n if (aborted) return;\n var status;\n clearTimeout(timeoutTimer);\n clearTimeout(options.retryTimeout);\n if (options.useXDR && xhr.status === undefined) {\n //IE8 CORS GET successful response doesn't have a status field, but body is fine\n status = 200;\n } else {\n status = xhr.status === 1223 ? 204 : xhr.status;\n }\n var response = failureResponse;\n var err = null;\n if (status !== 0) {\n response = {\n body: getBody(),\n statusCode: status,\n method: method,\n headers: {},\n url: uri,\n rawRequest: xhr\n };\n if (xhr.getAllResponseHeaders) {\n //remember xhr can in fact be XDR for CORS in IE\n response.headers = parseHeaders(xhr.getAllResponseHeaders());\n }\n } else {\n err = new Error(\"Internal XMLHttpRequest Error\");\n } // call all registered response interceptors for a given request type:\n\n if (options.requestType && createXHR.responseInterceptorsStorage.getIsEnabled()) {\n var responseInterceptorPayload = {\n headers: response.headers || {},\n body: response.body,\n responseUrl: xhr.responseURL,\n responseType: xhr.responseType\n };\n var _updatedPayload2 = createXHR.responseInterceptorsStorage.execute(options.requestType, responseInterceptorPayload);\n response.body = _updatedPayload2.body;\n response.headers = _updatedPayload2.headers;\n }\n return callback(err, response, response.body);\n }\n var xhr = options.xhr || null;\n if (!xhr) {\n if (options.cors || options.useXDR) {\n xhr = new createXHR.XDomainRequest();\n } else {\n xhr = new createXHR.XMLHttpRequest();\n }\n }\n var key;\n var aborted;\n var uri = xhr.url = options.uri || options.url;\n var method = xhr.method = options.method || \"GET\";\n var body = options.body || options.data;\n var headers = xhr.headers = options.headers || {};\n var sync = !!options.sync;\n var isJson = false;\n var timeoutTimer;\n var failureResponse = {\n body: undefined,\n headers: {},\n statusCode: 0,\n method: method,\n url: uri,\n rawRequest: xhr\n };\n if (\"json\" in options && options.json !== false) {\n isJson = true;\n headers[\"accept\"] || headers[\"Accept\"] || (headers[\"Accept\"] = \"application/json\"); //Don't override existing accept header declared by user\n\n if (method !== \"GET\" && method !== \"HEAD\") {\n headers[\"content-type\"] || headers[\"Content-Type\"] || (headers[\"Content-Type\"] = \"application/json\"); //Don't override existing accept header declared by user\n\n body = JSON.stringify(options.json === true ? body : options.json);\n }\n }\n xhr.onreadystatechange = readystatechange;\n xhr.onload = loadFunc;\n xhr.onerror = errorFunc; // IE9 must have onprogress be set to a unique function.\n\n xhr.onprogress = function () {// IE must die\n };\n xhr.onabort = function () {\n aborted = true;\n clearTimeout(options.retryTimeout);\n };\n xhr.ontimeout = errorFunc;\n xhr.open(method, uri, !sync, options.username, options.password); //has to be after open\n\n if (!sync) {\n xhr.withCredentials = !!options.withCredentials;\n } // Cannot set timeout with sync request\n // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly\n // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent\n\n if (!sync && options.timeout > 0) {\n timeoutTimer = setTimeout(function () {\n if (aborted) return;\n aborted = true; //IE9 may still call readystatechange\n\n xhr.abort(\"timeout\");\n var e = new Error(\"XMLHttpRequest timeout\");\n e.code = \"ETIMEDOUT\";\n errorFunc(e);\n }, options.timeout);\n }\n if (xhr.setRequestHeader) {\n for (key in headers) {\n if (headers.hasOwnProperty(key)) {\n xhr.setRequestHeader(key, headers[key]);\n }\n }\n } else if (options.headers && !isEmpty(options.headers)) {\n throw new Error(\"Headers cannot be set on an XDomainRequest object\");\n }\n if (\"responseType\" in options) {\n xhr.responseType = options.responseType;\n }\n if (\"beforeSend\" in options && typeof options.beforeSend === \"function\") {\n options.beforeSend(xhr);\n } // Microsoft Edge browser sends \"undefined\" when send is called with undefined value.\n // XMLHttpRequest spec says to pass null as body to indicate no body\n // See https://github.com/naugtur/xhr/issues/100.\n\n xhr.send(body || null);\n return xhr;\n }\n function getXml(xhr) {\n // xhr.responseXML will throw Exception \"InvalidStateError\" or \"DOMException\"\n // See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseXML.\n try {\n if (xhr.responseType === \"document\") {\n return xhr.responseXML;\n }\n var firefoxBugTakenEffect = xhr.responseXML && xhr.responseXML.documentElement.nodeName === \"parsererror\";\n if (xhr.responseType === \"\" && !firefoxBugTakenEffect) {\n return xhr.responseXML;\n }\n } catch (e) {}\n return null;\n }\n function noop() {}\n lib.default = default_1;\n\n /**\n * @file text-track.js\n */\n\n /** @import Tech from '../tech/tech' */\n\n /**\n * Takes a webvtt file contents and parses it into cues\n *\n * @param {string} srcContent\n * webVTT file contents\n *\n * @param {TextTrack} track\n * TextTrack to add cues to. Cues come from the srcContent.\n *\n * @private\n */\n const parseCues = function (srcContent, track) {\n const parser = new window.WebVTT.Parser(window, window.vttjs, window.WebVTT.StringDecoder());\n const errors = [];\n parser.oncue = function (cue) {\n track.addCue(cue);\n };\n parser.onparsingerror = function (error) {\n errors.push(error);\n };\n parser.onflush = function () {\n track.trigger({\n type: 'loadeddata',\n target: track\n });\n };\n parser.parse(srcContent);\n if (errors.length > 0) {\n if (window.console && window.console.groupCollapsed) {\n window.console.groupCollapsed(`Text Track parsing errors for ${track.src}`);\n }\n errors.forEach(error => log.error(error));\n if (window.console && window.console.groupEnd) {\n window.console.groupEnd();\n }\n }\n parser.flush();\n };\n\n /**\n * Load a `TextTrack` from a specified url.\n *\n * @param {string} src\n * Url to load track from.\n *\n * @param {TextTrack} track\n * Track to add cues to. Comes from the content at the end of `url`.\n *\n * @private\n */\n const loadTrack = function (src, track) {\n const opts = {\n uri: src\n };\n const crossOrigin = isCrossOrigin(src);\n if (crossOrigin) {\n opts.cors = crossOrigin;\n }\n const withCredentials = track.tech_.crossOrigin() === 'use-credentials';\n if (withCredentials) {\n opts.withCredentials = withCredentials;\n }\n lib(opts, bind_(this, function (err, response, responseBody) {\n if (err) {\n return log.error(err, response);\n }\n track.loaded_ = true;\n\n // Make sure that vttjs has loaded, otherwise, wait till it finished loading\n // NOTE: this is only used for the alt/video.novtt.js build\n if (typeof window.WebVTT !== 'function') {\n if (track.tech_) {\n // to prevent use before define eslint error, we define loadHandler\n // as a let here\n track.tech_.any(['vttjsloaded', 'vttjserror'], event => {\n if (event.type === 'vttjserror') {\n log.error(`vttjs failed to load, stopping trying to process ${track.src}`);\n return;\n }\n return parseCues(responseBody, track);\n });\n }\n } else {\n parseCues(responseBody, track);\n }\n }));\n };\n\n /**\n * A representation of a single `TextTrack`.\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack}\n * @extends Track\n */\n class TextTrack extends Track {\n /**\n * Create an instance of this class.\n *\n * @param {Object} options={}\n * Object of option names and values\n *\n * @param {Tech} options.tech\n * A reference to the tech that owns this TextTrack.\n *\n * @param {TextTrack~Kind} [options.kind='subtitles']\n * A valid text track kind.\n *\n * @param {TextTrack~Mode} [options.mode='disabled']\n * A valid text track mode.\n *\n * @param {string} [options.id='vjs_track_' + Guid.newGUID()]\n * A unique id for this TextTrack.\n *\n * @param {string} [options.label='']\n * The menu label for this track.\n *\n * @param {string} [options.language='']\n * A valid two character language code.\n *\n * @param {string} [options.srclang='']\n * A valid two character language code. An alternative, but deprioritized\n * version of `options.language`\n *\n * @param {string} [options.src]\n * A url to TextTrack cues.\n *\n * @param {boolean} [options.default]\n * If this track should default to on or off.\n */\n constructor(options = {}) {\n if (!options.tech) {\n throw new Error('A tech was not provided.');\n }\n const settings = merge(options, {\n kind: TextTrackKind[options.kind] || 'subtitles',\n language: options.language || options.srclang || ''\n });\n let mode = TextTrackMode[settings.mode] || 'disabled';\n const default_ = settings.default;\n if (settings.kind === 'metadata' || settings.kind === 'chapters') {\n mode = 'hidden';\n }\n super(settings);\n this.tech_ = settings.tech;\n this.cues_ = [];\n this.activeCues_ = [];\n this.preload_ = this.tech_.preloadTextTracks !== false;\n const cues = new TextTrackCueList(this.cues_);\n const activeCues = new TextTrackCueList(this.activeCues_);\n let changed = false;\n this.timeupdateHandler = bind_(this, function (event = {}) {\n if (this.tech_.isDisposed()) {\n return;\n }\n if (!this.tech_.isReady_) {\n if (event.type !== 'timeupdate') {\n this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler);\n }\n return;\n }\n\n // Accessing this.activeCues for the side-effects of updating itself\n // due to its nature as a getter function. Do not remove or cues will\n // stop updating!\n // Use the setter to prevent deletion from uglify (pure_getters rule)\n this.activeCues = this.activeCues;\n if (changed) {\n this.trigger('cuechange');\n changed = false;\n }\n if (event.type !== 'timeupdate') {\n this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler);\n }\n });\n const disposeHandler = () => {\n this.stopTracking();\n };\n this.tech_.one('dispose', disposeHandler);\n if (mode !== 'disabled') {\n this.startTracking();\n }\n Object.defineProperties(this, {\n /**\n * @memberof TextTrack\n * @member {boolean} default\n * If this track was set to be on or off by default. Cannot be changed after\n * creation.\n * @instance\n *\n * @readonly\n */\n default: {\n get() {\n return default_;\n },\n set() {}\n },\n /**\n * @memberof TextTrack\n * @member {string} mode\n * Set the mode of this TextTrack to a valid {@link TextTrack~Mode}. Will\n * not be set if setting to an invalid mode.\n * @instance\n *\n * @fires TextTrack#modechange\n */\n mode: {\n get() {\n return mode;\n },\n set(newMode) {\n if (!TextTrackMode[newMode]) {\n return;\n }\n if (mode === newMode) {\n return;\n }\n mode = newMode;\n if (!this.preload_ && mode !== 'disabled' && this.cues.length === 0) {\n // On-demand load.\n loadTrack(this.src, this);\n }\n this.stopTracking();\n if (mode !== 'disabled') {\n this.startTracking();\n }\n /**\n * An event that fires when mode changes on this track. This allows\n * the TextTrackList that holds this track to act accordingly.\n *\n * > Note: This is not part of the spec!\n *\n * @event TextTrack#modechange\n * @type {Event}\n */\n this.trigger('modechange');\n }\n },\n /**\n * @memberof TextTrack\n * @member {TextTrackCueList} cues\n * The text track cue list for this TextTrack.\n * @instance\n */\n cues: {\n get() {\n if (!this.loaded_) {\n return null;\n }\n return cues;\n },\n set() {}\n },\n /**\n * @memberof TextTrack\n * @member {TextTrackCueList} activeCues\n * The list text track cues that are currently active for this TextTrack.\n * @instance\n */\n activeCues: {\n get() {\n if (!this.loaded_) {\n return null;\n }\n\n // nothing to do\n if (this.cues.length === 0) {\n return activeCues;\n }\n const ct = this.tech_.currentTime();\n const active = [];\n for (let i = 0, l = this.cues.length; i < l; i++) {\n const cue = this.cues[i];\n if (cue.startTime <= ct && cue.endTime >= ct) {\n active.push(cue);\n }\n }\n changed = false;\n if (active.length !== this.activeCues_.length) {\n changed = true;\n } else {\n for (let i = 0; i < active.length; i++) {\n if (this.activeCues_.indexOf(active[i]) === -1) {\n changed = true;\n }\n }\n }\n this.activeCues_ = active;\n activeCues.setCues_(this.activeCues_);\n return activeCues;\n },\n // /!\\ Keep this setter empty (see the timeupdate handler above)\n set() {}\n }\n });\n if (settings.src) {\n this.src = settings.src;\n if (!this.preload_) {\n // Tracks will load on-demand.\n // Act like we're loaded for other purposes.\n this.loaded_ = true;\n }\n if (this.preload_ || settings.kind !== 'subtitles' && settings.kind !== 'captions') {\n loadTrack(this.src, this);\n }\n } else {\n this.loaded_ = true;\n }\n }\n startTracking() {\n // More precise cues based on requestVideoFrameCallback with a requestAnimationFram fallback\n this.rvf_ = this.tech_.requestVideoFrameCallback(this.timeupdateHandler);\n // Also listen to timeupdate in case rVFC/rAF stops (window in background, audio in video el)\n this.tech_.on('timeupdate', this.timeupdateHandler);\n }\n stopTracking() {\n if (this.rvf_) {\n this.tech_.cancelVideoFrameCallback(this.rvf_);\n this.rvf_ = undefined;\n }\n this.tech_.off('timeupdate', this.timeupdateHandler);\n }\n\n /**\n * Add a cue to the internal list of cues.\n *\n * @param {TextTrack~Cue} cue\n * The cue to add to our internal list\n */\n addCue(originalCue) {\n let cue = originalCue;\n\n // Testing if the cue is a VTTCue in a way that survives minification\n if (!('getCueAsHTML' in cue)) {\n cue = new window.vttjs.VTTCue(originalCue.startTime, originalCue.endTime, originalCue.text);\n for (const prop in originalCue) {\n if (!(prop in cue)) {\n cue[prop] = originalCue[prop];\n }\n }\n\n // make sure that `id` is copied over\n cue.id = originalCue.id;\n cue.originalCue_ = originalCue;\n }\n const tracks = this.tech_.textTracks();\n for (let i = 0; i < tracks.length; i++) {\n if (tracks[i] !== this) {\n tracks[i].removeCue(cue);\n }\n }\n this.cues_.push(cue);\n this.cues.setCues_(this.cues_);\n }\n\n /**\n * Creates a copy of the text track and makes it serializable\n * by removing circular dependencies.\n *\n * @return {Object} The track information as a serializable object\n */\n toJSON() {\n return textTrackConverter.trackToJson(this);\n }\n\n /**\n * Remove a cue from our internal list\n *\n * @param {TextTrack~Cue} removeCue\n * The cue to remove from our internal list\n */\n removeCue(removeCue) {\n let i = this.cues_.length;\n while (i--) {\n const cue = this.cues_[i];\n if (cue === removeCue || cue.originalCue_ && cue.originalCue_ === removeCue) {\n this.cues_.splice(i, 1);\n this.cues.setCues_(this.cues_);\n break;\n }\n }\n }\n }\n\n /**\n * cuechange - One or more cues in the track have become active or stopped being active.\n *\n * @protected\n */\n TextTrack.prototype.allowedEvents_ = {\n cuechange: 'cuechange'\n };\n\n /**\n * A representation of a single `AudioTrack`. If it is part of an {@link AudioTrackList}\n * only one `AudioTrack` in the list will be enabled at a time.\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotrack}\n * @extends Track\n */\n class AudioTrack extends Track {\n /**\n * Create an instance of this class.\n *\n * @param {Object} [options={}]\n * Object of option names and values\n *\n * @param {AudioTrack~Kind} [options.kind='']\n * A valid audio track kind\n *\n * @param {string} [options.id='vjs_track_' + Guid.newGUID()]\n * A unique id for this AudioTrack.\n *\n * @param {string} [options.label='']\n * The menu label for this track.\n *\n * @param {string} [options.language='']\n * A valid two character language code.\n *\n * @param {boolean} [options.enabled]\n * If this track is the one that is currently playing. If this track is part of\n * an {@link AudioTrackList}, only one {@link AudioTrack} will be enabled.\n */\n constructor(options = {}) {\n const settings = merge(options, {\n kind: AudioTrackKind[options.kind] || ''\n });\n super(settings);\n let enabled = false;\n\n /**\n * @memberof AudioTrack\n * @member {boolean} enabled\n * If this `AudioTrack` is enabled or not. When setting this will\n * fire {@link AudioTrack#enabledchange} if the state of enabled is changed.\n * @instance\n *\n * @fires VideoTrack#selectedchange\n */\n Object.defineProperty(this, 'enabled', {\n get() {\n return enabled;\n },\n set(newEnabled) {\n // an invalid or unchanged value\n if (typeof newEnabled !== 'boolean' || newEnabled === enabled) {\n return;\n }\n enabled = newEnabled;\n\n /**\n * An event that fires when enabled changes on this track. This allows\n * the AudioTrackList that holds this track to act accordingly.\n *\n * > Note: This is not part of the spec! Native tracks will do\n * this internally without an event.\n *\n * @event AudioTrack#enabledchange\n * @type {Event}\n */\n this.trigger('enabledchange');\n }\n });\n\n // if the user sets this track to selected then\n // set selected to that true value otherwise\n // we keep it false\n if (settings.enabled) {\n this.enabled = settings.enabled;\n }\n this.loaded_ = true;\n }\n }\n\n /**\n * A representation of a single `VideoTrack`.\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotrack}\n * @extends Track\n */\n class VideoTrack extends Track {\n /**\n * Create an instance of this class.\n *\n * @param {Object} [options={}]\n * Object of option names and values\n *\n * @param {string} [options.kind='']\n * A valid {@link VideoTrack~Kind}\n *\n * @param {string} [options.id='vjs_track_' + Guid.newGUID()]\n * A unique id for this AudioTrack.\n *\n * @param {string} [options.label='']\n * The menu label for this track.\n *\n * @param {string} [options.language='']\n * A valid two character language code.\n *\n * @param {boolean} [options.selected]\n * If this track is the one that is currently playing.\n */\n constructor(options = {}) {\n const settings = merge(options, {\n kind: VideoTrackKind[options.kind] || ''\n });\n super(settings);\n let selected = false;\n\n /**\n * @memberof VideoTrack\n * @member {boolean} selected\n * If this `VideoTrack` is selected or not. When setting this will\n * fire {@link VideoTrack#selectedchange} if the state of selected changed.\n * @instance\n *\n * @fires VideoTrack#selectedchange\n */\n Object.defineProperty(this, 'selected', {\n get() {\n return selected;\n },\n set(newSelected) {\n // an invalid or unchanged value\n if (typeof newSelected !== 'boolean' || newSelected === selected) {\n return;\n }\n selected = newSelected;\n\n /**\n * An event that fires when selected changes on this track. This allows\n * the VideoTrackList that holds this track to act accordingly.\n *\n * > Note: This is not part of the spec! Native tracks will do\n * this internally without an event.\n *\n * @event VideoTrack#selectedchange\n * @type {Event}\n */\n this.trigger('selectedchange');\n }\n });\n\n // if the user sets this track to selected then\n // set selected to that true value otherwise\n // we keep it false\n if (settings.selected) {\n this.selected = settings.selected;\n }\n }\n }\n\n /**\n * @file html-track-element.js\n */\n\n /** @import Tech from '../tech/tech' */\n\n /**\n * A single track represented in the DOM.\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#htmltrackelement}\n * @extends EventTarget\n */\n class HTMLTrackElement extends EventTarget {\n /**\n * Create an instance of this class.\n *\n * @param {Object} options={}\n * Object of option names and values\n *\n * @param {Tech} options.tech\n * A reference to the tech that owns this HTMLTrackElement.\n *\n * @param {TextTrack~Kind} [options.kind='subtitles']\n * A valid text track kind.\n *\n * @param {TextTrack~Mode} [options.mode='disabled']\n * A valid text track mode.\n *\n * @param {string} [options.id='vjs_track_' + Guid.newGUID()]\n * A unique id for this TextTrack.\n *\n * @param {string} [options.label='']\n * The menu label for this track.\n *\n * @param {string} [options.language='']\n * A valid two character language code.\n *\n * @param {string} [options.srclang='']\n * A valid two character language code. An alternative, but deprioritized\n * version of `options.language`\n *\n * @param {string} [options.src]\n * A url to TextTrack cues.\n *\n * @param {boolean} [options.default]\n * If this track should default to on or off.\n */\n constructor(options = {}) {\n super();\n let readyState;\n const track = new TextTrack(options);\n this.kind = track.kind;\n this.src = track.src;\n this.srclang = track.language;\n this.label = track.label;\n this.default = track.default;\n Object.defineProperties(this, {\n /**\n * @memberof HTMLTrackElement\n * @member {HTMLTrackElement~ReadyState} readyState\n * The current ready state of the track element.\n * @instance\n */\n readyState: {\n get() {\n return readyState;\n }\n },\n /**\n * @memberof HTMLTrackElement\n * @member {TextTrack} track\n * The underlying TextTrack object.\n * @instance\n *\n */\n track: {\n get() {\n return track;\n }\n }\n });\n readyState = HTMLTrackElement.NONE;\n\n /**\n * @listens TextTrack#loadeddata\n * @fires HTMLTrackElement#load\n */\n track.addEventListener('loadeddata', () => {\n readyState = HTMLTrackElement.LOADED;\n this.trigger({\n type: 'load',\n target: this\n });\n });\n }\n }\n\n /**\n * @protected\n */\n HTMLTrackElement.prototype.allowedEvents_ = {\n load: 'load'\n };\n\n /**\n * The text track not loaded state.\n *\n * @type {number}\n * @static\n */\n HTMLTrackElement.NONE = 0;\n\n /**\n * The text track loading state.\n *\n * @type {number}\n * @static\n */\n HTMLTrackElement.LOADING = 1;\n\n /**\n * The text track loaded state.\n *\n * @type {number}\n * @static\n */\n HTMLTrackElement.LOADED = 2;\n\n /**\n * The text track failed to load state.\n *\n * @type {number}\n * @static\n */\n HTMLTrackElement.ERROR = 3;\n\n /*\n * This file contains all track properties that are used in\n * player.js, tech.js, html5.js and possibly other techs in the future.\n */\n\n const NORMAL = {\n audio: {\n ListClass: AudioTrackList,\n TrackClass: AudioTrack,\n capitalName: 'Audio'\n },\n video: {\n ListClass: VideoTrackList,\n TrackClass: VideoTrack,\n capitalName: 'Video'\n },\n text: {\n ListClass: TextTrackList,\n TrackClass: TextTrack,\n capitalName: 'Text'\n }\n };\n Object.keys(NORMAL).forEach(function (type) {\n NORMAL[type].getterName = `${type}Tracks`;\n NORMAL[type].privateName = `${type}Tracks_`;\n });\n const REMOTE = {\n remoteText: {\n ListClass: TextTrackList,\n TrackClass: TextTrack,\n capitalName: 'RemoteText',\n getterName: 'remoteTextTracks',\n privateName: 'remoteTextTracks_'\n },\n remoteTextEl: {\n ListClass: HtmlTrackElementList,\n TrackClass: HTMLTrackElement,\n capitalName: 'RemoteTextTrackEls',\n getterName: 'remoteTextTrackEls',\n privateName: 'remoteTextTrackEls_'\n }\n };\n const ALL = Object.assign({}, NORMAL, REMOTE);\n REMOTE.names = Object.keys(REMOTE);\n NORMAL.names = Object.keys(NORMAL);\n ALL.names = [].concat(REMOTE.names).concat(NORMAL.names);\n\n var minDoc = {};\n\n var topLevel = typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof window !== 'undefined' ? window : {};\n var doccy;\n if (typeof document !== 'undefined') {\n doccy = document;\n } else {\n doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];\n if (!doccy) {\n doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;\n }\n }\n var document_1 = doccy;\n\n /**\n * Copyright 2013 vtt.js Contributors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */\n /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */\n\n var _objCreate = Object.create || function () {\n function F() {}\n return function (o) {\n if (arguments.length !== 1) {\n throw new Error('Object.create shim only accepts one parameter.');\n }\n F.prototype = o;\n return new F();\n };\n }();\n\n // Creates a new ParserError object from an errorData object. The errorData\n // object should have default code and message properties. The default message\n // property can be overriden by passing in a message parameter.\n // See ParsingError.Errors below for acceptable errors.\n function ParsingError(errorData, message) {\n this.name = \"ParsingError\";\n this.code = errorData.code;\n this.message = message || errorData.message;\n }\n ParsingError.prototype = _objCreate(Error.prototype);\n ParsingError.prototype.constructor = ParsingError;\n\n // ParsingError metadata for acceptable ParsingErrors.\n ParsingError.Errors = {\n BadSignature: {\n code: 0,\n message: \"Malformed WebVTT signature.\"\n },\n BadTimeStamp: {\n code: 1,\n message: \"Malformed time stamp.\"\n }\n };\n\n // Try to parse input as a time stamp.\n function parseTimeStamp(input) {\n function computeSeconds(h, m, s, f) {\n return (h | 0) * 3600 + (m | 0) * 60 + (s | 0) + (f | 0) / 1000;\n }\n var m = input.match(/^(\\d+):(\\d{1,2})(:\\d{1,2})?\\.(\\d{3})/);\n if (!m) {\n return null;\n }\n if (m[3]) {\n // Timestamp takes the form of [hours]:[minutes]:[seconds].[milliseconds]\n return computeSeconds(m[1], m[2], m[3].replace(\":\", \"\"), m[4]);\n } else if (m[1] > 59) {\n // Timestamp takes the form of [hours]:[minutes].[milliseconds]\n // First position is hours as it's over 59.\n return computeSeconds(m[1], m[2], 0, m[4]);\n } else {\n // Timestamp takes the form of [minutes]:[seconds].[milliseconds]\n return computeSeconds(0, m[1], m[2], m[4]);\n }\n }\n\n // A settings object holds key/value pairs and will ignore anything but the first\n // assignment to a specific key.\n function Settings() {\n this.values = _objCreate(null);\n }\n Settings.prototype = {\n // Only accept the first assignment to any key.\n set: function (k, v) {\n if (!this.get(k) && v !== \"\") {\n this.values[k] = v;\n }\n },\n // Return the value for a key, or a default value.\n // If 'defaultKey' is passed then 'dflt' is assumed to be an object with\n // a number of possible default values as properties where 'defaultKey' is\n // the key of the property that will be chosen; otherwise it's assumed to be\n // a single value.\n get: function (k, dflt, defaultKey) {\n if (defaultKey) {\n return this.has(k) ? this.values[k] : dflt[defaultKey];\n }\n return this.has(k) ? this.values[k] : dflt;\n },\n // Check whether we have a value for a key.\n has: function (k) {\n return k in this.values;\n },\n // Accept a setting if its one of the given alternatives.\n alt: function (k, v, a) {\n for (var n = 0; n < a.length; ++n) {\n if (v === a[n]) {\n this.set(k, v);\n break;\n }\n }\n },\n // Accept a setting if its a valid (signed) integer.\n integer: function (k, v) {\n if (/^-?\\d+$/.test(v)) {\n // integer\n this.set(k, parseInt(v, 10));\n }\n },\n // Accept a setting if its a valid percentage.\n percent: function (k, v) {\n if (v.match(/^([\\d]{1,3})(\\.[\\d]*)?%$/)) {\n v = parseFloat(v);\n if (v >= 0 && v <= 100) {\n this.set(k, v);\n return true;\n }\n }\n return false;\n }\n };\n\n // Helper function to parse input into groups separated by 'groupDelim', and\n // interprete each group as a key/value pair separated by 'keyValueDelim'.\n function parseOptions(input, callback, keyValueDelim, groupDelim) {\n var groups = groupDelim ? input.split(groupDelim) : [input];\n for (var i in groups) {\n if (typeof groups[i] !== \"string\") {\n continue;\n }\n var kv = groups[i].split(keyValueDelim);\n if (kv.length !== 2) {\n continue;\n }\n var k = kv[0].trim();\n var v = kv[1].trim();\n callback(k, v);\n }\n }\n function parseCue(input, cue, regionList) {\n // Remember the original input if we need to throw an error.\n var oInput = input;\n // 4.1 WebVTT timestamp\n function consumeTimeStamp() {\n var ts = parseTimeStamp(input);\n if (ts === null) {\n throw new ParsingError(ParsingError.Errors.BadTimeStamp, \"Malformed timestamp: \" + oInput);\n }\n // Remove time stamp from input.\n input = input.replace(/^[^\\sa-zA-Z-]+/, \"\");\n return ts;\n }\n\n // 4.4.2 WebVTT cue settings\n function consumeCueSettings(input, cue) {\n var settings = new Settings();\n parseOptions(input, function (k, v) {\n switch (k) {\n case \"region\":\n // Find the last region we parsed with the same region id.\n for (var i = regionList.length - 1; i >= 0; i--) {\n if (regionList[i].id === v) {\n settings.set(k, regionList[i].region);\n break;\n }\n }\n break;\n case \"vertical\":\n settings.alt(k, v, [\"rl\", \"lr\"]);\n break;\n case \"line\":\n var vals = v.split(\",\"),\n vals0 = vals[0];\n settings.integer(k, vals0);\n settings.percent(k, vals0) ? settings.set(\"snapToLines\", false) : null;\n settings.alt(k, vals0, [\"auto\"]);\n if (vals.length === 2) {\n settings.alt(\"lineAlign\", vals[1], [\"start\", \"center\", \"end\"]);\n }\n break;\n case \"position\":\n vals = v.split(\",\");\n settings.percent(k, vals[0]);\n if (vals.length === 2) {\n settings.alt(\"positionAlign\", vals[1], [\"start\", \"center\", \"end\"]);\n }\n break;\n case \"size\":\n settings.percent(k, v);\n break;\n case \"align\":\n settings.alt(k, v, [\"start\", \"center\", \"end\", \"left\", \"right\"]);\n break;\n }\n }, /:/, /\\s/);\n\n // Apply default values for any missing fields.\n cue.region = settings.get(\"region\", null);\n cue.vertical = settings.get(\"vertical\", \"\");\n try {\n cue.line = settings.get(\"line\", \"auto\");\n } catch (e) {}\n cue.lineAlign = settings.get(\"lineAlign\", \"start\");\n cue.snapToLines = settings.get(\"snapToLines\", true);\n cue.size = settings.get(\"size\", 100);\n // Safari still uses the old middle value and won't accept center\n try {\n cue.align = settings.get(\"align\", \"center\");\n } catch (e) {\n cue.align = settings.get(\"align\", \"middle\");\n }\n try {\n cue.position = settings.get(\"position\", \"auto\");\n } catch (e) {\n cue.position = settings.get(\"position\", {\n start: 0,\n left: 0,\n center: 50,\n middle: 50,\n end: 100,\n right: 100\n }, cue.align);\n }\n cue.positionAlign = settings.get(\"positionAlign\", {\n start: \"start\",\n left: \"start\",\n center: \"center\",\n middle: \"center\",\n end: \"end\",\n right: \"end\"\n }, cue.align);\n }\n function skipWhitespace() {\n input = input.replace(/^\\s+/, \"\");\n }\n\n // 4.1 WebVTT cue timings.\n skipWhitespace();\n cue.startTime = consumeTimeStamp(); // (1) collect cue start time\n skipWhitespace();\n if (input.substr(0, 3) !== \"-->\") {\n // (3) next characters must match \"-->\"\n throw new ParsingError(ParsingError.Errors.BadTimeStamp, \"Malformed time stamp (time stamps must be separated by '-->'): \" + oInput);\n }\n input = input.substr(3);\n skipWhitespace();\n cue.endTime = consumeTimeStamp(); // (5) collect cue end time\n\n // 4.1 WebVTT cue settings list.\n skipWhitespace();\n consumeCueSettings(input, cue);\n }\n\n // When evaluating this file as part of a Webpack bundle for server\n // side rendering, `document` is an empty object.\n var TEXTAREA_ELEMENT = document_1.createElement && document_1.createElement(\"textarea\");\n var TAG_NAME = {\n c: \"span\",\n i: \"i\",\n b: \"b\",\n u: \"u\",\n ruby: \"ruby\",\n rt: \"rt\",\n v: \"span\",\n lang: \"span\"\n };\n\n // 5.1 default text color\n // 5.2 default text background color is equivalent to text color with bg_ prefix\n var DEFAULT_COLOR_CLASS = {\n white: 'rgba(255,255,255,1)',\n lime: 'rgba(0,255,0,1)',\n cyan: 'rgba(0,255,255,1)',\n red: 'rgba(255,0,0,1)',\n yellow: 'rgba(255,255,0,1)',\n magenta: 'rgba(255,0,255,1)',\n blue: 'rgba(0,0,255,1)',\n black: 'rgba(0,0,0,1)'\n };\n var TAG_ANNOTATION = {\n v: \"title\",\n lang: \"lang\"\n };\n var NEEDS_PARENT = {\n rt: \"ruby\"\n };\n\n // Parse content into a document fragment.\n function parseContent(window, input) {\n function nextToken() {\n // Check for end-of-string.\n if (!input) {\n return null;\n }\n\n // Consume 'n' characters from the input.\n function consume(result) {\n input = input.substr(result.length);\n return result;\n }\n var m = input.match(/^([^<]*)(<[^>]*>?)?/);\n // If there is some text before the next tag, return it, otherwise return\n // the tag.\n return consume(m[1] ? m[1] : m[2]);\n }\n function unescape(s) {\n TEXTAREA_ELEMENT.innerHTML = s;\n s = TEXTAREA_ELEMENT.textContent;\n TEXTAREA_ELEMENT.textContent = \"\";\n return s;\n }\n function shouldAdd(current, element) {\n return !NEEDS_PARENT[element.localName] || NEEDS_PARENT[element.localName] === current.localName;\n }\n\n // Create an element for this tag.\n function createElement(type, annotation) {\n var tagName = TAG_NAME[type];\n if (!tagName) {\n return null;\n }\n var element = window.document.createElement(tagName);\n var name = TAG_ANNOTATION[type];\n if (name && annotation) {\n element[name] = annotation.trim();\n }\n return element;\n }\n var rootDiv = window.document.createElement(\"div\"),\n current = rootDiv,\n t,\n tagStack = [];\n while ((t = nextToken()) !== null) {\n if (t[0] === '<') {\n if (t[1] === \"/\") {\n // If the closing tag matches, move back up to the parent node.\n if (tagStack.length && tagStack[tagStack.length - 1] === t.substr(2).replace(\">\", \"\")) {\n tagStack.pop();\n current = current.parentNode;\n }\n // Otherwise just ignore the end tag.\n continue;\n }\n var ts = parseTimeStamp(t.substr(1, t.length - 2));\n var node;\n if (ts) {\n // Timestamps are lead nodes as well.\n node = window.document.createProcessingInstruction(\"timestamp\", ts);\n current.appendChild(node);\n continue;\n }\n var m = t.match(/^<([^.\\s/0-9>]+)(\\.[^\\s\\\\>]+)?([^>\\\\]+)?(\\\\?)>?$/);\n // If we can't parse the tag, skip to the next tag.\n if (!m) {\n continue;\n }\n // Try to construct an element, and ignore the tag if we couldn't.\n node = createElement(m[1], m[3]);\n if (!node) {\n continue;\n }\n // Determine if the tag should be added based on the context of where it\n // is placed in the cuetext.\n if (!shouldAdd(current, node)) {\n continue;\n }\n // Set the class list (as a list of classes, separated by space).\n if (m[2]) {\n var classes = m[2].split('.');\n classes.forEach(function (cl) {\n var bgColor = /^bg_/.test(cl);\n // slice out `bg_` if it's a background color\n var colorName = bgColor ? cl.slice(3) : cl;\n if (DEFAULT_COLOR_CLASS.hasOwnProperty(colorName)) {\n var propName = bgColor ? 'background-color' : 'color';\n var propValue = DEFAULT_COLOR_CLASS[colorName];\n node.style[propName] = propValue;\n }\n });\n node.className = classes.join(' ');\n }\n // Append the node to the current node, and enter the scope of the new\n // node.\n tagStack.push(m[1]);\n current.appendChild(node);\n current = node;\n continue;\n }\n\n // Text nodes are leaf nodes.\n current.appendChild(window.document.createTextNode(unescape(t)));\n }\n return rootDiv;\n }\n\n // This is a list of all the Unicode characters that have a strong\n // right-to-left category. What this means is that these characters are\n // written right-to-left for sure. It was generated by pulling all the strong\n // right-to-left characters out of the Unicode data table. That table can\n // found at: http://www.unicode.org/Public/UNIDATA/UnicodeData.txt\n var strongRTLRanges = [[0x5be, 0x5be], [0x5c0, 0x5c0], [0x5c3, 0x5c3], [0x5c6, 0x5c6], [0x5d0, 0x5ea], [0x5f0, 0x5f4], [0x608, 0x608], [0x60b, 0x60b], [0x60d, 0x60d], [0x61b, 0x61b], [0x61e, 0x64a], [0x66d, 0x66f], [0x671, 0x6d5], [0x6e5, 0x6e6], [0x6ee, 0x6ef], [0x6fa, 0x70d], [0x70f, 0x710], [0x712, 0x72f], [0x74d, 0x7a5], [0x7b1, 0x7b1], [0x7c0, 0x7ea], [0x7f4, 0x7f5], [0x7fa, 0x7fa], [0x800, 0x815], [0x81a, 0x81a], [0x824, 0x824], [0x828, 0x828], [0x830, 0x83e], [0x840, 0x858], [0x85e, 0x85e], [0x8a0, 0x8a0], [0x8a2, 0x8ac], [0x200f, 0x200f], [0xfb1d, 0xfb1d], [0xfb1f, 0xfb28], [0xfb2a, 0xfb36], [0xfb38, 0xfb3c], [0xfb3e, 0xfb3e], [0xfb40, 0xfb41], [0xfb43, 0xfb44], [0xfb46, 0xfbc1], [0xfbd3, 0xfd3d], [0xfd50, 0xfd8f], [0xfd92, 0xfdc7], [0xfdf0, 0xfdfc], [0xfe70, 0xfe74], [0xfe76, 0xfefc], [0x10800, 0x10805], [0x10808, 0x10808], [0x1080a, 0x10835], [0x10837, 0x10838], [0x1083c, 0x1083c], [0x1083f, 0x10855], [0x10857, 0x1085f], [0x10900, 0x1091b], [0x10920, 0x10939], [0x1093f, 0x1093f], [0x10980, 0x109b7], [0x109be, 0x109bf], [0x10a00, 0x10a00], [0x10a10, 0x10a13], [0x10a15, 0x10a17], [0x10a19, 0x10a33], [0x10a40, 0x10a47], [0x10a50, 0x10a58], [0x10a60, 0x10a7f], [0x10b00, 0x10b35], [0x10b40, 0x10b55], [0x10b58, 0x10b72], [0x10b78, 0x10b7f], [0x10c00, 0x10c48], [0x1ee00, 0x1ee03], [0x1ee05, 0x1ee1f], [0x1ee21, 0x1ee22], [0x1ee24, 0x1ee24], [0x1ee27, 0x1ee27], [0x1ee29, 0x1ee32], [0x1ee34, 0x1ee37], [0x1ee39, 0x1ee39], [0x1ee3b, 0x1ee3b], [0x1ee42, 0x1ee42], [0x1ee47, 0x1ee47], [0x1ee49, 0x1ee49], [0x1ee4b, 0x1ee4b], [0x1ee4d, 0x1ee4f], [0x1ee51, 0x1ee52], [0x1ee54, 0x1ee54], [0x1ee57, 0x1ee57], [0x1ee59, 0x1ee59], [0x1ee5b, 0x1ee5b], [0x1ee5d, 0x1ee5d], [0x1ee5f, 0x1ee5f], [0x1ee61, 0x1ee62], [0x1ee64, 0x1ee64], [0x1ee67, 0x1ee6a], [0x1ee6c, 0x1ee72], [0x1ee74, 0x1ee77], [0x1ee79, 0x1ee7c], [0x1ee7e, 0x1ee7e], [0x1ee80, 0x1ee89], [0x1ee8b, 0x1ee9b], [0x1eea1, 0x1eea3], [0x1eea5, 0x1eea9], [0x1eeab, 0x1eebb], [0x10fffd, 0x10fffd]];\n function isStrongRTLChar(charCode) {\n for (var i = 0; i < strongRTLRanges.length; i++) {\n var currentRange = strongRTLRanges[i];\n if (charCode >= currentRange[0] && charCode <= currentRange[1]) {\n return true;\n }\n }\n return false;\n }\n function determineBidi(cueDiv) {\n var nodeStack = [],\n text = \"\",\n charCode;\n if (!cueDiv || !cueDiv.childNodes) {\n return \"ltr\";\n }\n function pushNodes(nodeStack, node) {\n for (var i = node.childNodes.length - 1; i >= 0; i--) {\n nodeStack.push(node.childNodes[i]);\n }\n }\n function nextTextNode(nodeStack) {\n if (!nodeStack || !nodeStack.length) {\n return null;\n }\n var node = nodeStack.pop(),\n text = node.textContent || node.innerText;\n if (text) {\n // TODO: This should match all unicode type B characters (paragraph\n // separator characters). See issue #115.\n var m = text.match(/^.*(\\n|\\r)/);\n if (m) {\n nodeStack.length = 0;\n return m[0];\n }\n return text;\n }\n if (node.tagName === \"ruby\") {\n return nextTextNode(nodeStack);\n }\n if (node.childNodes) {\n pushNodes(nodeStack, node);\n return nextTextNode(nodeStack);\n }\n }\n pushNodes(nodeStack, cueDiv);\n while (text = nextTextNode(nodeStack)) {\n for (var i = 0; i < text.length; i++) {\n charCode = text.charCodeAt(i);\n if (isStrongRTLChar(charCode)) {\n return \"rtl\";\n }\n }\n }\n return \"ltr\";\n }\n function computeLinePos(cue) {\n if (typeof cue.line === \"number\" && (cue.snapToLines || cue.line >= 0 && cue.line <= 100)) {\n return cue.line;\n }\n if (!cue.track || !cue.track.textTrackList || !cue.track.textTrackList.mediaElement) {\n return -1;\n }\n var track = cue.track,\n trackList = track.textTrackList,\n count = 0;\n for (var i = 0; i < trackList.length && trackList[i] !== track; i++) {\n if (trackList[i].mode === \"showing\") {\n count++;\n }\n }\n return ++count * -1;\n }\n function StyleBox() {}\n\n // Apply styles to a div. If there is no div passed then it defaults to the\n // div on 'this'.\n StyleBox.prototype.applyStyles = function (styles, div) {\n div = div || this.div;\n for (var prop in styles) {\n if (styles.hasOwnProperty(prop)) {\n div.style[prop] = styles[prop];\n }\n }\n };\n StyleBox.prototype.formatStyle = function (val, unit) {\n return val === 0 ? 0 : val + unit;\n };\n\n // Constructs the computed display state of the cue (a div). Places the div\n // into the overlay which should be a block level element (usually a div).\n function CueStyleBox(window, cue, styleOptions) {\n StyleBox.call(this);\n this.cue = cue;\n\n // Parse our cue's text into a DOM tree rooted at 'cueDiv'. This div will\n // have inline positioning and will function as the cue background box.\n this.cueDiv = parseContent(window, cue.text);\n var styles = {\n color: \"rgba(255, 255, 255, 1)\",\n backgroundColor: \"rgba(0, 0, 0, 0.8)\",\n position: \"relative\",\n left: 0,\n right: 0,\n top: 0,\n bottom: 0,\n display: \"inline\",\n writingMode: cue.vertical === \"\" ? \"horizontal-tb\" : cue.vertical === \"lr\" ? \"vertical-lr\" : \"vertical-rl\",\n unicodeBidi: \"plaintext\"\n };\n this.applyStyles(styles, this.cueDiv);\n\n // Create an absolutely positioned div that will be used to position the cue\n // div. Note, all WebVTT cue-setting alignments are equivalent to the CSS\n // mirrors of them except middle instead of center on Safari.\n this.div = window.document.createElement(\"div\");\n styles = {\n direction: determineBidi(this.cueDiv),\n writingMode: cue.vertical === \"\" ? \"horizontal-tb\" : cue.vertical === \"lr\" ? \"vertical-lr\" : \"vertical-rl\",\n unicodeBidi: \"plaintext\",\n textAlign: cue.align === \"middle\" ? \"center\" : cue.align,\n font: styleOptions.font,\n whiteSpace: \"pre-line\",\n position: \"absolute\"\n };\n this.applyStyles(styles);\n this.div.appendChild(this.cueDiv);\n\n // Calculate the distance from the reference edge of the viewport to the text\n // position of the cue box. The reference edge will be resolved later when\n // the box orientation styles are applied.\n var textPos = 0;\n switch (cue.positionAlign) {\n case \"start\":\n case \"line-left\":\n textPos = cue.position;\n break;\n case \"center\":\n textPos = cue.position - cue.size / 2;\n break;\n case \"end\":\n case \"line-right\":\n textPos = cue.position - cue.size;\n break;\n }\n\n // Horizontal box orientation; textPos is the distance from the left edge of the\n // area to the left edge of the box and cue.size is the distance extending to\n // the right from there.\n if (cue.vertical === \"\") {\n this.applyStyles({\n left: this.formatStyle(textPos, \"%\"),\n width: this.formatStyle(cue.size, \"%\")\n });\n // Vertical box orientation; textPos is the distance from the top edge of the\n // area to the top edge of the box and cue.size is the height extending\n // downwards from there.\n } else {\n this.applyStyles({\n top: this.formatStyle(textPos, \"%\"),\n height: this.formatStyle(cue.size, \"%\")\n });\n }\n this.move = function (box) {\n this.applyStyles({\n top: this.formatStyle(box.top, \"px\"),\n bottom: this.formatStyle(box.bottom, \"px\"),\n left: this.formatStyle(box.left, \"px\"),\n right: this.formatStyle(box.right, \"px\"),\n height: this.formatStyle(box.height, \"px\"),\n width: this.formatStyle(box.width, \"px\")\n });\n };\n }\n CueStyleBox.prototype = _objCreate(StyleBox.prototype);\n CueStyleBox.prototype.constructor = CueStyleBox;\n\n // Represents the co-ordinates of an Element in a way that we can easily\n // compute things with such as if it overlaps or intersects with another Element.\n // Can initialize it with either a StyleBox or another BoxPosition.\n function BoxPosition(obj) {\n // Either a BoxPosition was passed in and we need to copy it, or a StyleBox\n // was passed in and we need to copy the results of 'getBoundingClientRect'\n // as the object returned is readonly. All co-ordinate values are in reference\n // to the viewport origin (top left).\n var lh, height, width, top;\n if (obj.div) {\n height = obj.div.offsetHeight;\n width = obj.div.offsetWidth;\n top = obj.div.offsetTop;\n var rects = (rects = obj.div.childNodes) && (rects = rects[0]) && rects.getClientRects && rects.getClientRects();\n obj = obj.div.getBoundingClientRect();\n // In certain cases the outter div will be slightly larger then the sum of\n // the inner div's lines. This could be due to bold text, etc, on some platforms.\n // In this case we should get the average line height and use that. This will\n // result in the desired behaviour.\n lh = rects ? Math.max(rects[0] && rects[0].height || 0, obj.height / rects.length) : 0;\n }\n this.left = obj.left;\n this.right = obj.right;\n this.top = obj.top || top;\n this.height = obj.height || height;\n this.bottom = obj.bottom || top + (obj.height || height);\n this.width = obj.width || width;\n this.lineHeight = lh !== undefined ? lh : obj.lineHeight;\n }\n\n // Move the box along a particular axis. Optionally pass in an amount to move\n // the box. If no amount is passed then the default is the line height of the\n // box.\n BoxPosition.prototype.move = function (axis, toMove) {\n toMove = toMove !== undefined ? toMove : this.lineHeight;\n switch (axis) {\n case \"+x\":\n this.left += toMove;\n this.right += toMove;\n break;\n case \"-x\":\n this.left -= toMove;\n this.right -= toMove;\n break;\n case \"+y\":\n this.top += toMove;\n this.bottom += toMove;\n break;\n case \"-y\":\n this.top -= toMove;\n this.bottom -= toMove;\n break;\n }\n };\n\n // Check if this box overlaps another box, b2.\n BoxPosition.prototype.overlaps = function (b2) {\n return this.left < b2.right && this.right > b2.left && this.top < b2.bottom && this.bottom > b2.top;\n };\n\n // Check if this box overlaps any other boxes in boxes.\n BoxPosition.prototype.overlapsAny = function (boxes) {\n for (var i = 0; i < boxes.length; i++) {\n if (this.overlaps(boxes[i])) {\n return true;\n }\n }\n return false;\n };\n\n // Check if this box is within another box.\n BoxPosition.prototype.within = function (container) {\n return this.top >= container.top && this.bottom <= container.bottom && this.left >= container.left && this.right <= container.right;\n };\n\n // Check if this box is entirely within the container or it is overlapping\n // on the edge opposite of the axis direction passed. For example, if \"+x\" is\n // passed and the box is overlapping on the left edge of the container, then\n // return true.\n BoxPosition.prototype.overlapsOppositeAxis = function (container, axis) {\n switch (axis) {\n case \"+x\":\n return this.left < container.left;\n case \"-x\":\n return this.right > container.right;\n case \"+y\":\n return this.top < container.top;\n case \"-y\":\n return this.bottom > container.bottom;\n }\n };\n\n // Find the percentage of the area that this box is overlapping with another\n // box.\n BoxPosition.prototype.intersectPercentage = function (b2) {\n var x = Math.max(0, Math.min(this.right, b2.right) - Math.max(this.left, b2.left)),\n y = Math.max(0, Math.min(this.bottom, b2.bottom) - Math.max(this.top, b2.top)),\n intersectArea = x * y;\n return intersectArea / (this.height * this.width);\n };\n\n // Convert the positions from this box to CSS compatible positions using\n // the reference container's positions. This has to be done because this\n // box's positions are in reference to the viewport origin, whereas, CSS\n // values are in referecne to their respective edges.\n BoxPosition.prototype.toCSSCompatValues = function (reference) {\n return {\n top: this.top - reference.top,\n bottom: reference.bottom - this.bottom,\n left: this.left - reference.left,\n right: reference.right - this.right,\n height: this.height,\n width: this.width\n };\n };\n\n // Get an object that represents the box's position without anything extra.\n // Can pass a StyleBox, HTMLElement, or another BoxPositon.\n BoxPosition.getSimpleBoxPosition = function (obj) {\n var height = obj.div ? obj.div.offsetHeight : obj.tagName ? obj.offsetHeight : 0;\n var width = obj.div ? obj.div.offsetWidth : obj.tagName ? obj.offsetWidth : 0;\n var top = obj.div ? obj.div.offsetTop : obj.tagName ? obj.offsetTop : 0;\n obj = obj.div ? obj.div.getBoundingClientRect() : obj.tagName ? obj.getBoundingClientRect() : obj;\n var ret = {\n left: obj.left,\n right: obj.right,\n top: obj.top || top,\n height: obj.height || height,\n bottom: obj.bottom || top + (obj.height || height),\n width: obj.width || width\n };\n return ret;\n };\n\n // Move a StyleBox to its specified, or next best, position. The containerBox\n // is the box that contains the StyleBox, such as a div. boxPositions are\n // a list of other boxes that the styleBox can't overlap with.\n function moveBoxToLinePosition(window, styleBox, containerBox, boxPositions) {\n // Find the best position for a cue box, b, on the video. The axis parameter\n // is a list of axis, the order of which, it will move the box along. For example:\n // Passing [\"+x\", \"-x\"] will move the box first along the x axis in the positive\n // direction. If it doesn't find a good position for it there it will then move\n // it along the x axis in the negative direction.\n function findBestPosition(b, axis) {\n var bestPosition,\n specifiedPosition = new BoxPosition(b),\n percentage = 1; // Highest possible so the first thing we get is better.\n\n for (var i = 0; i < axis.length; i++) {\n while (b.overlapsOppositeAxis(containerBox, axis[i]) || b.within(containerBox) && b.overlapsAny(boxPositions)) {\n b.move(axis[i]);\n }\n // We found a spot where we aren't overlapping anything. This is our\n // best position.\n if (b.within(containerBox)) {\n return b;\n }\n var p = b.intersectPercentage(containerBox);\n // If we're outside the container box less then we were on our last try\n // then remember this position as the best position.\n if (percentage > p) {\n bestPosition = new BoxPosition(b);\n percentage = p;\n }\n // Reset the box position to the specified position.\n b = new BoxPosition(specifiedPosition);\n }\n return bestPosition || specifiedPosition;\n }\n var boxPosition = new BoxPosition(styleBox),\n cue = styleBox.cue,\n linePos = computeLinePos(cue),\n axis = [];\n\n // If we have a line number to align the cue to.\n if (cue.snapToLines) {\n var size;\n switch (cue.vertical) {\n case \"\":\n axis = [\"+y\", \"-y\"];\n size = \"height\";\n break;\n case \"rl\":\n axis = [\"+x\", \"-x\"];\n size = \"width\";\n break;\n case \"lr\":\n axis = [\"-x\", \"+x\"];\n size = \"width\";\n break;\n }\n var step = boxPosition.lineHeight,\n position = step * Math.round(linePos),\n maxPosition = containerBox[size] + step,\n initialAxis = axis[0];\n\n // If the specified intial position is greater then the max position then\n // clamp the box to the amount of steps it would take for the box to\n // reach the max position.\n if (Math.abs(position) > maxPosition) {\n position = position < 0 ? -1 : 1;\n position *= Math.ceil(maxPosition / step) * step;\n }\n\n // If computed line position returns negative then line numbers are\n // relative to the bottom of the video instead of the top. Therefore, we\n // need to increase our initial position by the length or width of the\n // video, depending on the writing direction, and reverse our axis directions.\n if (linePos < 0) {\n position += cue.vertical === \"\" ? containerBox.height : containerBox.width;\n axis = axis.reverse();\n }\n\n // Move the box to the specified position. This may not be its best\n // position.\n boxPosition.move(initialAxis, position);\n } else {\n // If we have a percentage line value for the cue.\n var calculatedPercentage = boxPosition.lineHeight / containerBox.height * 100;\n switch (cue.lineAlign) {\n case \"center\":\n linePos -= calculatedPercentage / 2;\n break;\n case \"end\":\n linePos -= calculatedPercentage;\n break;\n }\n\n // Apply initial line position to the cue box.\n switch (cue.vertical) {\n case \"\":\n styleBox.applyStyles({\n top: styleBox.formatStyle(linePos, \"%\")\n });\n break;\n case \"rl\":\n styleBox.applyStyles({\n left: styleBox.formatStyle(linePos, \"%\")\n });\n break;\n case \"lr\":\n styleBox.applyStyles({\n right: styleBox.formatStyle(linePos, \"%\")\n });\n break;\n }\n axis = [\"+y\", \"-x\", \"+x\", \"-y\"];\n\n // Get the box position again after we've applied the specified positioning\n // to it.\n boxPosition = new BoxPosition(styleBox);\n }\n var bestPosition = findBestPosition(boxPosition, axis);\n styleBox.move(bestPosition.toCSSCompatValues(containerBox));\n }\n function WebVTT$1() {\n // Nothing\n }\n\n // Helper to allow strings to be decoded instead of the default binary utf8 data.\n WebVTT$1.StringDecoder = function () {\n return {\n decode: function (data) {\n if (!data) {\n return \"\";\n }\n if (typeof data !== \"string\") {\n throw new Error(\"Error - expected string data.\");\n }\n return decodeURIComponent(encodeURIComponent(data));\n }\n };\n };\n WebVTT$1.convertCueToDOMTree = function (window, cuetext) {\n if (!window || !cuetext) {\n return null;\n }\n return parseContent(window, cuetext);\n };\n var FONT_SIZE_PERCENT = 0.05;\n var FONT_STYLE = \"sans-serif\";\n var CUE_BACKGROUND_PADDING = \"1.5%\";\n\n // Runs the processing model over the cues and regions passed to it.\n // @param overlay A block level element (usually a div) that the computed cues\n // and regions will be placed into.\n WebVTT$1.processCues = function (window, cues, overlay) {\n if (!window || !cues || !overlay) {\n return null;\n }\n\n // Remove all previous children.\n while (overlay.firstChild) {\n overlay.removeChild(overlay.firstChild);\n }\n var paddedOverlay = window.document.createElement(\"div\");\n paddedOverlay.style.position = \"absolute\";\n paddedOverlay.style.left = \"0\";\n paddedOverlay.style.right = \"0\";\n paddedOverlay.style.top = \"0\";\n paddedOverlay.style.bottom = \"0\";\n paddedOverlay.style.margin = CUE_BACKGROUND_PADDING;\n overlay.appendChild(paddedOverlay);\n\n // Determine if we need to compute the display states of the cues. This could\n // be the case if a cue's state has been changed since the last computation or\n // if it has not been computed yet.\n function shouldCompute(cues) {\n for (var i = 0; i < cues.length; i++) {\n if (cues[i].hasBeenReset || !cues[i].displayState) {\n return true;\n }\n }\n return false;\n }\n\n // We don't need to recompute the cues' display states. Just reuse them.\n if (!shouldCompute(cues)) {\n for (var i = 0; i < cues.length; i++) {\n paddedOverlay.appendChild(cues[i].displayState);\n }\n return;\n }\n var boxPositions = [],\n containerBox = BoxPosition.getSimpleBoxPosition(paddedOverlay),\n fontSize = Math.round(containerBox.height * FONT_SIZE_PERCENT * 100) / 100;\n var styleOptions = {\n font: fontSize + \"px \" + FONT_STYLE\n };\n (function () {\n var styleBox, cue;\n for (var i = 0; i < cues.length; i++) {\n cue = cues[i];\n\n // Compute the intial position and styles of the cue div.\n styleBox = new CueStyleBox(window, cue, styleOptions);\n paddedOverlay.appendChild(styleBox.div);\n\n // Move the cue div to it's correct line position.\n moveBoxToLinePosition(window, styleBox, containerBox, boxPositions);\n\n // Remember the computed div so that we don't have to recompute it later\n // if we don't have too.\n cue.displayState = styleBox.div;\n boxPositions.push(BoxPosition.getSimpleBoxPosition(styleBox));\n }\n })();\n };\n WebVTT$1.Parser = function (window, vttjs, decoder) {\n if (!decoder) {\n decoder = vttjs;\n vttjs = {};\n }\n if (!vttjs) {\n vttjs = {};\n }\n this.window = window;\n this.vttjs = vttjs;\n this.state = \"INITIAL\";\n this.buffer = \"\";\n this.decoder = decoder || new TextDecoder(\"utf8\");\n this.regionList = [];\n };\n WebVTT$1.Parser.prototype = {\n // If the error is a ParsingError then report it to the consumer if\n // possible. If it's not a ParsingError then throw it like normal.\n reportOrThrowError: function (e) {\n if (e instanceof ParsingError) {\n this.onparsingerror && this.onparsingerror(e);\n } else {\n throw e;\n }\n },\n parse: function (data) {\n var self = this;\n\n // If there is no data then we won't decode it, but will just try to parse\n // whatever is in buffer already. This may occur in circumstances, for\n // example when flush() is called.\n if (data) {\n // Try to decode the data that we received.\n self.buffer += self.decoder.decode(data, {\n stream: true\n });\n }\n function collectNextLine() {\n var buffer = self.buffer;\n var pos = 0;\n while (pos < buffer.length && buffer[pos] !== '\\r' && buffer[pos] !== '\\n') {\n ++pos;\n }\n var line = buffer.substr(0, pos);\n // Advance the buffer early in case we fail below.\n if (buffer[pos] === '\\r') {\n ++pos;\n }\n if (buffer[pos] === '\\n') {\n ++pos;\n }\n self.buffer = buffer.substr(pos);\n return line;\n }\n\n // 3.4 WebVTT region and WebVTT region settings syntax\n function parseRegion(input) {\n var settings = new Settings();\n parseOptions(input, function (k, v) {\n switch (k) {\n case \"id\":\n settings.set(k, v);\n break;\n case \"width\":\n settings.percent(k, v);\n break;\n case \"lines\":\n settings.integer(k, v);\n break;\n case \"regionanchor\":\n case \"viewportanchor\":\n var xy = v.split(',');\n if (xy.length !== 2) {\n break;\n }\n // We have to make sure both x and y parse, so use a temporary\n // settings object here.\n var anchor = new Settings();\n anchor.percent(\"x\", xy[0]);\n anchor.percent(\"y\", xy[1]);\n if (!anchor.has(\"x\") || !anchor.has(\"y\")) {\n break;\n }\n settings.set(k + \"X\", anchor.get(\"x\"));\n settings.set(k + \"Y\", anchor.get(\"y\"));\n break;\n case \"scroll\":\n settings.alt(k, v, [\"up\"]);\n break;\n }\n }, /=/, /\\s/);\n\n // Create the region, using default values for any values that were not\n // specified.\n if (settings.has(\"id\")) {\n var region = new (self.vttjs.VTTRegion || self.window.VTTRegion)();\n region.width = settings.get(\"width\", 100);\n region.lines = settings.get(\"lines\", 3);\n region.regionAnchorX = settings.get(\"regionanchorX\", 0);\n region.regionAnchorY = settings.get(\"regionanchorY\", 100);\n region.viewportAnchorX = settings.get(\"viewportanchorX\", 0);\n region.viewportAnchorY = settings.get(\"viewportanchorY\", 100);\n region.scroll = settings.get(\"scroll\", \"\");\n // Register the region.\n self.onregion && self.onregion(region);\n // Remember the VTTRegion for later in case we parse any VTTCues that\n // reference it.\n self.regionList.push({\n id: settings.get(\"id\"),\n region: region\n });\n }\n }\n\n // draft-pantos-http-live-streaming-20\n // https://tools.ietf.org/html/draft-pantos-http-live-streaming-20#section-3.5\n // 3.5 WebVTT\n function parseTimestampMap(input) {\n var settings = new Settings();\n parseOptions(input, function (k, v) {\n switch (k) {\n case \"MPEGT\":\n settings.integer(k + 'S', v);\n break;\n case \"LOCA\":\n settings.set(k + 'L', parseTimeStamp(v));\n break;\n }\n }, /[^\\d]:/, /,/);\n self.ontimestampmap && self.ontimestampmap({\n \"MPEGTS\": settings.get(\"MPEGTS\"),\n \"LOCAL\": settings.get(\"LOCAL\")\n });\n }\n\n // 3.2 WebVTT metadata header syntax\n function parseHeader(input) {\n if (input.match(/X-TIMESTAMP-MAP/)) {\n // This line contains HLS X-TIMESTAMP-MAP metadata\n parseOptions(input, function (k, v) {\n switch (k) {\n case \"X-TIMESTAMP-MAP\":\n parseTimestampMap(v);\n break;\n }\n }, /=/);\n } else {\n parseOptions(input, function (k, v) {\n switch (k) {\n case \"Region\":\n // 3.3 WebVTT region metadata header syntax\n parseRegion(v);\n break;\n }\n }, /:/);\n }\n }\n\n // 5.1 WebVTT file parsing.\n try {\n var line;\n if (self.state === \"INITIAL\") {\n // We can't start parsing until we have the first line.\n if (!/\\r\\n|\\n/.test(self.buffer)) {\n return this;\n }\n line = collectNextLine();\n var m = line.match(/^WEBVTT([ \\t].*)?$/);\n if (!m || !m[0]) {\n throw new ParsingError(ParsingError.Errors.BadSignature);\n }\n self.state = \"HEADER\";\n }\n var alreadyCollectedLine = false;\n while (self.buffer) {\n // We can't parse a line until we have the full line.\n if (!/\\r\\n|\\n/.test(self.buffer)) {\n return this;\n }\n if (!alreadyCollectedLine) {\n line = collectNextLine();\n } else {\n alreadyCollectedLine = false;\n }\n switch (self.state) {\n case \"HEADER\":\n // 13-18 - Allow a header (metadata) under the WEBVTT line.\n if (/:/.test(line)) {\n parseHeader(line);\n } else if (!line) {\n // An empty line terminates the header and starts the body (cues).\n self.state = \"ID\";\n }\n continue;\n case \"NOTE\":\n // Ignore NOTE blocks.\n if (!line) {\n self.state = \"ID\";\n }\n continue;\n case \"ID\":\n // Check for the start of NOTE blocks.\n if (/^NOTE($|[ \\t])/.test(line)) {\n self.state = \"NOTE\";\n break;\n }\n // 19-29 - Allow any number of line terminators, then initialize new cue values.\n if (!line) {\n continue;\n }\n self.cue = new (self.vttjs.VTTCue || self.window.VTTCue)(0, 0, \"\");\n // Safari still uses the old middle value and won't accept center\n try {\n self.cue.align = \"center\";\n } catch (e) {\n self.cue.align = \"middle\";\n }\n self.state = \"CUE\";\n // 30-39 - Check if self line contains an optional identifier or timing data.\n if (line.indexOf(\"-->\") === -1) {\n self.cue.id = line;\n continue;\n }\n // Process line as start of a cue.\n /*falls through*/\n case \"CUE\":\n // 40 - Collect cue timings and settings.\n try {\n parseCue(line, self.cue, self.regionList);\n } catch (e) {\n self.reportOrThrowError(e);\n // In case of an error ignore rest of the cue.\n self.cue = null;\n self.state = \"BADCUE\";\n continue;\n }\n self.state = \"CUETEXT\";\n continue;\n case \"CUETEXT\":\n var hasSubstring = line.indexOf(\"-->\") !== -1;\n // 34 - If we have an empty line then report the cue.\n // 35 - If we have the special substring '-->' then report the cue,\n // but do not collect the line as we need to process the current\n // one as a new cue.\n if (!line || hasSubstring && (alreadyCollectedLine = true)) {\n // We are done parsing self cue.\n self.oncue && self.oncue(self.cue);\n self.cue = null;\n self.state = \"ID\";\n continue;\n }\n if (self.cue.text) {\n self.cue.text += \"\\n\";\n }\n self.cue.text += line.replace(/\\u2028/g, '\\n').replace(/u2029/g, '\\n');\n continue;\n case \"BADCUE\":\n // BADCUE\n // 54-62 - Collect and discard the remaining cue.\n if (!line) {\n self.state = \"ID\";\n }\n continue;\n }\n }\n } catch (e) {\n self.reportOrThrowError(e);\n\n // If we are currently parsing a cue, report what we have.\n if (self.state === \"CUETEXT\" && self.cue && self.oncue) {\n self.oncue(self.cue);\n }\n self.cue = null;\n // Enter BADWEBVTT state if header was not parsed correctly otherwise\n // another exception occurred so enter BADCUE state.\n self.state = self.state === \"INITIAL\" ? \"BADWEBVTT\" : \"BADCUE\";\n }\n return this;\n },\n flush: function () {\n var self = this;\n try {\n // Finish decoding the stream.\n self.buffer += self.decoder.decode();\n // Synthesize the end of the current cue or region.\n if (self.cue || self.state === \"HEADER\") {\n self.buffer += \"\\n\\n\";\n self.parse();\n }\n // If we've flushed, parsed, and we're still on the INITIAL state then\n // that means we don't have enough of the stream to parse the first\n // line.\n if (self.state === \"INITIAL\") {\n throw new ParsingError(ParsingError.Errors.BadSignature);\n }\n } catch (e) {\n self.reportOrThrowError(e);\n }\n self.onflush && self.onflush();\n return this;\n }\n };\n var vtt = WebVTT$1;\n\n /**\n * Copyright 2013 vtt.js Contributors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n var autoKeyword = \"auto\";\n var directionSetting = {\n \"\": 1,\n \"lr\": 1,\n \"rl\": 1\n };\n var alignSetting = {\n \"start\": 1,\n \"center\": 1,\n \"end\": 1,\n \"left\": 1,\n \"right\": 1,\n \"auto\": 1,\n \"line-left\": 1,\n \"line-right\": 1\n };\n function findDirectionSetting(value) {\n if (typeof value !== \"string\") {\n return false;\n }\n var dir = directionSetting[value.toLowerCase()];\n return dir ? value.toLowerCase() : false;\n }\n function findAlignSetting(value) {\n if (typeof value !== \"string\") {\n return false;\n }\n var align = alignSetting[value.toLowerCase()];\n return align ? value.toLowerCase() : false;\n }\n function VTTCue(startTime, endTime, text) {\n /**\n * Shim implementation specific properties. These properties are not in\n * the spec.\n */\n\n // Lets us know when the VTTCue's data has changed in such a way that we need\n // to recompute its display state. This lets us compute its display state\n // lazily.\n this.hasBeenReset = false;\n\n /**\n * VTTCue and TextTrackCue properties\n * http://dev.w3.org/html5/webvtt/#vttcue-interface\n */\n\n var _id = \"\";\n var _pauseOnExit = false;\n var _startTime = startTime;\n var _endTime = endTime;\n var _text = text;\n var _region = null;\n var _vertical = \"\";\n var _snapToLines = true;\n var _line = \"auto\";\n var _lineAlign = \"start\";\n var _position = \"auto\";\n var _positionAlign = \"auto\";\n var _size = 100;\n var _align = \"center\";\n Object.defineProperties(this, {\n \"id\": {\n enumerable: true,\n get: function () {\n return _id;\n },\n set: function (value) {\n _id = \"\" + value;\n }\n },\n \"pauseOnExit\": {\n enumerable: true,\n get: function () {\n return _pauseOnExit;\n },\n set: function (value) {\n _pauseOnExit = !!value;\n }\n },\n \"startTime\": {\n enumerable: true,\n get: function () {\n return _startTime;\n },\n set: function (value) {\n if (typeof value !== \"number\") {\n throw new TypeError(\"Start time must be set to a number.\");\n }\n _startTime = value;\n this.hasBeenReset = true;\n }\n },\n \"endTime\": {\n enumerable: true,\n get: function () {\n return _endTime;\n },\n set: function (value) {\n if (typeof value !== \"number\") {\n throw new TypeError(\"End time must be set to a number.\");\n }\n _endTime = value;\n this.hasBeenReset = true;\n }\n },\n \"text\": {\n enumerable: true,\n get: function () {\n return _text;\n },\n set: function (value) {\n _text = \"\" + value;\n this.hasBeenReset = true;\n }\n },\n \"region\": {\n enumerable: true,\n get: function () {\n return _region;\n },\n set: function (value) {\n _region = value;\n this.hasBeenReset = true;\n }\n },\n \"vertical\": {\n enumerable: true,\n get: function () {\n return _vertical;\n },\n set: function (value) {\n var setting = findDirectionSetting(value);\n // Have to check for false because the setting an be an empty string.\n if (setting === false) {\n throw new SyntaxError(\"Vertical: an invalid or illegal direction string was specified.\");\n }\n _vertical = setting;\n this.hasBeenReset = true;\n }\n },\n \"snapToLines\": {\n enumerable: true,\n get: function () {\n return _snapToLines;\n },\n set: function (value) {\n _snapToLines = !!value;\n this.hasBeenReset = true;\n }\n },\n \"line\": {\n enumerable: true,\n get: function () {\n return _line;\n },\n set: function (value) {\n if (typeof value !== \"number\" && value !== autoKeyword) {\n throw new SyntaxError(\"Line: an invalid number or illegal string was specified.\");\n }\n _line = value;\n this.hasBeenReset = true;\n }\n },\n \"lineAlign\": {\n enumerable: true,\n get: function () {\n return _lineAlign;\n },\n set: function (value) {\n var setting = findAlignSetting(value);\n if (!setting) {\n console.warn(\"lineAlign: an invalid or illegal string was specified.\");\n } else {\n _lineAlign = setting;\n this.hasBeenReset = true;\n }\n }\n },\n \"position\": {\n enumerable: true,\n get: function () {\n return _position;\n },\n set: function (value) {\n if (value < 0 || value > 100) {\n throw new Error(\"Position must be between 0 and 100.\");\n }\n _position = value;\n this.hasBeenReset = true;\n }\n },\n \"positionAlign\": {\n enumerable: true,\n get: function () {\n return _positionAlign;\n },\n set: function (value) {\n var setting = findAlignSetting(value);\n if (!setting) {\n console.warn(\"positionAlign: an invalid or illegal string was specified.\");\n } else {\n _positionAlign = setting;\n this.hasBeenReset = true;\n }\n }\n },\n \"size\": {\n enumerable: true,\n get: function () {\n return _size;\n },\n set: function (value) {\n if (value < 0 || value > 100) {\n throw new Error(\"Size must be between 0 and 100.\");\n }\n _size = value;\n this.hasBeenReset = true;\n }\n },\n \"align\": {\n enumerable: true,\n get: function () {\n return _align;\n },\n set: function (value) {\n var setting = findAlignSetting(value);\n if (!setting) {\n throw new SyntaxError(\"align: an invalid or illegal alignment string was specified.\");\n }\n _align = setting;\n this.hasBeenReset = true;\n }\n }\n });\n\n /**\n * Other <track> spec defined properties\n */\n\n // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-display-state\n this.displayState = undefined;\n }\n\n /**\n * VTTCue methods\n */\n\n VTTCue.prototype.getCueAsHTML = function () {\n // Assume WebVTT.convertCueToDOMTree is on the global.\n return WebVTT.convertCueToDOMTree(window, this.text);\n };\n var vttcue = VTTCue;\n\n /**\n * Copyright 2013 vtt.js Contributors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n var scrollSetting = {\n \"\": true,\n \"up\": true\n };\n function findScrollSetting(value) {\n if (typeof value !== \"string\") {\n return false;\n }\n var scroll = scrollSetting[value.toLowerCase()];\n return scroll ? value.toLowerCase() : false;\n }\n function isValidPercentValue(value) {\n return typeof value === \"number\" && value >= 0 && value <= 100;\n }\n\n // VTTRegion shim http://dev.w3.org/html5/webvtt/#vttregion-interface\n function VTTRegion() {\n var _width = 100;\n var _lines = 3;\n var _regionAnchorX = 0;\n var _regionAnchorY = 100;\n var _viewportAnchorX = 0;\n var _viewportAnchorY = 100;\n var _scroll = \"\";\n Object.defineProperties(this, {\n \"width\": {\n enumerable: true,\n get: function () {\n return _width;\n },\n set: function (value) {\n if (!isValidPercentValue(value)) {\n throw new Error(\"Width must be between 0 and 100.\");\n }\n _width = value;\n }\n },\n \"lines\": {\n enumerable: true,\n get: function () {\n return _lines;\n },\n set: function (value) {\n if (typeof value !== \"number\") {\n throw new TypeError(\"Lines must be set to a number.\");\n }\n _lines = value;\n }\n },\n \"regionAnchorY\": {\n enumerable: true,\n get: function () {\n return _regionAnchorY;\n },\n set: function (value) {\n if (!isValidPercentValue(value)) {\n throw new Error(\"RegionAnchorX must be between 0 and 100.\");\n }\n _regionAnchorY = value;\n }\n },\n \"regionAnchorX\": {\n enumerable: true,\n get: function () {\n return _regionAnchorX;\n },\n set: function (value) {\n if (!isValidPercentValue(value)) {\n throw new Error(\"RegionAnchorY must be between 0 and 100.\");\n }\n _regionAnchorX = value;\n }\n },\n \"viewportAnchorY\": {\n enumerable: true,\n get: function () {\n return _viewportAnchorY;\n },\n set: function (value) {\n if (!isValidPercentValue(value)) {\n throw new Error(\"ViewportAnchorY must be between 0 and 100.\");\n }\n _viewportAnchorY = value;\n }\n },\n \"viewportAnchorX\": {\n enumerable: true,\n get: function () {\n return _viewportAnchorX;\n },\n set: function (value) {\n if (!isValidPercentValue(value)) {\n throw new Error(\"ViewportAnchorX must be between 0 and 100.\");\n }\n _viewportAnchorX = value;\n }\n },\n \"scroll\": {\n enumerable: true,\n get: function () {\n return _scroll;\n },\n set: function (value) {\n var setting = findScrollSetting(value);\n // Have to check for false as an empty string is a legal value.\n if (setting === false) {\n console.warn(\"Scroll: an invalid or illegal string was specified.\");\n } else {\n _scroll = setting;\n }\n }\n }\n });\n }\n var vttregion = VTTRegion;\n\n var browserIndex = createCommonjsModule(function (module) {\n /**\n * Copyright 2013 vtt.js Contributors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n // Default exports for Node. Export the extended versions of VTTCue and\n // VTTRegion in Node since we likely want the capability to convert back and\n // forth between JSON. If we don't then it's not that big of a deal since we're\n // off browser.\n\n var vttjs = module.exports = {\n WebVTT: vtt,\n VTTCue: vttcue,\n VTTRegion: vttregion\n };\n window_1.vttjs = vttjs;\n window_1.WebVTT = vttjs.WebVTT;\n var cueShim = vttjs.VTTCue;\n var regionShim = vttjs.VTTRegion;\n var nativeVTTCue = window_1.VTTCue;\n var nativeVTTRegion = window_1.VTTRegion;\n vttjs.shim = function () {\n window_1.VTTCue = cueShim;\n window_1.VTTRegion = regionShim;\n };\n vttjs.restore = function () {\n window_1.VTTCue = nativeVTTCue;\n window_1.VTTRegion = nativeVTTRegion;\n };\n if (!window_1.VTTCue) {\n vttjs.shim();\n }\n });\n browserIndex.WebVTT;\n browserIndex.VTTCue;\n browserIndex.VTTRegion;\n\n /**\n * @file tech.js\n */\n\n /** @import { TimeRange } from '../utils/time' */\n\n /**\n * An Object containing a structure like: `{src: 'url', type: 'mimetype'}` or string\n * that just contains the src url alone.\n * * `var SourceObject = {src: 'http://ex.com/video.mp4', type: 'video/mp4'};`\n * `var SourceString = 'http://example.com/some-video.mp4';`\n *\n * @typedef {Object|string} SourceObject\n *\n * @property {string} src\n * The url to the source\n *\n * @property {string} type\n * The mime type of the source\n */\n\n /**\n * A function used by {@link Tech} to create a new {@link TextTrack}.\n *\n * @private\n *\n * @param {Tech} self\n * An instance of the Tech class.\n *\n * @param {string} kind\n * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)\n *\n * @param {string} [label]\n * Label to identify the text track\n *\n * @param {string} [language]\n * Two letter language abbreviation\n *\n * @param {Object} [options={}]\n * An object with additional text track options\n *\n * @return {TextTrack}\n * The text track that was created.\n */\n function createTrackHelper(self, kind, label, language, options = {}) {\n const tracks = self.textTracks();\n options.kind = kind;\n if (label) {\n options.label = label;\n }\n if (language) {\n options.language = language;\n }\n options.tech = self;\n const track = new ALL.text.TrackClass(options);\n tracks.addTrack(track);\n return track;\n }\n\n /**\n * This is the base class for media playback technology controllers, such as\n * {@link HTML5}\n *\n * @extends Component\n */\n class Tech extends Component {\n /**\n * Create an instance of this Tech.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {Function} [ready]\n * Callback function to call when the `HTML5` Tech is ready.\n */\n constructor(options = {}, ready = function () {}) {\n // we don't want the tech to report user activity automatically.\n // This is done manually in addControlsListeners\n options.reportTouchActivity = false;\n super(null, options, ready);\n this.onDurationChange_ = e => this.onDurationChange(e);\n this.trackProgress_ = e => this.trackProgress(e);\n this.trackCurrentTime_ = e => this.trackCurrentTime(e);\n this.stopTrackingCurrentTime_ = e => this.stopTrackingCurrentTime(e);\n this.disposeSourceHandler_ = e => this.disposeSourceHandler(e);\n this.queuedHanders_ = new Set();\n\n // keep track of whether the current source has played at all to\n // implement a very limited played()\n this.hasStarted_ = false;\n this.on('playing', function () {\n this.hasStarted_ = true;\n });\n this.on('loadstart', function () {\n this.hasStarted_ = false;\n });\n ALL.names.forEach(name => {\n const props = ALL[name];\n if (options && options[props.getterName]) {\n this[props.privateName] = options[props.getterName];\n }\n });\n\n // Manually track progress in cases where the browser/tech doesn't report it.\n if (!this.featuresProgressEvents) {\n this.manualProgressOn();\n }\n\n // Manually track timeupdates in cases where the browser/tech doesn't report it.\n if (!this.featuresTimeupdateEvents) {\n this.manualTimeUpdatesOn();\n }\n ['Text', 'Audio', 'Video'].forEach(track => {\n if (options[`native${track}Tracks`] === false) {\n this[`featuresNative${track}Tracks`] = false;\n }\n });\n if (options.nativeCaptions === false || options.nativeTextTracks === false) {\n this.featuresNativeTextTracks = false;\n } else if (options.nativeCaptions === true || options.nativeTextTracks === true) {\n this.featuresNativeTextTracks = true;\n }\n if (!this.featuresNativeTextTracks) {\n this.emulateTextTracks();\n }\n this.preloadTextTracks = options.preloadTextTracks !== false;\n this.autoRemoteTextTracks_ = new ALL.text.ListClass();\n this.initTrackListeners();\n\n // Turn on component tap events only if not using native controls\n if (!options.nativeControlsForTouch) {\n this.emitTapEvents();\n }\n if (this.constructor) {\n this.name_ = this.constructor.name || 'Unknown Tech';\n }\n }\n\n /**\n * A special function to trigger source set in a way that will allow player\n * to re-trigger if the player or tech are not ready yet.\n *\n * @fires Tech#sourceset\n * @param {string} src The source string at the time of the source changing.\n */\n triggerSourceset(src) {\n if (!this.isReady_) {\n // on initial ready we have to trigger source set\n // 1ms after ready so that player can watch for it.\n this.one('ready', () => this.setTimeout(() => this.triggerSourceset(src), 1));\n }\n\n /**\n * Fired when the source is set on the tech causing the media element\n * to reload.\n *\n * @see {@link Player#event:sourceset}\n * @event Tech#sourceset\n * @type {Event}\n */\n this.trigger({\n src,\n type: 'sourceset'\n });\n }\n\n /* Fallbacks for unsupported event types\n ================================================================================ */\n\n /**\n * Polyfill the `progress` event for browsers that don't support it natively.\n *\n * @see {@link Tech#trackProgress}\n */\n manualProgressOn() {\n this.on('durationchange', this.onDurationChange_);\n this.manualProgress = true;\n\n // Trigger progress watching when a source begins loading\n this.one('ready', this.trackProgress_);\n }\n\n /**\n * Turn off the polyfill for `progress` events that was created in\n * {@link Tech#manualProgressOn}\n */\n manualProgressOff() {\n this.manualProgress = false;\n this.stopTrackingProgress();\n this.off('durationchange', this.onDurationChange_);\n }\n\n /**\n * This is used to trigger a `progress` event when the buffered percent changes. It\n * sets an interval function that will be called every 500 milliseconds to check if the\n * buffer end percent has changed.\n *\n * > This function is called by {@link Tech#manualProgressOn}\n *\n * @param {Event} event\n * The `ready` event that caused this to run.\n *\n * @listens Tech#ready\n * @fires Tech#progress\n */\n trackProgress(event) {\n this.stopTrackingProgress();\n this.progressInterval = this.setInterval(bind_(this, function () {\n // Don't trigger unless buffered amount is greater than last time\n\n const numBufferedPercent = this.bufferedPercent();\n if (this.bufferedPercent_ !== numBufferedPercent) {\n /**\n * See {@link Player#progress}\n *\n * @event Tech#progress\n * @type {Event}\n */\n this.trigger('progress');\n }\n this.bufferedPercent_ = numBufferedPercent;\n if (numBufferedPercent === 1) {\n this.stopTrackingProgress();\n }\n }), 500);\n }\n\n /**\n * Update our internal duration on a `durationchange` event by calling\n * {@link Tech#duration}.\n *\n * @param {Event} event\n * The `durationchange` event that caused this to run.\n *\n * @listens Tech#durationchange\n */\n onDurationChange(event) {\n this.duration_ = this.duration();\n }\n\n /**\n * Get and create a `TimeRange` object for buffering.\n *\n * @return {TimeRange}\n * The time range object that was created.\n */\n buffered() {\n return createTimeRanges(0, 0);\n }\n\n /**\n * Get the percentage of the current video that is currently buffered.\n *\n * @return {number}\n * A number from 0 to 1 that represents the decimal percentage of the\n * video that is buffered.\n *\n */\n bufferedPercent() {\n return bufferedPercent(this.buffered(), this.duration_);\n }\n\n /**\n * Turn off the polyfill for `progress` events that was created in\n * {@link Tech#manualProgressOn}\n * Stop manually tracking progress events by clearing the interval that was set in\n * {@link Tech#trackProgress}.\n */\n stopTrackingProgress() {\n this.clearInterval(this.progressInterval);\n }\n\n /**\n * Polyfill the `timeupdate` event for browsers that don't support it.\n *\n * @see {@link Tech#trackCurrentTime}\n */\n manualTimeUpdatesOn() {\n this.manualTimeUpdates = true;\n this.on('play', this.trackCurrentTime_);\n this.on('pause', this.stopTrackingCurrentTime_);\n }\n\n /**\n * Turn off the polyfill for `timeupdate` events that was created in\n * {@link Tech#manualTimeUpdatesOn}\n */\n manualTimeUpdatesOff() {\n this.manualTimeUpdates = false;\n this.stopTrackingCurrentTime();\n this.off('play', this.trackCurrentTime_);\n this.off('pause', this.stopTrackingCurrentTime_);\n }\n\n /**\n * Sets up an interval function to track current time and trigger `timeupdate` every\n * 250 milliseconds.\n *\n * @listens Tech#play\n * @triggers Tech#timeupdate\n */\n trackCurrentTime() {\n if (this.currentTimeInterval) {\n this.stopTrackingCurrentTime();\n }\n this.currentTimeInterval = this.setInterval(function () {\n /**\n * Triggered at an interval of 250ms to indicated that time is passing in the video.\n *\n * @event Tech#timeupdate\n * @type {Event}\n */\n this.trigger({\n type: 'timeupdate',\n target: this,\n manuallyTriggered: true\n });\n\n // 42 = 24 fps // 250 is what Webkit uses // FF uses 15\n }, 250);\n }\n\n /**\n * Stop the interval function created in {@link Tech#trackCurrentTime} so that the\n * `timeupdate` event is no longer triggered.\n *\n * @listens {Tech#pause}\n */\n stopTrackingCurrentTime() {\n this.clearInterval(this.currentTimeInterval);\n\n // #1002 - if the video ends right before the next timeupdate would happen,\n // the progress bar won't make it all the way to the end\n this.trigger({\n type: 'timeupdate',\n target: this,\n manuallyTriggered: true\n });\n }\n\n /**\n * Turn off all event polyfills, clear the `Tech`s {@link AudioTrackList},\n * {@link VideoTrackList}, and {@link TextTrackList}, and dispose of this Tech.\n *\n * @fires Component#dispose\n */\n dispose() {\n // clear out all tracks because we can't reuse them between techs\n this.clearTracks(NORMAL.names);\n\n // Turn off any manual progress or timeupdate tracking\n if (this.manualProgress) {\n this.manualProgressOff();\n }\n if (this.manualTimeUpdates) {\n this.manualTimeUpdatesOff();\n }\n super.dispose();\n }\n\n /**\n * Clear out a single `TrackList` or an array of `TrackLists` given their names.\n *\n * > Note: Techs without source handlers should call this between sources for `video`\n * & `audio` tracks. You don't want to use them between tracks!\n *\n * @param {string[]|string} types\n * TrackList names to clear, valid names are `video`, `audio`, and\n * `text`.\n */\n clearTracks(types) {\n types = [].concat(types);\n // clear out all tracks because we can't reuse them between techs\n types.forEach(type => {\n const list = this[`${type}Tracks`]() || [];\n let i = list.length;\n while (i--) {\n const track = list[i];\n if (type === 'text') {\n this.removeRemoteTextTrack(track);\n }\n list.removeTrack(track);\n }\n });\n }\n\n /**\n * Remove any TextTracks added via addRemoteTextTrack that are\n * flagged for automatic garbage collection\n */\n cleanupAutoTextTracks() {\n const list = this.autoRemoteTextTracks_ || [];\n let i = list.length;\n while (i--) {\n const track = list[i];\n this.removeRemoteTextTrack(track);\n }\n }\n\n /**\n * Reset the tech, which will removes all sources and reset the internal readyState.\n *\n * @abstract\n */\n reset() {}\n\n /**\n * Get the value of `crossOrigin` from the tech.\n *\n * @abstract\n *\n * @see {Html5#crossOrigin}\n */\n crossOrigin() {}\n\n /**\n * Set the value of `crossOrigin` on the tech.\n *\n * @abstract\n *\n * @param {string} crossOrigin the crossOrigin value\n * @see {Html5#setCrossOrigin}\n */\n setCrossOrigin() {}\n\n /**\n * Get or set an error on the Tech.\n *\n * @param {MediaError} [err]\n * Error to set on the Tech\n *\n * @return {MediaError|null}\n * The current error object on the tech, or null if there isn't one.\n */\n error(err) {\n if (err !== undefined) {\n this.error_ = new MediaError(err);\n this.trigger('error');\n }\n return this.error_;\n }\n\n /**\n * Returns the `TimeRange`s that have been played through for the current source.\n *\n * > NOTE: This implementation is incomplete. It does not track the played `TimeRange`.\n * It only checks whether the source has played at all or not.\n *\n * @return {TimeRange}\n * - A single time range if this video has played\n * - An empty set of ranges if not.\n */\n played() {\n if (this.hasStarted_) {\n return createTimeRanges(0, 0);\n }\n return createTimeRanges();\n }\n\n /**\n * Start playback\n *\n * @abstract\n *\n * @see {Html5#play}\n */\n play() {}\n\n /**\n * Set whether we are scrubbing or not\n *\n * @abstract\n * @param {boolean} _isScrubbing\n * - true for we are currently scrubbing\n * - false for we are no longer scrubbing\n *\n * @see {Html5#setScrubbing}\n */\n setScrubbing(_isScrubbing) {}\n\n /**\n * Get whether we are scrubbing or not\n *\n * @abstract\n *\n * @see {Html5#scrubbing}\n */\n scrubbing() {}\n\n /**\n * Causes a manual time update to occur if {@link Tech#manualTimeUpdatesOn} was\n * previously called.\n *\n * @param {number} _seconds\n * Set the current time of the media to this.\n * @fires Tech#timeupdate\n */\n setCurrentTime(_seconds) {\n // improve the accuracy of manual timeupdates\n if (this.manualTimeUpdates) {\n /**\n * A manual `timeupdate` event.\n *\n * @event Tech#timeupdate\n * @type {Event}\n */\n this.trigger({\n type: 'timeupdate',\n target: this,\n manuallyTriggered: true\n });\n }\n }\n\n /**\n * Turn on listeners for {@link VideoTrackList}, {@link {AudioTrackList}, and\n * {@link TextTrackList} events.\n *\n * This adds {@link EventTarget~EventListeners} for `addtrack`, and `removetrack`.\n *\n * @fires Tech#audiotrackchange\n * @fires Tech#videotrackchange\n * @fires Tech#texttrackchange\n */\n initTrackListeners() {\n /**\n * Triggered when tracks are added or removed on the Tech {@link AudioTrackList}\n *\n * @event Tech#audiotrackchange\n * @type {Event}\n */\n\n /**\n * Triggered when tracks are added or removed on the Tech {@link VideoTrackList}\n *\n * @event Tech#videotrackchange\n * @type {Event}\n */\n\n /**\n * Triggered when tracks are added or removed on the Tech {@link TextTrackList}\n *\n * @event Tech#texttrackchange\n * @type {Event}\n */\n NORMAL.names.forEach(name => {\n const props = NORMAL[name];\n const trackListChanges = () => {\n this.trigger(`${name}trackchange`);\n };\n const tracks = this[props.getterName]();\n tracks.addEventListener('removetrack', trackListChanges);\n tracks.addEventListener('addtrack', trackListChanges);\n this.on('dispose', () => {\n tracks.removeEventListener('removetrack', trackListChanges);\n tracks.removeEventListener('addtrack', trackListChanges);\n });\n });\n }\n\n /**\n * Emulate TextTracks using vtt.js if necessary\n *\n * @fires Tech#vttjsloaded\n * @fires Tech#vttjserror\n */\n addWebVttScript_() {\n if (window.WebVTT) {\n return;\n }\n\n // Initially, Tech.el_ is a child of a dummy-div wait until the Component system\n // signals that the Tech is ready at which point Tech.el_ is part of the DOM\n // before inserting the WebVTT script\n if (document.body.contains(this.el())) {\n // load via require if available and vtt.js script location was not passed in\n // as an option. novtt builds will turn the above require call into an empty object\n // which will cause this if check to always fail.\n if (!this.options_['vtt.js'] && isPlain(browserIndex) && Object.keys(browserIndex).length > 0) {\n this.trigger('vttjsloaded');\n return;\n }\n\n // load vtt.js via the script location option or the cdn of no location was\n // passed in\n const script = document.createElement('script');\n script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.14.1/vtt.min.js';\n script.onload = () => {\n /**\n * Fired when vtt.js is loaded.\n *\n * @event Tech#vttjsloaded\n * @type {Event}\n */\n this.trigger('vttjsloaded');\n };\n script.onerror = () => {\n /**\n * Fired when vtt.js was not loaded due to an error\n *\n * @event Tech#vttjsloaded\n * @type {Event}\n */\n this.trigger('vttjserror');\n };\n this.on('dispose', () => {\n script.onload = null;\n script.onerror = null;\n });\n // but have not loaded yet and we set it to true before the inject so that\n // we don't overwrite the injected window.WebVTT if it loads right away\n window.WebVTT = true;\n this.el().parentNode.appendChild(script);\n } else {\n this.ready(this.addWebVttScript_);\n }\n }\n\n /**\n * Emulate texttracks\n *\n */\n emulateTextTracks() {\n const tracks = this.textTracks();\n const remoteTracks = this.remoteTextTracks();\n const handleAddTrack = e => tracks.addTrack(e.track);\n const handleRemoveTrack = e => tracks.removeTrack(e.track);\n remoteTracks.on('addtrack', handleAddTrack);\n remoteTracks.on('removetrack', handleRemoveTrack);\n this.addWebVttScript_();\n const updateDisplay = () => this.trigger('texttrackchange');\n const textTracksChanges = () => {\n updateDisplay();\n for (let i = 0; i < tracks.length; i++) {\n const track = tracks[i];\n track.removeEventListener('cuechange', updateDisplay);\n if (track.mode === 'showing') {\n track.addEventListener('cuechange', updateDisplay);\n }\n }\n };\n textTracksChanges();\n tracks.addEventListener('change', textTracksChanges);\n tracks.addEventListener('addtrack', textTracksChanges);\n tracks.addEventListener('removetrack', textTracksChanges);\n this.on('dispose', function () {\n remoteTracks.off('addtrack', handleAddTrack);\n remoteTracks.off('removetrack', handleRemoveTrack);\n tracks.removeEventListener('change', textTracksChanges);\n tracks.removeEventListener('addtrack', textTracksChanges);\n tracks.removeEventListener('removetrack', textTracksChanges);\n for (let i = 0; i < tracks.length; i++) {\n const track = tracks[i];\n track.removeEventListener('cuechange', updateDisplay);\n }\n });\n }\n\n /**\n * Create and returns a remote {@link TextTrack} object.\n *\n * @param {string} kind\n * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)\n *\n * @param {string} [label]\n * Label to identify the text track\n *\n * @param {string} [language]\n * Two letter language abbreviation\n *\n * @return {TextTrack}\n * The TextTrack that gets created.\n */\n addTextTrack(kind, label, language) {\n if (!kind) {\n throw new Error('TextTrack kind is required but was not provided');\n }\n return createTrackHelper(this, kind, label, language);\n }\n\n /**\n * Create an emulated TextTrack for use by addRemoteTextTrack\n *\n * This is intended to be overridden by classes that inherit from\n * Tech in order to create native or custom TextTracks.\n *\n * @param {Object} options\n * The object should contain the options to initialize the TextTrack with.\n *\n * @param {string} [options.kind]\n * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata).\n *\n * @param {string} [options.label].\n * Label to identify the text track\n *\n * @param {string} [options.language]\n * Two letter language abbreviation.\n *\n * @return {HTMLTrackElement}\n * The track element that gets created.\n */\n createRemoteTextTrack(options) {\n const track = merge(options, {\n tech: this\n });\n return new REMOTE.remoteTextEl.TrackClass(track);\n }\n\n /**\n * Creates a remote text track object and returns an html track element.\n *\n * > Note: This can be an emulated {@link HTMLTrackElement} or a native one.\n *\n * @param {Object} options\n * See {@link Tech#createRemoteTextTrack} for more detailed properties.\n *\n * @param {boolean} [manualCleanup=false]\n * - When false: the TextTrack will be automatically removed from the video\n * element whenever the source changes\n * - When True: The TextTrack will have to be cleaned up manually\n *\n * @return {HTMLTrackElement}\n * An Html Track Element.\n *\n */\n addRemoteTextTrack(options = {}, manualCleanup) {\n const htmlTrackElement = this.createRemoteTextTrack(options);\n if (typeof manualCleanup !== 'boolean') {\n manualCleanup = false;\n }\n\n // store HTMLTrackElement and TextTrack to remote list\n this.remoteTextTrackEls().addTrackElement_(htmlTrackElement);\n this.remoteTextTracks().addTrack(htmlTrackElement.track);\n if (manualCleanup === false) {\n // create the TextTrackList if it doesn't exist\n this.ready(() => this.autoRemoteTextTracks_.addTrack(htmlTrackElement.track));\n }\n return htmlTrackElement;\n }\n\n /**\n * Remove a remote text track from the remote `TextTrackList`.\n *\n * @param {TextTrack} track\n * `TextTrack` to remove from the `TextTrackList`\n */\n removeRemoteTextTrack(track) {\n const trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track);\n\n // remove HTMLTrackElement and TextTrack from remote list\n this.remoteTextTrackEls().removeTrackElement_(trackElement);\n this.remoteTextTracks().removeTrack(track);\n this.autoRemoteTextTracks_.removeTrack(track);\n }\n\n /**\n * Gets available media playback quality metrics as specified by the W3C's Media\n * Playback Quality API.\n *\n * @see [Spec]{@link https://wicg.github.io/media-playback-quality}\n *\n * @return {Object}\n * An object with supported media playback quality metrics\n *\n * @abstract\n */\n getVideoPlaybackQuality() {\n return {};\n }\n\n /**\n * Attempt to create a floating video window always on top of other windows\n * so that users may continue consuming media while they interact with other\n * content sites, or applications on their device.\n *\n * @see [Spec]{@link https://wicg.github.io/picture-in-picture}\n *\n * @return {Promise|undefined}\n * A promise with a Picture-in-Picture window if the browser supports\n * Promises (or one was passed in as an option). It returns undefined\n * otherwise.\n *\n * @abstract\n */\n requestPictureInPicture() {\n return Promise.reject();\n }\n\n /**\n * A method to check for the value of the 'disablePictureInPicture' <video> property.\n * Defaults to true, as it should be considered disabled if the tech does not support pip\n *\n * @abstract\n */\n disablePictureInPicture() {\n return true;\n }\n\n /**\n * A method to set or unset the 'disablePictureInPicture' <video> property.\n *\n * @abstract\n */\n setDisablePictureInPicture() {}\n\n /**\n * A fallback implementation of requestVideoFrameCallback using requestAnimationFrame\n *\n * @param {function} cb\n * @return {number} request id\n */\n requestVideoFrameCallback(cb) {\n const id = newGUID();\n if (!this.isReady_ || this.paused()) {\n this.queuedHanders_.add(id);\n this.one('playing', () => {\n if (this.queuedHanders_.has(id)) {\n this.queuedHanders_.delete(id);\n cb();\n }\n });\n } else {\n this.requestNamedAnimationFrame(id, cb);\n }\n return id;\n }\n\n /**\n * A fallback implementation of cancelVideoFrameCallback\n *\n * @param {number} id id of callback to be cancelled\n */\n cancelVideoFrameCallback(id) {\n if (this.queuedHanders_.has(id)) {\n this.queuedHanders_.delete(id);\n } else {\n this.cancelNamedAnimationFrame(id);\n }\n }\n\n /**\n * A method to set a poster from a `Tech`.\n *\n * @abstract\n */\n setPoster() {}\n\n /**\n * A method to check for the presence of the 'playsinline' <video> attribute.\n *\n * @abstract\n */\n playsinline() {}\n\n /**\n * A method to set or unset the 'playsinline' <video> attribute.\n *\n * @abstract\n */\n setPlaysinline() {}\n\n /**\n * Attempt to force override of native audio tracks.\n *\n * @param {boolean} override - If set to true native audio will be overridden,\n * otherwise native audio will potentially be used.\n *\n * @abstract\n */\n overrideNativeAudioTracks(override) {}\n\n /**\n * Attempt to force override of native video tracks.\n *\n * @param {boolean} override - If set to true native video will be overridden,\n * otherwise native video will potentially be used.\n *\n * @abstract\n */\n overrideNativeVideoTracks(override) {}\n\n /**\n * Check if the tech can support the given mime-type.\n *\n * The base tech does not support any type, but source handlers might\n * overwrite this.\n *\n * @param {string} _type\n * The mimetype to check for support\n *\n * @return {string}\n * 'probably', 'maybe', or empty string\n *\n * @see [Spec]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType}\n *\n * @abstract\n */\n canPlayType(_type) {\n return '';\n }\n\n /**\n * Check if the type is supported by this tech.\n *\n * The base tech does not support any type, but source handlers might\n * overwrite this.\n *\n * @param {string} _type\n * The media type to check\n * @return {string} Returns the native video element's response\n */\n static canPlayType(_type) {\n return '';\n }\n\n /**\n * Check if the tech can support the given source\n *\n * @param {Object} srcObj\n * The source object\n * @param {Object} options\n * The options passed to the tech\n * @return {string} 'probably', 'maybe', or '' (empty string)\n */\n static canPlaySource(srcObj, options) {\n return Tech.canPlayType(srcObj.type);\n }\n\n /*\n * Return whether the argument is a Tech or not.\n * Can be passed either a Class like `Html5` or a instance like `player.tech_`\n *\n * @param {Object} component\n * The item to check\n *\n * @return {boolean}\n * Whether it is a tech or not\n * - True if it is a tech\n * - False if it is not\n */\n static isTech(component) {\n return component.prototype instanceof Tech || component instanceof Tech || component === Tech;\n }\n\n /**\n * Registers a `Tech` into a shared list for videojs.\n *\n * @param {string} name\n * Name of the `Tech` to register.\n *\n * @param {Object} tech\n * The `Tech` class to register.\n */\n static registerTech(name, tech) {\n if (!Tech.techs_) {\n Tech.techs_ = {};\n }\n if (!Tech.isTech(tech)) {\n throw new Error(`Tech ${name} must be a Tech`);\n }\n if (!Tech.canPlayType) {\n throw new Error('Techs must have a static canPlayType method on them');\n }\n if (!Tech.canPlaySource) {\n throw new Error('Techs must have a static canPlaySource method on them');\n }\n name = toTitleCase(name);\n Tech.techs_[name] = tech;\n Tech.techs_[toLowerCase(name)] = tech;\n if (name !== 'Tech') {\n // camel case the techName for use in techOrder\n Tech.defaultTechOrder_.push(name);\n }\n return tech;\n }\n\n /**\n * Get a `Tech` from the shared list by name.\n *\n * @param {string} name\n * `camelCase` or `TitleCase` name of the Tech to get\n *\n * @return {Tech|undefined}\n * The `Tech` or undefined if there was no tech with the name requested.\n */\n static getTech(name) {\n if (!name) {\n return;\n }\n if (Tech.techs_ && Tech.techs_[name]) {\n return Tech.techs_[name];\n }\n name = toTitleCase(name);\n if (window && window.videojs && window.videojs[name]) {\n log.warn(`The ${name} tech was added to the videojs object when it should be registered using videojs.registerTech(name, tech)`);\n return window.videojs[name];\n }\n }\n }\n\n /**\n * Get the {@link VideoTrackList}\n *\n * @returns {VideoTrackList}\n * @method Tech.prototype.videoTracks\n */\n\n /**\n * Get the {@link AudioTrackList}\n *\n * @returns {AudioTrackList}\n * @method Tech.prototype.audioTracks\n */\n\n /**\n * Get the {@link TextTrackList}\n *\n * @returns {TextTrackList}\n * @method Tech.prototype.textTracks\n */\n\n /**\n * Get the remote element {@link TextTrackList}\n *\n * @returns {TextTrackList}\n * @method Tech.prototype.remoteTextTracks\n */\n\n /**\n * Get the remote element {@link HtmlTrackElementList}\n *\n * @returns {HtmlTrackElementList}\n * @method Tech.prototype.remoteTextTrackEls\n */\n\n ALL.names.forEach(function (name) {\n const props = ALL[name];\n Tech.prototype[props.getterName] = function () {\n this[props.privateName] = this[props.privateName] || new props.ListClass();\n return this[props.privateName];\n };\n });\n\n /**\n * List of associated text tracks\n *\n * @type {TextTrackList}\n * @private\n * @property Tech#textTracks_\n */\n\n /**\n * List of associated audio tracks.\n *\n * @type {AudioTrackList}\n * @private\n * @property Tech#audioTracks_\n */\n\n /**\n * List of associated video tracks.\n *\n * @type {VideoTrackList}\n * @private\n * @property Tech#videoTracks_\n */\n\n /**\n * Boolean indicating whether the `Tech` supports volume control.\n *\n * @type {boolean}\n * @default\n */\n Tech.prototype.featuresVolumeControl = true;\n\n /**\n * Boolean indicating whether the `Tech` supports muting volume.\n *\n * @type {boolean}\n * @default\n */\n Tech.prototype.featuresMuteControl = true;\n\n /**\n * Boolean indicating whether the `Tech` supports fullscreen resize control.\n * Resizing plugins using request fullscreen reloads the plugin\n *\n * @type {boolean}\n * @default\n */\n Tech.prototype.featuresFullscreenResize = false;\n\n /**\n * Boolean indicating whether the `Tech` supports changing the speed at which the video\n * plays. Examples:\n * - Set player to play 2x (twice) as fast\n * - Set player to play 0.5x (half) as fast\n *\n * @type {boolean}\n * @default\n */\n Tech.prototype.featuresPlaybackRate = false;\n\n /**\n * Boolean indicating whether the `Tech` supports the `progress` event.\n * This will be used to determine if {@link Tech#manualProgressOn} should be called.\n *\n * @type {boolean}\n * @default\n */\n Tech.prototype.featuresProgressEvents = false;\n\n /**\n * Boolean indicating whether the `Tech` supports the `sourceset` event.\n *\n * A tech should set this to `true` and then use {@link Tech#triggerSourceset}\n * to trigger a {@link Tech#event:sourceset} at the earliest time after getting\n * a new source.\n *\n * @type {boolean}\n * @default\n */\n Tech.prototype.featuresSourceset = false;\n\n /**\n * Boolean indicating whether the `Tech` supports the `timeupdate` event.\n * This will be used to determine if {@link Tech#manualTimeUpdates} should be called.\n *\n * @type {boolean}\n * @default\n */\n Tech.prototype.featuresTimeupdateEvents = false;\n\n /**\n * Boolean indicating whether the `Tech` supports the native `TextTrack`s.\n * This will help us integrate with native `TextTrack`s if the browser supports them.\n *\n * @type {boolean}\n * @default\n */\n Tech.prototype.featuresNativeTextTracks = false;\n\n /**\n * Boolean indicating whether the `Tech` supports `requestVideoFrameCallback`.\n *\n * @type {boolean}\n * @default\n */\n Tech.prototype.featuresVideoFrameCallback = false;\n\n /**\n * A functional mixin for techs that want to use the Source Handler pattern.\n * Source handlers are scripts for handling specific formats.\n * The source handler pattern is used for adaptive formats (HLS, DASH) that\n * manually load video data and feed it into a Source Buffer (Media Source Extensions)\n * Example: `Tech.withSourceHandlers.call(MyTech);`\n *\n * @param {Tech} _Tech\n * The tech to add source handler functions to.\n *\n * @mixes Tech~SourceHandlerAdditions\n */\n Tech.withSourceHandlers = function (_Tech) {\n /**\n * Register a source handler\n *\n * @param {Function} handler\n * The source handler class\n *\n * @param {number} [index]\n * Register it at the following index\n */\n _Tech.registerSourceHandler = function (handler, index) {\n let handlers = _Tech.sourceHandlers;\n if (!handlers) {\n handlers = _Tech.sourceHandlers = [];\n }\n if (index === undefined) {\n // add to the end of the list\n index = handlers.length;\n }\n handlers.splice(index, 0, handler);\n };\n\n /**\n * Check if the tech can support the given type. Also checks the\n * Techs sourceHandlers.\n *\n * @param {string} type\n * The mimetype to check.\n *\n * @return {string}\n * 'probably', 'maybe', or '' (empty string)\n */\n _Tech.canPlayType = function (type) {\n const handlers = _Tech.sourceHandlers || [];\n let can;\n for (let i = 0; i < handlers.length; i++) {\n can = handlers[i].canPlayType(type);\n if (can) {\n return can;\n }\n }\n return '';\n };\n\n /**\n * Returns the first source handler that supports the source.\n *\n * TODO: Answer question: should 'probably' be prioritized over 'maybe'\n *\n * @param {SourceObject} source\n * The source object\n *\n * @param {Object} options\n * The options passed to the tech\n *\n * @return {SourceHandler|null}\n * The first source handler that supports the source or null if\n * no SourceHandler supports the source\n */\n _Tech.selectSourceHandler = function (source, options) {\n const handlers = _Tech.sourceHandlers || [];\n let can;\n for (let i = 0; i < handlers.length; i++) {\n can = handlers[i].canHandleSource(source, options);\n if (can) {\n return handlers[i];\n }\n }\n return null;\n };\n\n /**\n * Check if the tech can support the given source.\n *\n * @param {SourceObject} srcObj\n * The source object\n *\n * @param {Object} options\n * The options passed to the tech\n *\n * @return {string}\n * 'probably', 'maybe', or '' (empty string)\n */\n _Tech.canPlaySource = function (srcObj, options) {\n const sh = _Tech.selectSourceHandler(srcObj, options);\n if (sh) {\n return sh.canHandleSource(srcObj, options);\n }\n return '';\n };\n\n /**\n * When using a source handler, prefer its implementation of\n * any function normally provided by the tech.\n */\n const deferrable = ['seekable', 'seeking', 'duration'];\n\n /**\n * A wrapper around {@link Tech#seekable} that will call a `SourceHandler`s seekable\n * function if it exists, with a fallback to the Techs seekable function.\n *\n * @method _Tech.seekable\n */\n\n /**\n * A wrapper around {@link Tech#duration} that will call a `SourceHandler`s duration\n * function if it exists, otherwise it will fallback to the techs duration function.\n *\n * @method _Tech.duration\n */\n\n deferrable.forEach(function (fnName) {\n const originalFn = this[fnName];\n if (typeof originalFn !== 'function') {\n return;\n }\n this[fnName] = function () {\n if (this.sourceHandler_ && this.sourceHandler_[fnName]) {\n return this.sourceHandler_[fnName].apply(this.sourceHandler_, arguments);\n }\n return originalFn.apply(this, arguments);\n };\n }, _Tech.prototype);\n\n /**\n * Create a function for setting the source using a source object\n * and source handlers.\n * Should never be called unless a source handler was found.\n *\n * @param {SourceObject} source\n * A source object with src and type keys\n */\n _Tech.prototype.setSource = function (source) {\n let sh = _Tech.selectSourceHandler(source, this.options_);\n if (!sh) {\n // Fall back to a native source handler when unsupported sources are\n // deliberately set\n if (_Tech.nativeSourceHandler) {\n sh = _Tech.nativeSourceHandler;\n } else {\n log.error('No source handler found for the current source.');\n }\n }\n\n // Dispose any existing source handler\n this.disposeSourceHandler();\n this.off('dispose', this.disposeSourceHandler_);\n if (sh !== _Tech.nativeSourceHandler) {\n this.currentSource_ = source;\n }\n this.sourceHandler_ = sh.handleSource(source, this, this.options_);\n this.one('dispose', this.disposeSourceHandler_);\n };\n\n /**\n * Clean up any existing SourceHandlers and listeners when the Tech is disposed.\n *\n * @listens Tech#dispose\n */\n _Tech.prototype.disposeSourceHandler = function () {\n // if we have a source and get another one\n // then we are loading something new\n // than clear all of our current tracks\n if (this.currentSource_) {\n this.clearTracks(['audio', 'video']);\n this.currentSource_ = null;\n }\n\n // always clean up auto-text tracks\n this.cleanupAutoTextTracks();\n if (this.sourceHandler_) {\n if (this.sourceHandler_.dispose) {\n this.sourceHandler_.dispose();\n }\n this.sourceHandler_ = null;\n }\n };\n };\n\n // The base Tech class needs to be registered as a Component. It is the only\n // Tech that can be registered as a Component.\n Component.registerComponent('Tech', Tech);\n Tech.registerTech('Tech', Tech);\n\n /**\n * A list of techs that should be added to techOrder on Players\n *\n * @private\n */\n Tech.defaultTechOrder_ = [];\n\n /**\n * @file middleware.js\n * @module middleware\n */\n\n /** @import Player from '../player' */\n /** @import Tech from '../tech/tech' */\n\n const middlewares = {};\n const middlewareInstances = {};\n const TERMINATOR = {};\n\n /**\n * A middleware object is a plain JavaScript object that has methods that\n * match the {@link Tech} methods found in the lists of allowed\n * {@link module:middleware.allowedGetters|getters},\n * {@link module:middleware.allowedSetters|setters}, and\n * {@link module:middleware.allowedMediators|mediators}.\n *\n * @typedef {Object} MiddlewareObject\n */\n\n /**\n * A middleware factory function that should return a\n * {@link module:middleware~MiddlewareObject|MiddlewareObject}.\n *\n * This factory will be called for each player when needed, with the player\n * passed in as an argument.\n *\n * @callback MiddlewareFactory\n * @param {Player} player\n * A Video.js player.\n */\n\n /**\n * Define a middleware that the player should use by way of a factory function\n * that returns a middleware object.\n *\n * @param {string} type\n * The MIME type to match or `\"*\"` for all MIME types.\n *\n * @param {MiddlewareFactory} middleware\n * A middleware factory function that will be executed for\n * matching types.\n */\n function use(type, middleware) {\n middlewares[type] = middlewares[type] || [];\n middlewares[type].push(middleware);\n }\n\n /**\n * Asynchronously sets a source using middleware by recursing through any\n * matching middlewares and calling `setSource` on each, passing along the\n * previous returned value each time.\n *\n * @param {Player} player\n * A {@link Player} instance.\n *\n * @param {Tech~SourceObject} src\n * A source object.\n *\n * @param {Function}\n * The next middleware to run.\n */\n function setSource(player, src, next) {\n player.setTimeout(() => setSourceHelper(src, middlewares[src.type], next, player), 1);\n }\n\n /**\n * When the tech is set, passes the tech to each middleware's `setTech` method.\n *\n * @param {Object[]} middleware\n * An array of middleware instances.\n *\n * @param {Tech} tech\n * A Video.js tech.\n */\n function setTech(middleware, tech) {\n middleware.forEach(mw => mw.setTech && mw.setTech(tech));\n }\n\n /**\n * Calls a getter on the tech first, through each middleware\n * from right to left to the player.\n *\n * @param {Object[]} middleware\n * An array of middleware instances.\n *\n * @param {Tech} tech\n * The current tech.\n *\n * @param {string} method\n * A method name.\n *\n * @return {*}\n * The final value from the tech after middleware has intercepted it.\n */\n function get(middleware, tech, method) {\n return middleware.reduceRight(middlewareIterator(method), tech[method]());\n }\n\n /**\n * Takes the argument given to the player and calls the setter method on each\n * middleware from left to right to the tech.\n *\n * @param {Object[]} middleware\n * An array of middleware instances.\n *\n * @param {Tech} tech\n * The current tech.\n *\n * @param {string} method\n * A method name.\n *\n * @param {*} arg\n * The value to set on the tech.\n *\n * @return {*}\n * The return value of the `method` of the `tech`.\n */\n function set(middleware, tech, method, arg) {\n return tech[method](middleware.reduce(middlewareIterator(method), arg));\n }\n\n /**\n * Takes the argument given to the player and calls the `call` version of the\n * method on each middleware from left to right.\n *\n * Then, call the passed in method on the tech and return the result unchanged\n * back to the player, through middleware, this time from right to left.\n *\n * @param {Object[]} middleware\n * An array of middleware instances.\n *\n * @param {Tech} tech\n * The current tech.\n *\n * @param {string} method\n * A method name.\n *\n * @param {*} arg\n * The value to set on the tech.\n *\n * @return {*}\n * The return value of the `method` of the `tech`, regardless of the\n * return values of middlewares.\n */\n function mediate(middleware, tech, method, arg = null) {\n const callMethod = 'call' + toTitleCase(method);\n const middlewareValue = middleware.reduce(middlewareIterator(callMethod), arg);\n const terminated = middlewareValue === TERMINATOR;\n // deprecated. The `null` return value should instead return TERMINATOR to\n // prevent confusion if a techs method actually returns null.\n const returnValue = terminated ? null : tech[method](middlewareValue);\n executeRight(middleware, method, returnValue, terminated);\n return returnValue;\n }\n\n /**\n * Enumeration of allowed getters where the keys are method names.\n *\n * @type {Object}\n */\n const allowedGetters = {\n buffered: 1,\n currentTime: 1,\n duration: 1,\n muted: 1,\n played: 1,\n paused: 1,\n seekable: 1,\n volume: 1,\n ended: 1\n };\n\n /**\n * Enumeration of allowed setters where the keys are method names.\n *\n * @type {Object}\n */\n const allowedSetters = {\n setCurrentTime: 1,\n setMuted: 1,\n setVolume: 1\n };\n\n /**\n * Enumeration of allowed mediators where the keys are method names.\n *\n * @type {Object}\n */\n const allowedMediators = {\n play: 1,\n pause: 1\n };\n function middlewareIterator(method) {\n return (value, mw) => {\n // if the previous middleware terminated, pass along the termination\n if (value === TERMINATOR) {\n return TERMINATOR;\n }\n if (mw[method]) {\n return mw[method](value);\n }\n return value;\n };\n }\n function executeRight(mws, method, value, terminated) {\n for (let i = mws.length - 1; i >= 0; i--) {\n const mw = mws[i];\n if (mw[method]) {\n mw[method](terminated, value);\n }\n }\n }\n\n /**\n * Clear the middleware cache for a player.\n *\n * @param {Player} player\n * A {@link Player} instance.\n */\n function clearCacheForPlayer(player) {\n if (middlewareInstances.hasOwnProperty(player.id())) {\n delete middlewareInstances[player.id()];\n }\n }\n\n /**\n * {\n * [playerId]: [[mwFactory, mwInstance], ...]\n * }\n *\n * @private\n */\n function getOrCreateFactory(player, mwFactory) {\n const mws = middlewareInstances[player.id()];\n let mw = null;\n if (mws === undefined || mws === null) {\n mw = mwFactory(player);\n middlewareInstances[player.id()] = [[mwFactory, mw]];\n return mw;\n }\n for (let i = 0; i < mws.length; i++) {\n const [mwf, mwi] = mws[i];\n if (mwf !== mwFactory) {\n continue;\n }\n mw = mwi;\n }\n if (mw === null) {\n mw = mwFactory(player);\n mws.push([mwFactory, mw]);\n }\n return mw;\n }\n function setSourceHelper(src = {}, middleware = [], next, player, acc = [], lastRun = false) {\n const [mwFactory, ...mwrest] = middleware;\n\n // if mwFactory is a string, then we're at a fork in the road\n if (typeof mwFactory === 'string') {\n setSourceHelper(src, middlewares[mwFactory], next, player, acc, lastRun);\n\n // if we have an mwFactory, call it with the player to get the mw,\n // then call the mw's setSource method\n } else if (mwFactory) {\n const mw = getOrCreateFactory(player, mwFactory);\n\n // if setSource isn't present, implicitly select this middleware\n if (!mw.setSource) {\n acc.push(mw);\n return setSourceHelper(src, mwrest, next, player, acc, lastRun);\n }\n mw.setSource(Object.assign({}, src), function (err, _src) {\n // something happened, try the next middleware on the current level\n // make sure to use the old src\n if (err) {\n return setSourceHelper(src, mwrest, next, player, acc, lastRun);\n }\n\n // we've succeeded, now we need to go deeper\n acc.push(mw);\n\n // if it's the same type, continue down the current chain\n // otherwise, we want to go down the new chain\n setSourceHelper(_src, src.type === _src.type ? mwrest : middlewares[_src.type], next, player, acc, lastRun);\n });\n } else if (mwrest.length) {\n setSourceHelper(src, mwrest, next, player, acc, lastRun);\n } else if (lastRun) {\n next(src, acc);\n } else {\n setSourceHelper(src, middlewares['*'], next, player, acc, true);\n }\n }\n\n /** @import Player from '../player' */\n\n /**\n * Mimetypes\n *\n * @see https://www.iana.org/assignments/media-types/media-types.xhtml\n * @typedef Mimetypes~Kind\n * @enum\n */\n const MimetypesKind = {\n opus: 'video/ogg',\n ogv: 'video/ogg',\n mp4: 'video/mp4',\n mov: 'video/mp4',\n m4v: 'video/mp4',\n mkv: 'video/x-matroska',\n m4a: 'audio/mp4',\n mp3: 'audio/mpeg',\n aac: 'audio/aac',\n caf: 'audio/x-caf',\n flac: 'audio/flac',\n oga: 'audio/ogg',\n wav: 'audio/wav',\n m3u8: 'application/x-mpegURL',\n mpd: 'application/dash+xml',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n png: 'image/png',\n svg: 'image/svg+xml',\n webp: 'image/webp'\n };\n\n /**\n * Get the mimetype of a given src url if possible\n *\n * @param {string} src\n * The url to the src\n *\n * @return {string}\n * return the mimetype if it was known or empty string otherwise\n */\n const getMimetype = function (src = '') {\n const ext = getFileExtension(src);\n const mimetype = MimetypesKind[ext.toLowerCase()];\n return mimetype || '';\n };\n\n /**\n * Find the mime type of a given source string if possible. Uses the player\n * source cache.\n *\n * @param {Player} player\n * The player object\n *\n * @param {string} src\n * The source string\n *\n * @return {string}\n * The type that was found\n */\n const findMimetype = (player, src) => {\n if (!src) {\n return '';\n }\n\n // 1. check for the type in the `source` cache\n if (player.cache_.source.src === src && player.cache_.source.type) {\n return player.cache_.source.type;\n }\n\n // 2. see if we have this source in our `currentSources` cache\n const matchingSources = player.cache_.sources.filter(s => s.src === src);\n if (matchingSources.length) {\n return matchingSources[0].type;\n }\n\n // 3. look for the src url in source elements and use the type there\n const sources = player.$$('source');\n for (let i = 0; i < sources.length; i++) {\n const s = sources[i];\n if (s.type && s.src && s.src === src) {\n return s.type;\n }\n }\n\n // 4. finally fallback to our list of mime types based on src url extension\n return getMimetype(src);\n };\n\n /**\n * @module filter-source\n */\n\n /**\n * Filter out single bad source objects or multiple source objects in an\n * array. Also flattens nested source object arrays into a 1 dimensional\n * array of source objects.\n *\n * @param {Tech~SourceObject|Tech~SourceObject[]} src\n * The src object to filter\n *\n * @return {Tech~SourceObject[]}\n * An array of sourceobjects containing only valid sources\n *\n * @private\n */\n const filterSource = function (src) {\n // traverse array\n if (Array.isArray(src)) {\n let newsrc = [];\n src.forEach(function (srcobj) {\n srcobj = filterSource(srcobj);\n if (Array.isArray(srcobj)) {\n newsrc = newsrc.concat(srcobj);\n } else if (isObject(srcobj)) {\n newsrc.push(srcobj);\n }\n });\n src = newsrc;\n } else if (typeof src === 'string' && src.trim()) {\n // convert string into object\n src = [fixSource({\n src\n })];\n } else if (isObject(src) && typeof src.src === 'string' && src.src && src.src.trim()) {\n // src is already valid\n src = [fixSource(src)];\n } else {\n // invalid source, turn it into an empty array\n src = [];\n }\n return src;\n };\n\n /**\n * Checks src mimetype, adding it when possible\n *\n * @param {Tech~SourceObject} src\n * The src object to check\n * @return {Tech~SourceObject}\n * src Object with known type\n */\n function fixSource(src) {\n if (!src.type) {\n const mimetype = getMimetype(src.src);\n if (mimetype) {\n src.type = mimetype;\n }\n }\n return src;\n }\n\n var icons = \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n <defs>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-play\\\">\\n <path d=\\\"M16 10v28l22-14z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-pause\\\">\\n <path d=\\\"M12 38h8V10h-8v28zm16-28v28h8V10h-8z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-audio\\\">\\n <path d=\\\"M24 2C14.06 2 6 10.06 6 20v14c0 3.31 2.69 6 6 6h6V24h-8v-4c0-7.73 6.27-14 14-14s14 6.27 14 14v4h-8v16h6c3.31 0 6-2.69 6-6V20c0-9.94-8.06-18-18-18z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-captions\\\">\\n <path d=\\\"M38 8H10c-2.21 0-4 1.79-4 4v24c0 2.21 1.79 4 4 4h28c2.21 0 4-1.79 4-4V12c0-2.21-1.79-4-4-4zM22 22h-3v-1h-4v6h4v-1h3v2a2 2 0 0 1-2 2h-6a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v2zm14 0h-3v-1h-4v6h4v-1h3v2a2 2 0 0 1-2 2h-6a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v2z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-subtitles\\\">\\n <path d=\\\"M40 8H8c-2.21 0-4 1.79-4 4v24c0 2.21 1.79 4 4 4h32c2.21 0 4-1.79 4-4V12c0-2.21-1.79-4-4-4zM8 24h8v4H8v-4zm20 12H8v-4h20v4zm12 0h-8v-4h8v4zm0-8H20v-4h20v4z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-fullscreen-enter\\\">\\n <path d=\\\"M14 28h-4v10h10v-4h-6v-6zm-4-8h4v-6h6v-4H10v10zm24 14h-6v4h10V28h-4v6zm-6-24v4h6v6h4V10H28z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-fullscreen-exit\\\">\\n <path d=\\\"M10 32h6v6h4V28H10v4zm6-16h-6v4h10V10h-4v6zm12 22h4v-6h6v-4H28v10zm4-22v-6h-4v10h10v-4h-6z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-play-circle\\\">\\n <path d=\\\"M20 33l12-9-12-9v18zm4-29C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm0 36c-8.82 0-16-7.18-16-16S15.18 8 24 8s16 7.18 16 16-7.18 16-16 16z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-volume-mute\\\">\\n <path d=\\\"M33 24c0-3.53-2.04-6.58-5-8.05v4.42l4.91 4.91c.06-.42.09-.85.09-1.28zm5 0c0 1.88-.41 3.65-1.08 5.28l3.03 3.03C41.25 29.82 42 27 42 24c0-8.56-5.99-15.72-14-17.54v4.13c5.78 1.72 10 7.07 10 13.41zM8.55 6L6 8.55 15.45 18H6v12h8l10 10V26.55l8.51 8.51c-1.34 1.03-2.85 1.86-4.51 2.36v4.13a17.94 17.94 0 0 0 7.37-3.62L39.45 42 42 39.45l-18-18L8.55 6zM24 8l-4.18 4.18L24 16.36V8z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-volume-low\\\">\\n <path d=\\\"M14 18v12h8l10 10V8L22 18h-8z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-volume-medium\\\">\\n <path d=\\\"M37 24c0-3.53-2.04-6.58-5-8.05v16.11c2.96-1.48 5-4.53 5-8.06zm-27-6v12h8l10 10V8L18 18h-8z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-volume-high\\\">\\n <path d=\\\"M6 18v12h8l10 10V8L14 18H6zm27 6c0-3.53-2.04-6.58-5-8.05v16.11c2.96-1.48 5-4.53 5-8.06zM28 6.46v4.13c5.78 1.72 10 7.07 10 13.41s-4.22 11.69-10 13.41v4.13c8.01-1.82 14-8.97 14-17.54S36.01 8.28 28 6.46z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-spinner\\\">\\n <path d=\\\"M18.8 21l9.53-16.51C26.94 4.18 25.49 4 24 4c-4.8 0-9.19 1.69-12.64 4.51l7.33 12.69.11-.2zm24.28-3c-1.84-5.85-6.3-10.52-11.99-12.68L23.77 18h19.31zm.52 2H28.62l.58 1 9.53 16.5C41.99 33.94 44 29.21 44 24c0-1.37-.14-2.71-.4-4zm-26.53 4l-7.8-13.5C6.01 14.06 4 18.79 4 24c0 1.37.14 2.71.4 4h14.98l-2.31-4zM4.92 30c1.84 5.85 6.3 10.52 11.99 12.68L24.23 30H4.92zm22.54 0l-7.8 13.51c1.4.31 2.85.49 4.34.49 4.8 0 9.19-1.69 12.64-4.51L29.31 26.8 27.46 30z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 24 24\\\" id=\\\"vjs-icon-hd\\\">\\n <path d=\\\"M19 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-8 12H9.5v-2h-2v2H6V9h1.5v2.5h2V9H11v6zm2-6h4c.55 0 1 .45 1 1v4c0 .55-.45 1-1 1h-4V9zm1.5 4.5h2v-3h-2v3z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-chapters\\\">\\n <path d=\\\"M6 26h4v-4H6v4zm0 8h4v-4H6v4zm0-16h4v-4H6v4zm8 8h28v-4H14v4zm0 8h28v-4H14v4zm0-20v4h28v-4H14z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 40 40\\\" id=\\\"vjs-icon-downloading\\\">\\n <path d=\\\"M18.208 36.875q-3.208-.292-5.979-1.729-2.771-1.438-4.812-3.729-2.042-2.292-3.188-5.229-1.146-2.938-1.146-6.23 0-6.583 4.334-11.416 4.333-4.834 10.833-5.5v3.166q-5.167.75-8.583 4.646Q6.25 14.75 6.25 19.958q0 5.209 3.396 9.104 3.396 3.896 8.562 4.646zM20 28.417L11.542 20l2.083-2.083 4.917 4.916v-11.25h2.916v11.25l4.875-4.916L28.417 20zm1.792 8.458v-3.167q1.833-.25 3.541-.958 1.709-.708 3.167-1.875l2.333 2.292q-1.958 1.583-4.25 2.541-2.291.959-4.791 1.167zm6.791-27.792q-1.541-1.125-3.25-1.854-1.708-.729-3.541-1.021V3.042q2.5.25 4.77 1.208 2.271.958 4.271 2.5zm4.584 21.584l-2.25-2.25q1.166-1.5 1.854-3.209.687-1.708.937-3.541h3.209q-.292 2.5-1.229 4.791-.938 2.292-2.521 4.209zm.541-12.417q-.291-1.833-.958-3.562-.667-1.73-1.833-3.188l2.375-2.208q1.541 1.916 2.458 4.208.917 2.292 1.167 4.75z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-file-download\\\">\\n <path d=\\\"M10.8 40.55q-1.35 0-2.375-1T7.4 37.15v-7.7h3.4v7.7h26.35v-7.7h3.4v7.7q0 1.4-1 2.4t-2.4 1zM24 32.1L13.9 22.05l2.45-2.45 5.95 5.95V7.15h3.4v18.4l5.95-5.95 2.45 2.45z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-file-download-done\\\">\\n <path d=\\\"M9.8 40.5v-3.45h28.4v3.45zm9.2-9.05L7.4 19.85l2.45-2.35L19 26.65l19.2-19.2 2.4 2.4z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-file-download-off\\\">\\n <path d=\\\"M4.9 4.75L43.25 43.1 41 45.3l-4.75-4.75q-.05.05-.075.025-.025-.025-.075-.025H10.8q-1.35 0-2.375-1T7.4 37.15v-7.7h3.4v7.7h22.05l-7-7-1.85 1.8L13.9 21.9l1.85-1.85L2.7 7zm26.75 14.7l2.45 2.45-3.75 3.8-2.45-2.5zM25.7 7.15V21.1l-3.4-3.45V7.15z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-share\\\">\\n <path d=\\\"M36 32.17c-1.52 0-2.89.59-3.93 1.54L17.82 25.4c.11-.45.18-.92.18-1.4s-.07-.95-.18-1.4l14.1-8.23c1.07 1 2.5 1.62 4.08 1.62 3.31 0 6-2.69 6-6s-2.69-6-6-6-6 2.69-6 6c0 .48.07.95.18 1.4l-14.1 8.23c-1.07-1-2.5-1.62-4.08-1.62-3.31 0-6 2.69-6 6s2.69 6 6 6c1.58 0 3.01-.62 4.08-1.62l14.25 8.31c-.1.42-.16.86-.16 1.31A5.83 5.83 0 1 0 36 32.17z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-cog\\\">\\n <path d=\\\"M38.86 25.95c.08-.64.14-1.29.14-1.95s-.06-1.31-.14-1.95l4.23-3.31c.38-.3.49-.84.24-1.28l-4-6.93c-.25-.43-.77-.61-1.22-.43l-4.98 2.01c-1.03-.79-2.16-1.46-3.38-1.97L29 4.84c-.09-.47-.5-.84-1-.84h-8c-.5 0-.91.37-.99.84l-.75 5.3a14.8 14.8 0 0 0-3.38 1.97L9.9 10.1a1 1 0 0 0-1.22.43l-4 6.93c-.25.43-.14.97.24 1.28l4.22 3.31C9.06 22.69 9 23.34 9 24s.06 1.31.14 1.95l-4.22 3.31c-.38.3-.49.84-.24 1.28l4 6.93c.25.43.77.61 1.22.43l4.98-2.01c1.03.79 2.16 1.46 3.38 1.97l.75 5.3c.08.47.49.84.99.84h8c.5 0 .91-.37.99-.84l.75-5.3a14.8 14.8 0 0 0 3.38-1.97l4.98 2.01a1 1 0 0 0 1.22-.43l4-6.93c.25-.43.14-.97-.24-1.28l-4.22-3.31zM24 31c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-square\\\">\\n <path d=\\\"M36 8H12c-2.21 0-4 1.79-4 4v24c0 2.21 1.79 4 4 4h24c2.21 0 4-1.79 4-4V12c0-2.21-1.79-4-4-4zm0 28H12V12h24v24z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-circle\\\">\\n <circle cx=\\\"24\\\" cy=\\\"24\\\" r=\\\"20\\\"></circle>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-circle-outline\\\">\\n <path d=\\\"M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm0 36c-8.82 0-16-7.18-16-16S15.18 8 24 8s16 7.18 16 16-7.18 16-16 16z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-circle-inner-circle\\\">\\n <path d=\\\"M24 4C12.97 4 4 12.97 4 24s8.97 20 20 20 20-8.97 20-20S35.03 4 24 4zm0 36c-8.82 0-16-7.18-16-16S15.18 8 24 8s16 7.18 16 16-7.18 16-16 16zm6-16c0 3.31-2.69 6-6 6s-6-2.69-6-6 2.69-6 6-6 6 2.69 6 6z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-cancel\\\">\\n <path d=\\\"M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm10 27.17L31.17 34 24 26.83 16.83 34 14 31.17 21.17 24 14 16.83 16.83 14 24 21.17 31.17 14 34 16.83 26.83 24 34 31.17z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-replay\\\">\\n <path d=\\\"M24 10V2L14 12l10 10v-8c6.63 0 12 5.37 12 12s-5.37 12-12 12-12-5.37-12-12H8c0 8.84 7.16 16 16 16s16-7.16 16-16-7.16-16-16-16z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-repeat\\\">\\n <path d=\\\"M14 14h20v6l8-8-8-8v6H10v12h4v-8zm20 20H14v-6l-8 8 8 8v-6h24V26h-4v8z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 96 48 48\\\" id=\\\"vjs-icon-replay-5\\\">\\n <path d=\\\"M17.689 98l-8.697 8.696 8.697 8.697 2.486-2.485-4.32-4.319h1.302c4.93 0 9.071 1.722 12.424 5.165 3.352 3.443 5.029 7.638 5.029 12.584h3.55c0-2.958-.553-5.73-1.658-8.313-1.104-2.583-2.622-4.841-4.555-6.774-1.932-1.932-4.19-3.45-6.773-4.555-2.584-1.104-5.355-1.657-8.313-1.657H15.5l4.615-4.615zm-8.08 21.659v13.861h11.357v5.008H9.609V143h12.7c.834 0 1.55-.298 2.146-.894.596-.597.895-1.31.895-2.145v-7.781c0-.835-.299-1.55-.895-2.147a2.929 2.929 0 0 0-2.147-.894h-8.227v-5.096H25.35v-4.384z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 96 48 48\\\" id=\\\"vjs-icon-replay-10\\\">\\n <path d=\\\"M42.315 125.63c0-4.997-1.694-9.235-5.08-12.713-3.388-3.479-7.571-5.218-12.552-5.218h-1.315l4.363 4.363-2.51 2.51-8.787-8.786L25.221 97l2.45 2.45-4.662 4.663h1.375c2.988 0 5.788.557 8.397 1.673 2.61 1.116 4.892 2.65 6.844 4.602 1.953 1.953 3.487 4.234 4.602 6.844 1.116 2.61 1.674 5.41 1.674 8.398zM8.183 142v-19.657H3.176V117.8h9.643V142zm13.63 0c-1.156 0-2.127-.393-2.912-1.178-.778-.778-1.168-1.746-1.168-2.902v-16.04c0-1.156.393-2.127 1.178-2.912.779-.779 1.746-1.168 2.902-1.168h7.696c1.156 0 2.126.392 2.911 1.177.779.78 1.168 1.747 1.168 2.903v16.04c0 1.156-.392 2.127-1.177 2.912-.779.779-1.746 1.168-2.902 1.168zm.556-4.636h6.583v-15.02H22.37z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 96 48 48\\\" id=\\\"vjs-icon-replay-30\\\">\\n <path d=\\\"M26.047 97l-8.733 8.732 8.733 8.733 2.496-2.494-4.336-4.338h1.307c4.95 0 9.108 1.73 12.474 5.187 3.367 3.458 5.051 7.668 5.051 12.635h3.565c0-2.97-.556-5.751-1.665-8.346-1.109-2.594-2.633-4.862-4.574-6.802-1.94-1.941-4.208-3.466-6.803-4.575-2.594-1.109-5.375-1.664-8.345-1.664H23.85l4.634-4.634zM2.555 117.531v4.688h10.297v5.25H5.873v4.687h6.979v5.156H2.555V142H13.36c1.061 0 1.95-.395 2.668-1.186.718-.79 1.076-1.772 1.076-2.94v-16.218c0-1.168-.358-2.149-1.076-2.94-.717-.79-1.607-1.185-2.668-1.185zm22.482.14c-1.149 0-2.11.39-2.885 1.165-.78.78-1.172 1.744-1.172 2.893v15.943c0 1.149.388 2.11 1.163 2.885.78.78 1.745 1.172 2.894 1.172h7.649c1.148 0 2.11-.388 2.884-1.163.78-.78 1.17-1.745 1.17-2.894v-15.943c0-1.15-.386-2.111-1.16-2.885-.78-.78-1.746-1.172-2.894-1.172zm.553 4.518h6.545v14.93H25.59z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 96 48 48\\\" id=\\\"vjs-icon-forward-5\\\">\\n <path d=\\\"M29.508 97l-2.431 2.43 4.625 4.625h-1.364c-2.965 0-5.742.554-8.332 1.66-2.589 1.107-4.851 2.629-6.788 4.566-1.937 1.937-3.458 4.2-4.565 6.788-1.107 2.59-1.66 5.367-1.66 8.331h3.557c0-4.957 1.68-9.16 5.04-12.611 3.36-3.45 7.51-5.177 12.451-5.177h1.304l-4.326 4.33 2.49 2.49 8.715-8.716zm-9.783 21.61v13.89h11.382v5.018H19.725V142h12.727a2.93 2.93 0 0 0 2.15-.896 2.93 2.93 0 0 0 .896-2.15v-7.798c0-.837-.299-1.554-.896-2.152a2.93 2.93 0 0 0-2.15-.896h-8.245V123h11.29v-4.392z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 96 48 48\\\" id=\\\"vjs-icon-forward-10\\\">\\n <path d=\\\"M23.119 97l-2.386 2.383 4.538 4.538h-1.339c-2.908 0-5.633.543-8.173 1.63-2.54 1.085-4.76 2.577-6.66 4.478-1.9 1.9-3.392 4.12-4.478 6.66-1.085 2.54-1.629 5.264-1.629 8.172h3.49c0-4.863 1.648-8.986 4.944-12.372 3.297-3.385 7.368-5.078 12.216-5.078h1.279l-4.245 4.247 2.443 2.442 8.55-8.55zm-9.52 21.45v4.42h4.871V142h4.513v-23.55zm18.136 0c-1.125 0-2.066.377-2.824 1.135-.764.764-1.148 1.709-1.148 2.834v15.612c0 1.124.38 2.066 1.139 2.824.764.764 1.708 1.145 2.833 1.145h7.489c1.125 0 2.066-.378 2.824-1.136.764-.764 1.145-1.709 1.145-2.833v-15.612c0-1.125-.378-2.067-1.136-2.825-.764-.764-1.708-1.145-2.833-1.145zm.54 4.42h6.408v14.617h-6.407z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 96 48 48\\\" id=\\\"vjs-icon-forward-30\\\">\\n <path d=\\\"M25.549 97l-2.437 2.434 4.634 4.635H26.38c-2.97 0-5.753.555-8.347 1.664-2.594 1.109-4.861 2.633-6.802 4.574-1.94 1.94-3.465 4.207-4.574 6.802-1.109 2.594-1.664 5.377-1.664 8.347h3.565c0-4.967 1.683-9.178 5.05-12.636 3.366-3.458 7.525-5.187 12.475-5.187h1.307l-4.335 4.338 2.495 2.494 8.732-8.732zm-11.553 20.53v4.689h10.297v5.249h-6.978v4.688h6.978v5.156H13.996V142h10.808c1.06 0 1.948-.395 2.666-1.186.718-.79 1.077-1.771 1.077-2.94v-16.217c0-1.169-.36-2.15-1.077-2.94-.718-.79-1.605-1.186-2.666-1.186zm21.174.168c-1.149 0-2.11.389-2.884 1.163-.78.78-1.172 1.745-1.172 2.894v15.942c0 1.15.388 2.11 1.162 2.885.78.78 1.745 1.17 2.894 1.17h7.649c1.149 0 2.11-.386 2.885-1.16.78-.78 1.17-1.746 1.17-2.895v-15.942c0-1.15-.387-2.11-1.161-2.885-.78-.78-1.745-1.172-2.894-1.172zm.552 4.516h6.542v14.931h-6.542z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 512 512\\\" id=\\\"vjs-icon-audio-description\\\">\\n <g fill-rule=\\\"evenodd\\\"><path d=\\\"M227.29 381.351V162.993c50.38-1.017 89.108-3.028 117.631 17.126 27.374 19.342 48.734 56.965 44.89 105.325-4.067 51.155-41.335 94.139-89.776 98.475-24.085 2.155-71.972 0-71.972 0s-.84-1.352-.773-2.568m48.755-54.804c31.43 1.26 53.208-16.633 56.495-45.386 4.403-38.51-21.188-63.552-58.041-60.796v103.612c-.036 1.466.575 2.22 1.546 2.57\\\"></path><path d=\\\"M383.78 381.328c13.336 3.71 17.387-11.06 23.215-21.408 12.722-22.571 22.294-51.594 22.445-84.774.221-47.594-18.343-82.517-35.6-106.182h-8.51c-.587 3.874 2.226 7.315 3.865 10.276 13.166 23.762 25.367 56.553 25.54 94.194.2 43.176-14.162 79.278-30.955 107.894\\\"></path><path d=\\\"M425.154 381.328c13.336 3.71 17.384-11.061 23.215-21.408 12.721-22.571 22.291-51.594 22.445-84.774.221-47.594-18.343-82.517-35.6-106.182h-8.511c-.586 3.874 2.226 7.315 3.866 10.276 13.166 23.762 25.367 56.553 25.54 94.194.2 43.176-14.162 79.278-30.955 107.894\\\"></path><path d=\\\"M466.26 381.328c13.337 3.71 17.385-11.061 23.216-21.408 12.722-22.571 22.292-51.594 22.445-84.774.221-47.594-18.343-82.517-35.6-106.182h-8.51c-.587 3.874 2.225 7.315 3.865 10.276 13.166 23.762 25.367 56.553 25.54 94.194.2 43.176-14.162 79.278-30.955 107.894M4.477 383.005H72.58l18.573-28.484 64.169-.135s.065 19.413.065 28.62h48.756V160.307h-58.816c-5.653 9.537-140.85 222.697-140.85 222.697zm152.667-145.282v71.158l-40.453-.27 40.453-70.888z\\\"></path></g>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-next-item\\\">\\n <path d=\\\"M12 36l17-12-17-12v24zm20-24v24h4V12h-4z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-previous-item\\\">\\n <path d=\\\"M12 12h4v24h-4zm7 12l17 12V12z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-shuffle\\\">\\n <path d=\\\"M21.17 18.34L10.83 8 8 10.83l10.34 10.34 2.83-2.83zM29 8l4.09 4.09L8 37.17 10.83 40l25.09-25.09L40 19V8H29zm.66 18.83l-2.83 2.83 6.26 6.26L29 40h11V29l-4.09 4.09-6.25-6.26z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-cast\\\">\\n <path d=\\\"M42 6H6c-2.21 0-4 1.79-4 4v6h4v-6h36v28H28v4h14c2.21 0 4-1.79 4-4V10c0-2.21-1.79-4-4-4zM2 36v6h6c0-3.31-2.69-6-6-6zm0-8v4c5.52 0 10 4.48 10 10h4c0-7.73-6.27-14-14-14zm0-8v4c9.94 0 18 8.06 18 18h4c0-12.15-9.85-22-22-22z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 48 48\\\" id=\\\"vjs-icon-picture-in-picture-enter\\\">\\n <path d=\\\"M38 22H22v11.99h16V22zm8 16V9.96C46 7.76 44.2 6 42 6H6C3.8 6 2 7.76 2 9.96V38c0 2.2 1.8 4 4 4h36c2.2 0 4-1.8 4-4zm-4 .04H6V9.94h36v28.1z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 22 18\\\" id=\\\"vjs-icon-picture-in-picture-exit\\\">\\n <path d=\\\"M18 4H4v10h14V4zm4 12V1.98C22 .88 21.1 0 20 0H2C.9 0 0 .88 0 1.98V16c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2zm-2 .02H2V1.97h18v14.05z\\\"></path>\\n <path fill=\\\"none\\\" d=\\\"M-1-3h24v24H-1z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 1792 1792\\\" id=\\\"vjs-icon-facebook\\\">\\n <path d=\\\"M1343 12v264h-157q-86 0-116 36t-30 108v189h293l-39 296h-254v759H734V905H479V609h255V391q0-186 104-288.5T1115 0q147 0 228 12z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 1792 1792\\\" id=\\\"vjs-icon-linkedin\\\">\\n <path d=\\\"M477 625v991H147V625h330zm21-306q1 73-50.5 122T312 490h-2q-82 0-132-49t-50-122q0-74 51.5-122.5T314 148t133 48.5T498 319zm1166 729v568h-329v-530q0-105-40.5-164.5T1168 862q-63 0-105.5 34.5T999 982q-11 30-11 81v553H659q2-399 2-647t-1-296l-1-48h329v144h-2q20-32 41-56t56.5-52 87-43.5T1285 602q171 0 275 113.5t104 332.5z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 1200 1227\\\" id=\\\"vjs-icon-twitter\\\">\\n <path d=\\\"M714.163 519.284L1160.89 0H1055.03L667.137 450.887L357.328 0H0L468.492 681.821L0 1226.37H105.866L515.491 750.218L842.672 1226.37H1200L714.137 519.284H714.163ZM569.165 687.828L521.697 619.934L144.011 79.6944H306.615L611.412 515.685L658.88 583.579L1055.08 1150.3H892.476L569.165 687.854V687.828Z\\\"/>\\n </symbol>\\n <symbol viewBox=\\\"0 0 1792 1792\\\" id=\\\"vjs-icon-tumblr\\\">\\n <path d=\\\"M1328 1329l80 237q-23 35-111 66t-177 32q-104 2-190.5-26T787 1564t-95-106-55.5-120-16.5-118V676H452V461q72-26 129-69.5t91-90 58-102 34-99T779 12q1-5 4.5-8.5T791 0h244v424h333v252h-334v518q0 30 6.5 56t22.5 52.5 49.5 41.5 81.5 14q78-2 134-29z\\\"></path>\\n </symbol>\\n <symbol viewBox=\\\"0 0 1792 1792\\\" id=\\\"vjs-icon-pinterest\\\">\\n <path d=\\\"M1664 896q0 209-103 385.5T1281.5 1561 896 1664q-111 0-218-32 59-93 78-164 9-34 54-211 20 39 73 67.5t114 28.5q121 0 216-68.5t147-188.5 52-270q0-114-59.5-214T1180 449t-255-63q-105 0-196 29t-154.5 77-109 110.5-67 129.5T377 866q0 104 40 183t117 111q30 12 38-20 2-7 8-31t8-30q6-23-11-43-51-61-51-151 0-151 104.5-259.5T904 517q151 0 235.5 82t84.5 213q0 170-68.5 289T980 1220q-61 0-98-43.5T859 1072q8-35 26.5-93.5t30-103T927 800q0-50-27-83t-77-33q-62 0-105 57t-43 142q0 73 25 122l-99 418q-17 70-13 177-206-91-333-281T128 896q0-209 103-385.5T510.5 231 896 128t385.5 103T1561 510.5 1664 896z\\\"></path>\\n </symbol>\\n </defs>\\n</svg>\";\n\n // /**\n\n // Determine the keycode for the 'back' key based on the platform\n const backKeyCode = IS_TIZEN ? 10009 : IS_WEBOS ? 461 : 8;\n const SpatialNavKeyCodes = {\n codes: {\n play: 415,\n pause: 19,\n ff: 417,\n rw: 412,\n back: backKeyCode\n },\n names: {\n 415: 'play',\n 19: 'pause',\n 417: 'ff',\n 412: 'rw',\n [backKeyCode]: 'back'\n },\n isEventKey(event, keyName) {\n keyName = keyName.toLowerCase();\n if (this.names[event.keyCode] && this.names[event.keyCode] === keyName) {\n return true;\n }\n return false;\n },\n getEventName(event) {\n if (this.names[event.keyCode]) {\n return this.names[event.keyCode];\n } else if (this.codes[event.code]) {\n const code = this.codes[event.code];\n return this.names[code];\n }\n return null;\n }\n };\n\n /**\n * @file spatial-navigation.js\n */\n\n /** @import Component from './component' */\n /** @import Player from './player' */\n\n // The number of seconds the `step*` functions move the timeline.\n const STEP_SECONDS = 5;\n\n /**\n * Spatial Navigation in Video.js enhances user experience and accessibility on smartTV devices,\n * enabling seamless navigation through interactive elements within the player using remote control arrow keys.\n * This functionality allows users to effortlessly navigate through focusable components.\n *\n * @extends EventTarget\n */\n class SpatialNavigation extends EventTarget {\n /**\n * Constructs a SpatialNavigation instance with initial settings.\n * Sets up the player instance, and prepares the spatial navigation system.\n *\n * @class\n * @param {Player} player - The Video.js player instance to which the spatial navigation is attached.\n */\n constructor(player) {\n super();\n this.player_ = player;\n this.focusableComponents = [];\n this.isListening_ = false;\n this.isPaused_ = false;\n this.onKeyDown_ = this.onKeyDown_.bind(this);\n this.lastFocusedComponent_ = null;\n }\n\n /**\n * Starts the spatial navigation by adding a keydown event listener to the video container.\n * This method ensures that the event listener is added only once.\n */\n start() {\n // If the listener is already active, exit early.\n if (this.isListening_) {\n return;\n }\n\n // Add the event listener since the listener is not yet active.\n this.player_.on('keydown', this.onKeyDown_);\n this.player_.on('modalKeydown', this.onKeyDown_);\n // Listen for source change events\n this.player_.on('loadedmetadata', () => {\n this.focus(this.updateFocusableComponents()[0]);\n });\n this.player_.on('modalclose', () => {\n this.refocusComponent();\n });\n this.player_.on('focusin', this.handlePlayerFocus_.bind(this));\n this.player_.on('focusout', this.handlePlayerBlur_.bind(this));\n this.isListening_ = true;\n if (this.player_.errorDisplay) {\n this.player_.errorDisplay.on('aftermodalfill', () => {\n this.updateFocusableComponents();\n if (this.focusableComponents.length) {\n // The modal has focusable components:\n\n if (this.focusableComponents.length > 1) {\n // The modal has close button + some additional buttons.\n // Focusing first additional button:\n\n this.focusableComponents[1].focus();\n } else {\n // The modal has only close button,\n // Focusing it:\n\n this.focusableComponents[0].focus();\n }\n }\n });\n }\n }\n\n /**\n * Stops the spatial navigation by removing the keydown event listener from the video container.\n * Also sets the `isListening_` flag to false.\n */\n stop() {\n this.player_.off('keydown', this.onKeyDown_);\n this.isListening_ = false;\n }\n\n /**\n * Responds to keydown events for spatial navigation and media control.\n *\n * Determines if spatial navigation or media control is active and handles key inputs accordingly.\n *\n * @param {KeyboardEvent} event - The keydown event to be handled.\n */\n onKeyDown_(event) {\n // Determine if the event is a custom modalKeydown event\n const actualEvent = event.originalEvent ? event.originalEvent : event;\n if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(actualEvent.key)) {\n // Handle directional navigation\n if (this.isPaused_) {\n return;\n }\n actualEvent.preventDefault();\n\n // \"ArrowLeft\" => \"left\" etc\n const direction = actualEvent.key.substring(5).toLowerCase();\n this.move(direction);\n } else if (SpatialNavKeyCodes.isEventKey(actualEvent, 'play') || SpatialNavKeyCodes.isEventKey(actualEvent, 'pause') || SpatialNavKeyCodes.isEventKey(actualEvent, 'ff') || SpatialNavKeyCodes.isEventKey(actualEvent, 'rw')) {\n // Handle media actions\n actualEvent.preventDefault();\n const action = SpatialNavKeyCodes.getEventName(actualEvent);\n this.performMediaAction_(action);\n } else if (SpatialNavKeyCodes.isEventKey(actualEvent, 'Back') && event.target && typeof event.target.closeable === 'function' && event.target.closeable()) {\n actualEvent.preventDefault();\n event.target.close();\n }\n }\n\n /**\n * Performs media control actions based on the given key input.\n *\n * Controls the playback and seeking functionalities of the media player.\n *\n * @param {string} key - The key representing the media action to be performed.\n * Accepted keys: 'play', 'pause', 'ff' (fast-forward), 'rw' (rewind).\n */\n performMediaAction_(key) {\n if (this.player_) {\n switch (key) {\n case 'play':\n if (this.player_.paused()) {\n this.player_.play();\n }\n break;\n case 'pause':\n if (!this.player_.paused()) {\n this.player_.pause();\n }\n break;\n case 'ff':\n this.userSeek_(this.player_.currentTime() + STEP_SECONDS);\n break;\n case 'rw':\n this.userSeek_(this.player_.currentTime() - STEP_SECONDS);\n break;\n }\n }\n }\n\n /**\n * Prevent liveThreshold from causing seeks to seem like they\n * are not happening from a user perspective.\n *\n * @param {number} ct\n * current time to seek to\n */\n userSeek_(ct) {\n if (this.player_.liveTracker && this.player_.liveTracker.isLive()) {\n this.player_.liveTracker.nextSeekedFromUser();\n }\n this.player_.currentTime(ct);\n }\n\n /**\n * Pauses the spatial navigation functionality.\n * This method sets a flag that can be used to temporarily disable the navigation logic.\n */\n pause() {\n this.isPaused_ = true;\n }\n\n /**\n * Resumes the spatial navigation functionality if it has been paused.\n * This method resets the pause flag, re-enabling the navigation logic.\n */\n resume() {\n this.isPaused_ = false;\n }\n\n /**\n * Handles Player Blur.\n *\n * @param {string|Event|Object} event\n * The name of the event, an `Event`, or an object with a key of type set to\n * an event name.\n *\n * Calls for handling of the Player Blur if:\n * *The next focused element is not a child of current focused element &\n * The next focused element is not a child of the Player.\n * *There is no next focused element\n */\n handlePlayerBlur_(event) {\n const nextFocusedElement = event.relatedTarget;\n let isChildrenOfPlayer = null;\n const currentComponent = this.getCurrentComponent(event.target);\n if (nextFocusedElement) {\n isChildrenOfPlayer = Boolean(nextFocusedElement.closest('.video-js'));\n\n // If nextFocusedElement is the 'TextTrackSettings' component\n if (nextFocusedElement.classList.contains('vjs-text-track-settings') && !this.isPaused_) {\n this.searchForTrackSelect_();\n }\n }\n if (!event.currentTarget.contains(event.relatedTarget) && !isChildrenOfPlayer || !nextFocusedElement) {\n if (currentComponent && currentComponent.name() === 'CloseButton') {\n this.refocusComponent();\n } else {\n this.pause();\n if (currentComponent && currentComponent.el()) {\n // Store last focused component\n this.lastFocusedComponent_ = currentComponent;\n }\n }\n }\n }\n\n /**\n * Handles the Player focus event.\n *\n * Calls for handling of the Player Focus if current element is focusable.\n */\n handlePlayerFocus_() {\n if (this.getCurrentComponent() && this.getCurrentComponent().getIsFocusable()) {\n this.resume();\n }\n }\n\n /**\n * Gets a set of focusable components.\n *\n * @return {Array}\n * Returns an array of focusable components.\n */\n updateFocusableComponents() {\n const player = this.player_;\n const focusableComponents = [];\n\n /**\n * Searches for children candidates.\n *\n * Pushes Components to array of 'focusableComponents'.\n * Calls itself if there is children elements inside iterated component.\n *\n * @param {Array} componentsArray - The array of components to search for focusable children.\n */\n function searchForChildrenCandidates(componentsArray) {\n for (const i of componentsArray) {\n if (i.hasOwnProperty('el_') && i.getIsFocusable() && i.getIsAvailableToBeFocused(i.el())) {\n focusableComponents.push(i);\n }\n if (i.hasOwnProperty('children_') && i.children_.length > 0) {\n searchForChildrenCandidates(i.children_);\n }\n }\n }\n\n // Iterate inside all children components of the player.\n player.children_.forEach(value => {\n if (value.hasOwnProperty('el_')) {\n // If component has required functions 'getIsFocusable' & 'getIsAvailableToBeFocused', is focusable & available to be focused.\n if (value.getIsFocusable && value.getIsAvailableToBeFocused && value.getIsFocusable() && value.getIsAvailableToBeFocused(value.el())) {\n focusableComponents.push(value);\n return;\n // If component has posible children components as candidates.\n } else if (value.hasOwnProperty('children_') && value.children_.length > 0) {\n searchForChildrenCandidates(value.children_);\n // If component has posible item components as candidates.\n } else if (value.hasOwnProperty('items') && value.items.length > 0) {\n searchForChildrenCandidates(value.items);\n // If there is a suitable child element within the component's DOM element.\n } else if (this.findSuitableDOMChild(value)) {\n focusableComponents.push(value);\n }\n }\n\n // TODO - Refactor the following logic after refactor of videojs-errors elements to be components is done.\n if (value.name_ === 'ErrorDisplay' && value.opened_) {\n const buttonContainer = value.el_.querySelector('.vjs-errors-ok-button-container');\n if (buttonContainer) {\n const modalButtons = buttonContainer.querySelectorAll('button');\n modalButtons.forEach((element, index) => {\n // Add elements as objects to be handled by the spatial navigation\n focusableComponents.push({\n name: () => {\n return 'ModalButton' + (index + 1);\n },\n el: () => element,\n getPositions: () => {\n const rect = element.getBoundingClientRect();\n\n // Creating objects that mirror DOMRectReadOnly for boundingClientRect and center\n const boundingClientRect = {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n left: rect.left\n };\n\n // Calculating the center position\n const center = {\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n width: 0,\n height: 0,\n top: rect.top + rect.height / 2,\n right: rect.left + rect.width / 2,\n bottom: rect.top + rect.height / 2,\n left: rect.left + rect.width / 2\n };\n return {\n boundingClientRect,\n center\n };\n },\n // Asume that the following are always focusable\n getIsAvailableToBeFocused: () => true,\n getIsFocusable: el => true,\n focus: () => element.focus()\n });\n });\n }\n }\n });\n this.focusableComponents = focusableComponents;\n return this.focusableComponents;\n }\n\n /**\n * Finds a suitable child element within the provided component's DOM element.\n *\n * @param {Object} component - The component containing the DOM element to search within.\n * @return {HTMLElement|null} Returns the suitable child element if found, or null if not found.\n */\n findSuitableDOMChild(component) {\n /**\n * Recursively searches for a suitable child node that can be focused within a given component.\n * It first checks if the provided node itself can be focused according to the component's\n * `getIsFocusable` and `getIsAvailableToBeFocused` methods. If not, it recursively searches\n * through the node's children to find a suitable child node that meets the focusability criteria.\n *\n * @param {HTMLElement} node - The DOM node to start the search from.\n * @return {HTMLElement|null} The first child node that is focusable and available to be focused,\n * or `null` if no suitable child is found.\n */\n function searchForSuitableChild(node) {\n if (component.getIsFocusable(node) && component.getIsAvailableToBeFocused(node)) {\n return node;\n }\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n const suitableChild = searchForSuitableChild(child);\n if (suitableChild) {\n return suitableChild;\n }\n }\n return null;\n }\n if (component.el()) {\n return searchForSuitableChild(component.el());\n }\n return null;\n }\n\n /**\n * Gets the currently focused component from the list of focusable components.\n * If a target element is provided, it uses that element to find the corresponding\n * component. If no target is provided, it defaults to using the document's currently\n * active element.\n *\n * @param {HTMLElement} [target] - The DOM element to check against the focusable components.\n * If not provided, `document.activeElement` is used.\n * @return {Component|null} - Returns the focused component if found among the focusable components,\n * otherwise returns null if no matching component is found.\n */\n getCurrentComponent(target) {\n this.updateFocusableComponents();\n // eslint-disable-next-line\n const curComp = target || document.activeElement;\n if (this.focusableComponents.length) {\n for (const i of this.focusableComponents) {\n // If component Node is equal to the current active element.\n if (i.el() === curComp) {\n return i;\n }\n }\n }\n }\n\n /**\n * Adds a component to the array of focusable components.\n *\n * @param {Component} component\n * The `Component` to be added.\n */\n add(component) {\n const focusableComponents = [...this.focusableComponents];\n if (component.hasOwnProperty('el_') && component.getIsFocusable() && component.getIsAvailableToBeFocused(component.el())) {\n focusableComponents.push(component);\n }\n this.focusableComponents = focusableComponents;\n // Trigger the notification manually\n this.trigger({\n type: 'focusableComponentsChanged',\n focusableComponents: this.focusableComponents\n });\n }\n\n /**\n * Removes component from the array of focusable components.\n *\n * @param {Component} component - The component to be removed from the focusable components array.\n */\n remove(component) {\n for (let i = 0; i < this.focusableComponents.length; i++) {\n if (this.focusableComponents[i].name() === component.name()) {\n this.focusableComponents.splice(i, 1);\n // Trigger the notification manually\n this.trigger({\n type: 'focusableComponentsChanged',\n focusableComponents: this.focusableComponents\n });\n return;\n }\n }\n }\n\n /**\n * Clears array of focusable components.\n */\n clear() {\n // Check if the array is already empty to avoid unnecessary event triggering\n if (this.focusableComponents.length > 0) {\n // Clear the array\n this.focusableComponents = [];\n\n // Trigger the notification manually\n this.trigger({\n type: 'focusableComponentsChanged',\n focusableComponents: this.focusableComponents\n });\n }\n }\n\n /**\n * Navigates to the next focusable component based on the specified direction.\n *\n * @param {string} direction 'up', 'down', 'left', 'right'\n */\n move(direction) {\n const currentFocusedComponent = this.getCurrentComponent();\n if (!currentFocusedComponent) {\n return;\n }\n const currentPositions = currentFocusedComponent.getPositions();\n const candidates = this.focusableComponents.filter(component => component !== currentFocusedComponent && this.isInDirection_(currentPositions.boundingClientRect, component.getPositions().boundingClientRect, direction));\n const bestCandidate = this.findBestCandidate_(currentPositions.center, candidates, direction);\n if (bestCandidate) {\n this.focus(bestCandidate);\n } else {\n this.trigger({\n type: 'endOfFocusableComponents',\n direction,\n focusedComponent: currentFocusedComponent\n });\n }\n }\n\n /**\n * Finds the best candidate on the current center position,\n * the list of candidates, and the specified navigation direction.\n *\n * @param {Object} currentCenter The center position of the current focused component element.\n * @param {Array} candidates An array of candidate components to receive focus.\n * @param {string} direction The direction of navigation ('up', 'down', 'left', 'right').\n * @return {Object|null} The component that is the best candidate for receiving focus.\n */\n findBestCandidate_(currentCenter, candidates, direction) {\n let minDistance = Infinity;\n let bestCandidate = null;\n for (const candidate of candidates) {\n const candidateCenter = candidate.getPositions().center;\n const distance = this.calculateDistance_(currentCenter, candidateCenter, direction);\n if (distance < minDistance) {\n minDistance = distance;\n bestCandidate = candidate;\n }\n }\n return bestCandidate;\n }\n\n /**\n * Determines if a target rectangle is in the specified navigation direction\n * relative to a source rectangle.\n *\n * @param {Object} srcRect The bounding rectangle of the source element.\n * @param {Object} targetRect The bounding rectangle of the target element.\n * @param {string} direction The navigation direction ('up', 'down', 'left', 'right').\n * @return {boolean} True if the target is in the specified direction relative to the source.\n */\n isInDirection_(srcRect, targetRect, direction) {\n switch (direction) {\n case 'right':\n return targetRect.left >= srcRect.right;\n case 'left':\n return targetRect.right <= srcRect.left;\n case 'down':\n return targetRect.top >= srcRect.bottom;\n case 'up':\n return targetRect.bottom <= srcRect.top;\n default:\n return false;\n }\n }\n\n /**\n * Focus the last focused component saved before blur on player.\n */\n refocusComponent() {\n if (this.lastFocusedComponent_) {\n // If user is not active, set it to active.\n if (!this.player_.userActive()) {\n this.player_.userActive(true);\n }\n this.updateFocusableComponents();\n\n // Search inside array of 'focusableComponents' for a match of name of\n // the last focused component.\n for (let i = 0; i < this.focusableComponents.length; i++) {\n if (this.focusableComponents[i].name() === this.lastFocusedComponent_.name()) {\n this.focus(this.focusableComponents[i]);\n return;\n }\n }\n } else {\n this.focus(this.updateFocusableComponents()[0]);\n }\n }\n\n /**\n * Focuses on a given component.\n * If the component is available to be focused, it focuses on the component.\n * If not, it attempts to find a suitable DOM child within the component and focuses on it.\n *\n * @param {Component} component - The component to be focused.\n */\n focus(component) {\n if (typeof component !== 'object') {\n return;\n }\n if (component.getIsAvailableToBeFocused(component.el())) {\n component.focus();\n } else if (this.findSuitableDOMChild(component)) {\n this.findSuitableDOMChild(component).focus();\n }\n }\n\n /**\n * Calculates the distance between two points, adjusting the calculation based on\n * the specified navigation direction.\n *\n * @param {Object} center1 The center point of the first element.\n * @param {Object} center2 The center point of the second element.\n * @param {string} direction The direction of navigation ('up', 'down', 'left', 'right').\n * @return {number} The calculated distance between the two centers.\n */\n calculateDistance_(center1, center2, direction) {\n const dx = Math.abs(center1.x - center2.x);\n const dy = Math.abs(center1.y - center2.y);\n let distance;\n switch (direction) {\n case 'right':\n case 'left':\n // Higher weight for vertical distance in horizontal navigation.\n distance = dx + dy * 100;\n break;\n case 'up':\n // Strongly prioritize vertical proximity for UP navigation.\n // Adjust the weight to ensure that elements directly above are favored.\n distance = dy * 2 + dx * 0.5;\n break;\n case 'down':\n // More balanced weight for vertical and horizontal distances.\n // Adjust the weights here to find the best balance.\n distance = dy * 5 + dx;\n break;\n default:\n distance = dx + dy;\n }\n return distance;\n }\n\n /**\n * This gets called by 'handlePlayerBlur_' if 'spatialNavigation' is enabled.\n * Searches for the first 'TextTrackSelect' inside of modal to focus.\n *\n * @private\n */\n searchForTrackSelect_() {\n const spatialNavigation = this;\n for (const component of spatialNavigation.updateFocusableComponents()) {\n if (component.constructor.name === 'TextTrackSelect') {\n spatialNavigation.focus(component);\n break;\n }\n }\n }\n }\n\n /**\n * @file loader.js\n */\n\n /** @import Player from '../player' */\n\n /**\n * The `MediaLoader` is the `Component` that decides which playback technology to load\n * when a player is initialized.\n *\n * @extends Component\n */\n class MediaLoader extends Component {\n /**\n * Create an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should attach to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {Function} [ready]\n * The function that is run when this component is ready.\n */\n constructor(player, options, ready) {\n // MediaLoader has no element\n const options_ = merge({\n createEl: false\n }, options);\n super(player, options_, ready);\n\n // If there are no sources when the player is initialized,\n // load the first supported playback technology.\n\n if (!options.playerOptions.sources || options.playerOptions.sources.length === 0) {\n for (let i = 0, j = options.playerOptions.techOrder; i < j.length; i++) {\n const techName = toTitleCase(j[i]);\n let tech = Tech.getTech(techName);\n\n // Support old behavior of techs being registered as components.\n // Remove once that deprecated behavior is removed.\n if (!techName) {\n tech = Component.getComponent(techName);\n }\n\n // Check if the browser supports this technology\n if (tech && tech.isSupported()) {\n player.loadTech_(techName);\n break;\n }\n }\n } else {\n // Loop through playback technologies (e.g. HTML5) and check for support.\n // Then load the best source.\n // A few assumptions here:\n // All playback technologies respect preload false.\n player.src(options.playerOptions.sources);\n }\n }\n }\n Component.registerComponent('MediaLoader', MediaLoader);\n\n /**\n * @file clickable-component.js\n */\n\n /** @import Player from './player' */\n\n /**\n * Component which is clickable or keyboard actionable, but is not a\n * native HTML button.\n *\n * @extends Component\n */\n class ClickableComponent extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of component options.\n *\n * @param {function} [options.clickHandler]\n * The function to call when the button is clicked / activated\n *\n * @param {string} [options.controlText]\n * The text to set on the button\n *\n * @param {string} [options.className]\n * A class or space separated list of classes to add the component\n *\n */\n constructor(player, options) {\n super(player, options);\n if (this.options_.controlText) {\n this.controlText(this.options_.controlText);\n }\n this.handleMouseOver_ = e => this.handleMouseOver(e);\n this.handleMouseOut_ = e => this.handleMouseOut(e);\n this.handleClick_ = e => this.handleClick(e);\n this.handleKeyDown_ = e => this.handleKeyDown(e);\n this.emitTapEvents();\n this.enable();\n }\n\n /**\n * Create the `ClickableComponent`s DOM element.\n *\n * @param {string} [tag=div]\n * The element's node type.\n *\n * @param {Object} [props={}]\n * An object of properties that should be set on the element.\n *\n * @param {Object} [attributes={}]\n * An object of attributes that should be set on the element.\n *\n * @return {Element}\n * The element that gets created.\n */\n createEl(tag = 'div', props = {}, attributes = {}) {\n props = Object.assign({\n className: this.buildCSSClass(),\n tabIndex: 0\n }, props);\n if (tag === 'button') {\n log.error(`Creating a ClickableComponent with an HTML element of ${tag} is not supported; use a Button instead.`);\n }\n\n // Add ARIA attributes for clickable element which is not a native HTML button\n attributes = Object.assign({\n role: 'button'\n }, attributes);\n this.tabIndex_ = props.tabIndex;\n const el = createEl(tag, props, attributes);\n if (!this.player_.options_.experimentalSvgIcons) {\n el.appendChild(createEl('span', {\n className: 'vjs-icon-placeholder'\n }, {\n 'aria-hidden': true\n }));\n }\n this.createControlTextEl(el);\n return el;\n }\n dispose() {\n // remove controlTextEl_ on dispose\n this.controlTextEl_ = null;\n super.dispose();\n }\n\n /**\n * Create a control text element on this `ClickableComponent`\n *\n * @param {Element} [el]\n * Parent element for the control text.\n *\n * @return {Element}\n * The control text element that gets created.\n */\n createControlTextEl(el) {\n this.controlTextEl_ = createEl('span', {\n className: 'vjs-control-text'\n }, {\n // let the screen reader user know that the text of the element may change\n 'aria-live': 'polite'\n });\n if (el) {\n el.appendChild(this.controlTextEl_);\n }\n this.controlText(this.controlText_, el);\n return this.controlTextEl_;\n }\n\n /**\n * Get or set the localize text to use for the controls on the `ClickableComponent`.\n *\n * @param {string} [text]\n * Control text for element.\n *\n * @param {Element} [el=this.el()]\n * Element to set the title on.\n *\n * @return {string}\n * - The control text when getting\n */\n controlText(text, el = this.el()) {\n if (text === undefined) {\n return this.controlText_ || 'Need Text';\n }\n const localizedText = this.localize(text);\n\n /** @protected */\n this.controlText_ = text;\n textContent(this.controlTextEl_, localizedText);\n if (!this.nonIconControl && !this.player_.options_.noUITitleAttributes) {\n // Set title attribute if only an icon is shown\n el.setAttribute('title', localizedText);\n }\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-control vjs-button ${super.buildCSSClass()}`;\n }\n\n /**\n * Enable this `ClickableComponent`\n */\n enable() {\n if (!this.enabled_) {\n this.enabled_ = true;\n this.removeClass('vjs-disabled');\n this.el_.setAttribute('aria-disabled', 'false');\n if (typeof this.tabIndex_ !== 'undefined') {\n this.el_.setAttribute('tabIndex', this.tabIndex_);\n }\n this.on(['tap', 'click'], this.handleClick_);\n this.on('keydown', this.handleKeyDown_);\n }\n }\n\n /**\n * Disable this `ClickableComponent`\n */\n disable() {\n this.enabled_ = false;\n this.addClass('vjs-disabled');\n this.el_.setAttribute('aria-disabled', 'true');\n if (typeof this.tabIndex_ !== 'undefined') {\n this.el_.removeAttribute('tabIndex');\n }\n this.off('mouseover', this.handleMouseOver_);\n this.off('mouseout', this.handleMouseOut_);\n this.off(['tap', 'click'], this.handleClick_);\n this.off('keydown', this.handleKeyDown_);\n }\n\n /**\n * Handles language change in ClickableComponent for the player in components\n *\n *\n */\n handleLanguagechange() {\n this.controlText(this.controlText_);\n }\n\n /**\n * Event handler that is called when a `ClickableComponent` receives a\n * `click` or `tap` event.\n *\n * @param {Event} event\n * The `tap` or `click` event that caused this function to be called.\n *\n * @listens tap\n * @listens click\n * @abstract\n */\n handleClick(event) {\n if (this.options_.clickHandler) {\n this.options_.clickHandler.call(this, arguments);\n }\n }\n\n /**\n * Event handler that is called when a `ClickableComponent` receives a\n * `keydown` event.\n *\n * By default, if the key is Space or Enter, it will trigger a `click` event.\n *\n * @param {KeyboardEvent} event\n * The `keydown` event that caused this function to be called.\n *\n * @listens keydown\n */\n handleKeyDown(event) {\n // Support Space or Enter key operation to fire a click event. Also,\n // prevent the event from propagating through the DOM and triggering\n // Player hotkeys.\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault();\n event.stopPropagation();\n this.trigger('click');\n } else {\n // Pass keypress handling up for unsupported keys\n super.handleKeyDown(event);\n }\n }\n }\n Component.registerComponent('ClickableComponent', ClickableComponent);\n\n /**\n * @file poster-image.js\n */\n\n /** @import Player from './player' */\n\n /**\n * A `ClickableComponent` that handles showing the poster image for the player.\n *\n * @extends ClickableComponent\n */\n class PosterImage extends ClickableComponent {\n /**\n * Create an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should attach to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.update();\n this.update_ = e => this.update(e);\n player.on('posterchange', this.update_);\n }\n\n /**\n * Clean up and dispose of the `PosterImage`.\n */\n dispose() {\n this.player().off('posterchange', this.update_);\n super.dispose();\n }\n\n /**\n * Create the `PosterImage`s DOM element.\n *\n * @return {Element}\n * The element that gets created.\n */\n createEl() {\n // The el is an empty div to keep position in the DOM\n // A picture and img el will be inserted when a source is set\n return createEl('div', {\n className: 'vjs-poster'\n });\n }\n\n /**\n * Get or set the `PosterImage`'s crossOrigin option.\n *\n * @param {string|null} [value]\n * The value to set the crossOrigin to. If an argument is\n * given, must be one of `'anonymous'` or `'use-credentials'`, or 'null'.\n *\n * @return {string|null}\n * - The current crossOrigin value of the `Player` when getting.\n * - undefined when setting\n */\n crossOrigin(value) {\n // `null` can be set to unset a value\n if (typeof value === 'undefined') {\n if (this.$('img')) {\n // If the poster's element exists, give its value\n return this.$('img').crossOrigin;\n } else if (this.player_.tech_ && this.player_.tech_.isReady_) {\n // If not but the tech is ready, query the tech\n return this.player_.crossOrigin();\n }\n // Otherwise check options as the poster is usually set before the state of crossorigin\n // can be retrieved by the getter\n return this.player_.options_.crossOrigin || this.player_.options_.crossorigin || null;\n }\n if (value !== null && value !== 'anonymous' && value !== 'use-credentials') {\n this.player_.log.warn(`crossOrigin must be null, \"anonymous\" or \"use-credentials\", given \"${value}\"`);\n return;\n }\n if (this.$('img')) {\n this.$('img').crossOrigin = value;\n }\n return;\n }\n\n /**\n * An {@link EventTarget~EventListener} for {@link Player#posterchange} events.\n *\n * @listens Player#posterchange\n *\n * @param {Event} [event]\n * The `Player#posterchange` event that triggered this function.\n */\n update(event) {\n const url = this.player().poster();\n this.setSrc(url);\n\n // If there's no poster source we should display:none on this component\n // so it's not still clickable or right-clickable\n if (url) {\n this.show();\n } else {\n this.hide();\n }\n }\n\n /**\n * Set the source of the `PosterImage` depending on the display method. (Re)creates\n * the inner picture and img elementss when needed.\n *\n * @param {string} [url]\n * The URL to the source for the `PosterImage`. If not specified or falsy,\n * any source and ant inner picture/img are removed.\n */\n setSrc(url) {\n if (!url) {\n this.el_.textContent = '';\n return;\n }\n if (!this.$('img')) {\n this.el_.appendChild(createEl('picture', {\n className: 'vjs-poster',\n // Don't want poster to be tabbable.\n tabIndex: -1\n }, {}, createEl('img', {\n loading: 'lazy',\n crossOrigin: this.crossOrigin()\n }, {\n alt: ''\n })));\n }\n this.$('img').src = url;\n }\n\n /**\n * An {@link EventTarget~EventListener} for clicks on the `PosterImage`. See\n * {@link ClickableComponent#handleClick} for instances where this will be triggered.\n *\n * @listens tap\n * @listens click\n * @listens keydown\n *\n * @param {Event} event\n + The `click`, `tap` or `keydown` event that caused this function to be called.\n */\n handleClick(event) {\n // We don't want a click to trigger playback when controls are disabled\n if (!this.player_.controls()) {\n return;\n }\n if (this.player_.tech(true)) {\n this.player_.tech(true).focus();\n }\n if (this.player_.paused()) {\n silencePromise(this.player_.play());\n } else {\n this.player_.pause();\n }\n }\n }\n\n /**\n * Get or set the `PosterImage`'s crossorigin option. For the HTML5 player, this\n * sets the `crossOrigin` property on the `<img>` tag to control the CORS\n * behavior.\n *\n * @param {string|null} [value]\n * The value to set the `PosterImages`'s crossorigin to. If an argument is\n * given, must be one of `anonymous` or `use-credentials`.\n *\n * @return {string|null|undefined}\n * - The current crossorigin value of the `Player` when getting.\n * - undefined when setting\n */\n PosterImage.prototype.crossorigin = PosterImage.prototype.crossOrigin;\n Component.registerComponent('PosterImage', PosterImage);\n\n /**\n * @file text-track-display.js\n */\n\n /** @import Player from '../player' */\n\n const darkGray = '#222';\n const lightGray = '#ccc';\n const fontMap = {\n monospace: 'monospace',\n sansSerif: 'sans-serif',\n serif: 'serif',\n monospaceSansSerif: '\"Andale Mono\", \"Lucida Console\", monospace',\n monospaceSerif: '\"Courier New\", monospace',\n proportionalSansSerif: 'sans-serif',\n proportionalSerif: 'serif',\n casual: '\"Comic Sans MS\", Impact, fantasy',\n script: '\"Monotype Corsiva\", cursive',\n smallcaps: '\"Andale Mono\", \"Lucida Console\", monospace, sans-serif'\n };\n\n /**\n * Construct an rgba color from a given hex color code.\n *\n * @param {number} color\n * Hex number for color, like #f0e or #f604e2.\n *\n * @param {number} opacity\n * Value for opacity, 0.0 - 1.0.\n *\n * @return {string}\n * The rgba color that was created, like 'rgba(255, 0, 0, 0.3)'.\n */\n function constructColor(color, opacity) {\n let hex;\n if (color.length === 4) {\n // color looks like \"#f0e\"\n hex = color[1] + color[1] + color[2] + color[2] + color[3] + color[3];\n } else if (color.length === 7) {\n // color looks like \"#f604e2\"\n hex = color.slice(1);\n } else {\n throw new Error('Invalid color code provided, ' + color + '; must be formatted as e.g. #f0e or #f604e2.');\n }\n return 'rgba(' + parseInt(hex.slice(0, 2), 16) + ',' + parseInt(hex.slice(2, 4), 16) + ',' + parseInt(hex.slice(4, 6), 16) + ',' + opacity + ')';\n }\n\n /**\n * Try to update the style of a DOM element. Some style changes will throw an error,\n * particularly in IE8. Those should be noops.\n *\n * @param {Element} el\n * The DOM element to be styled.\n *\n * @param {string} style\n * The CSS property on the element that should be styled.\n *\n * @param {string} rule\n * The style rule that should be applied to the property.\n *\n * @private\n */\n function tryUpdateStyle(el, style, rule) {\n try {\n el.style[style] = rule;\n } catch (e) {\n // Satisfies linter.\n return;\n }\n }\n\n /**\n * Converts the CSS top/right/bottom/left property numeric value to string in pixels.\n *\n * @param {number} position\n * The CSS top/right/bottom/left property value.\n *\n * @return {string}\n * The CSS property value that was created, like '10px'.\n *\n * @private\n */\n function getCSSPositionValue(position) {\n return position ? `${position}px` : '';\n }\n\n /**\n * The component for displaying text track cues.\n *\n * @extends Component\n */\n class TextTrackDisplay extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {Function} [ready]\n * The function to call when `TextTrackDisplay` is ready.\n */\n constructor(player, options, ready) {\n super(player, options, ready);\n const updateDisplayTextHandler = e => this.updateDisplay(e);\n const updateDisplayHandler = e => {\n this.updateDisplayOverlay();\n this.updateDisplay(e);\n };\n player.on('loadstart', e => this.toggleDisplay(e));\n player.on('useractive', updateDisplayTextHandler);\n player.on('userinactive', updateDisplayTextHandler);\n player.on('texttrackchange', updateDisplayTextHandler);\n player.on('loadedmetadata', e => {\n this.updateDisplayOverlay();\n this.preselectTrack(e);\n });\n\n // This used to be called during player init, but was causing an error\n // if a track should show by default and the display hadn't loaded yet.\n // Should probably be moved to an external track loader when we support\n // tracks that don't need a display.\n player.ready(bind_(this, function () {\n if (player.tech_ && player.tech_.featuresNativeTextTracks) {\n this.hide();\n return;\n }\n player.on('fullscreenchange', updateDisplayHandler);\n player.on('playerresize', updateDisplayHandler);\n const screenOrientation = window.screen.orientation || window;\n const changeOrientationEvent = window.screen.orientation ? 'change' : 'orientationchange';\n screenOrientation.addEventListener(changeOrientationEvent, updateDisplayHandler);\n player.on('dispose', () => screenOrientation.removeEventListener(changeOrientationEvent, updateDisplayHandler));\n const tracks = this.options_.playerOptions.tracks || [];\n for (let i = 0; i < tracks.length; i++) {\n this.player_.addRemoteTextTrack(tracks[i], true);\n }\n this.preselectTrack();\n }));\n }\n\n /**\n * Preselect a track following this precedence:\n * - matches the previously selected {@link TextTrack}'s language and kind\n * - matches the previously selected {@link TextTrack}'s language only\n * - is the first default captions track\n * - is the first default descriptions track\n *\n * @listens Player#loadstart\n */\n preselectTrack() {\n const modes = {\n captions: 1,\n subtitles: 1\n };\n const trackList = this.player_.textTracks();\n const userPref = this.player_.cache_.selectedLanguage;\n let firstDesc;\n let firstCaptions;\n let preferredTrack;\n for (let i = 0; i < trackList.length; i++) {\n const track = trackList[i];\n if (userPref && userPref.enabled && userPref.language && userPref.language === track.language && track.kind in modes) {\n // Always choose the track that matches both language and kind\n if (track.kind === userPref.kind) {\n preferredTrack = track;\n // or choose the first track that matches language\n } else if (!preferredTrack) {\n preferredTrack = track;\n }\n\n // clear everything if offTextTrackMenuItem was clicked\n } else if (userPref && !userPref.enabled) {\n preferredTrack = null;\n firstDesc = null;\n firstCaptions = null;\n } else if (track.default) {\n if (track.kind === 'descriptions' && !firstDesc) {\n firstDesc = track;\n } else if (track.kind in modes && !firstCaptions) {\n firstCaptions = track;\n }\n }\n }\n\n // The preferredTrack matches the user preference and takes\n // precedence over all the other tracks.\n // So, display the preferredTrack before the first default track\n // and the subtitles/captions track before the descriptions track\n if (preferredTrack) {\n preferredTrack.mode = 'showing';\n } else if (firstCaptions) {\n firstCaptions.mode = 'showing';\n } else if (firstDesc) {\n firstDesc.mode = 'showing';\n }\n }\n\n /**\n * Turn display of {@link TextTrack}'s from the current state into the other state.\n * There are only two states:\n * - 'shown'\n * - 'hidden'\n *\n * @listens Player#loadstart\n */\n toggleDisplay() {\n if (this.player_.tech_ && this.player_.tech_.featuresNativeTextTracks) {\n this.hide();\n } else {\n this.show();\n }\n }\n\n /**\n * Create the {@link Component}'s DOM element.\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n return super.createEl('div', {\n className: 'vjs-text-track-display'\n }, {\n 'translate': 'yes',\n 'aria-live': 'off',\n 'aria-atomic': 'true'\n });\n }\n\n /**\n * Clear all displayed {@link TextTrack}s.\n */\n clearDisplay() {\n if (typeof window.WebVTT === 'function') {\n window.WebVTT.processCues(window, [], this.el_);\n }\n }\n\n /**\n * Update the displayed {@link TextTrack} when either a {@link Player#texttrackchange},\n * a {@link Player#fullscreenchange}, a {@link Player#useractive}, or a\n * {@link Player#userinactive} is fired.\n *\n * @listens Player#texttrackchange\n * @listens Player#fullscreenchange\n * @listens Player#useractive\n * @listens Player#userinactive\n */\n updateDisplay() {\n const tracks = this.player_.textTracks();\n const allowMultipleShowingTracks = this.options_.allowMultipleShowingTracks;\n this.clearDisplay();\n if (allowMultipleShowingTracks) {\n const showingTracks = [];\n for (let i = 0; i < tracks.length; ++i) {\n const track = tracks[i];\n if (track.mode !== 'showing') {\n continue;\n }\n showingTracks.push(track);\n }\n this.updateForTrack(showingTracks);\n return;\n }\n\n // Track display prioritization model: if multiple tracks are 'showing',\n // display the first 'subtitles' or 'captions' track which is 'showing',\n // otherwise display the first 'descriptions' track which is 'showing'\n\n let descriptionsTrack = null;\n let captionsSubtitlesTrack = null;\n let i = tracks.length;\n while (i--) {\n const track = tracks[i];\n if (track.mode === 'showing') {\n if (track.kind === 'descriptions') {\n descriptionsTrack = track;\n } else {\n captionsSubtitlesTrack = track;\n }\n }\n }\n if (captionsSubtitlesTrack) {\n if (this.getAttribute('aria-live') !== 'off') {\n this.setAttribute('aria-live', 'off');\n }\n this.updateForTrack(captionsSubtitlesTrack);\n } else if (descriptionsTrack) {\n if (this.getAttribute('aria-live') !== 'assertive') {\n this.setAttribute('aria-live', 'assertive');\n }\n this.updateForTrack(descriptionsTrack);\n }\n if (!window.CSS.supports('inset', '10px')) {\n const textTrackDisplay = this.el_;\n const vjsTextTrackCues = textTrackDisplay.querySelectorAll('.vjs-text-track-cue');\n const controlBarHeight = this.player_.controlBar.el_.getBoundingClientRect().height;\n const playerHeight = this.player_.el_.getBoundingClientRect().height;\n\n // Clear inline style before getting actual height of textTrackDisplay\n textTrackDisplay.style = '';\n\n // textrack style updates, this styles are required to be inline\n tryUpdateStyle(textTrackDisplay, 'position', 'relative');\n tryUpdateStyle(textTrackDisplay, 'height', playerHeight - controlBarHeight + 'px');\n tryUpdateStyle(textTrackDisplay, 'top', 'unset');\n if (IS_SMART_TV) {\n tryUpdateStyle(textTrackDisplay, 'bottom', playerHeight + 'px');\n } else {\n tryUpdateStyle(textTrackDisplay, 'bottom', '0px');\n }\n\n // vjsTextTrackCue style updates\n if (vjsTextTrackCues.length > 0) {\n vjsTextTrackCues.forEach(vjsTextTrackCue => {\n // verify if inset styles are inline\n if (vjsTextTrackCue.style.inset) {\n const insetStyles = vjsTextTrackCue.style.inset.split(' ');\n\n // expected value is always 3\n if (insetStyles.length === 3) {\n Object.assign(vjsTextTrackCue.style, {\n top: insetStyles[0],\n right: insetStyles[1],\n bottom: insetStyles[2],\n left: 'unset'\n });\n }\n }\n });\n }\n }\n }\n\n /**\n * Updates the displayed TextTrack to be sure it overlays the video when a either\n * a {@link Player#texttrackchange} or a {@link Player#fullscreenchange} is fired.\n */\n updateDisplayOverlay() {\n // inset-inline and inset-block are not supprted on old chrome, but these are\n // only likely to be used on TV devices\n if (!this.player_.videoHeight() || !window.CSS.supports('inset-inline: 10px')) {\n return;\n }\n const playerWidth = this.player_.currentWidth();\n const playerHeight = this.player_.currentHeight();\n const playerAspectRatio = playerWidth / playerHeight;\n const videoAspectRatio = this.player_.videoWidth() / this.player_.videoHeight();\n let insetInlineMatch = 0;\n let insetBlockMatch = 0;\n if (Math.abs(playerAspectRatio - videoAspectRatio) > 0.1) {\n if (playerAspectRatio > videoAspectRatio) {\n insetInlineMatch = Math.round((playerWidth - playerHeight * videoAspectRatio) / 2);\n } else {\n insetBlockMatch = Math.round((playerHeight - playerWidth / videoAspectRatio) / 2);\n }\n }\n tryUpdateStyle(this.el_, 'insetInline', getCSSPositionValue(insetInlineMatch));\n tryUpdateStyle(this.el_, 'insetBlock', getCSSPositionValue(insetBlockMatch));\n }\n\n /**\n * Style {@Link TextTrack} activeCues according to {@Link TextTrackSettings}.\n *\n * @param {TextTrack} track\n * Text track object containing active cues to style.\n */\n updateDisplayState(track) {\n const overrides = this.player_.textTrackSettings.getValues();\n const cues = track.activeCues;\n let i = cues.length;\n while (i--) {\n const cue = cues[i];\n if (!cue) {\n continue;\n }\n const cueDiv = cue.displayState;\n if (overrides.color) {\n cueDiv.firstChild.style.color = overrides.color;\n }\n if (overrides.textOpacity) {\n tryUpdateStyle(cueDiv.firstChild, 'color', constructColor(overrides.color || '#fff', overrides.textOpacity));\n }\n if (overrides.backgroundColor) {\n cueDiv.firstChild.style.backgroundColor = overrides.backgroundColor;\n }\n if (overrides.backgroundOpacity) {\n tryUpdateStyle(cueDiv.firstChild, 'backgroundColor', constructColor(overrides.backgroundColor || '#000', overrides.backgroundOpacity));\n }\n if (overrides.windowColor) {\n if (overrides.windowOpacity) {\n tryUpdateStyle(cueDiv, 'backgroundColor', constructColor(overrides.windowColor, overrides.windowOpacity));\n } else {\n cueDiv.style.backgroundColor = overrides.windowColor;\n }\n }\n if (overrides.edgeStyle) {\n if (overrides.edgeStyle === 'dropshadow') {\n cueDiv.firstChild.style.textShadow = `2px 2px 3px ${darkGray}, 2px 2px 4px ${darkGray}, 2px 2px 5px ${darkGray}`;\n } else if (overrides.edgeStyle === 'raised') {\n cueDiv.firstChild.style.textShadow = `1px 1px ${darkGray}, 2px 2px ${darkGray}, 3px 3px ${darkGray}`;\n } else if (overrides.edgeStyle === 'depressed') {\n cueDiv.firstChild.style.textShadow = `1px 1px ${lightGray}, 0 1px ${lightGray}, -1px -1px ${darkGray}, 0 -1px ${darkGray}`;\n } else if (overrides.edgeStyle === 'uniform') {\n cueDiv.firstChild.style.textShadow = `0 0 4px ${darkGray}, 0 0 4px ${darkGray}, 0 0 4px ${darkGray}, 0 0 4px ${darkGray}`;\n }\n }\n if (overrides.fontPercent && overrides.fontPercent !== 1) {\n const fontSize = window.parseFloat(cueDiv.style.fontSize);\n cueDiv.style.fontSize = fontSize * overrides.fontPercent + 'px';\n cueDiv.style.height = 'auto';\n cueDiv.style.top = 'auto';\n }\n if (overrides.fontFamily && overrides.fontFamily !== 'default') {\n if (overrides.fontFamily === 'small-caps') {\n cueDiv.firstChild.style.fontVariant = 'small-caps';\n } else {\n cueDiv.firstChild.style.fontFamily = fontMap[overrides.fontFamily];\n }\n }\n }\n }\n\n /**\n * Add an {@link TextTrack} to to the {@link Tech}s {@link TextTrackList}.\n *\n * @param {TextTrack|TextTrack[]} tracks\n * Text track object or text track array to be added to the list.\n */\n updateForTrack(tracks) {\n if (!Array.isArray(tracks)) {\n tracks = [tracks];\n }\n if (typeof window.WebVTT !== 'function' || tracks.every(track => {\n return !track.activeCues;\n })) {\n return;\n }\n const cues = [];\n\n // push all active track cues\n for (let i = 0; i < tracks.length; ++i) {\n const track = tracks[i];\n for (let j = 0; j < track.activeCues.length; ++j) {\n cues.push(track.activeCues[j]);\n }\n }\n\n // removes all cues before it processes new ones\n window.WebVTT.processCues(window, cues, this.el_);\n\n // add unique class to each language text track & add settings styling if necessary\n for (let i = 0; i < tracks.length; ++i) {\n const track = tracks[i];\n for (let j = 0; j < track.activeCues.length; ++j) {\n const cueEl = track.activeCues[j].displayState;\n addClass(cueEl, 'vjs-text-track-cue', 'vjs-text-track-cue-' + (track.language ? track.language : i));\n if (track.language) {\n setAttribute(cueEl, 'lang', track.language);\n }\n }\n if (this.player_.textTrackSettings) {\n this.updateDisplayState(track);\n }\n }\n }\n }\n Component.registerComponent('TextTrackDisplay', TextTrackDisplay);\n\n /**\n * @file loading-spinner.js\n */\n\n /**\n * A loading spinner for use during waiting/loading events.\n *\n * @extends Component\n */\n class LoadingSpinner extends Component {\n /**\n * Create the `LoadingSpinner`s DOM element.\n *\n * @return {Element}\n * The dom element that gets created.\n */\n createEl() {\n const isAudio = this.player_.isAudio();\n const playerType = this.localize(isAudio ? 'Audio Player' : 'Video Player');\n const controlText = createEl('span', {\n className: 'vjs-control-text',\n textContent: this.localize('{1} is loading.', [playerType])\n });\n const el = super.createEl('div', {\n className: 'vjs-loading-spinner',\n dir: 'ltr'\n });\n el.appendChild(controlText);\n return el;\n }\n\n /**\n * Update control text on languagechange\n */\n handleLanguagechange() {\n this.$('.vjs-control-text').textContent = this.localize('{1} is loading.', [this.player_.isAudio() ? 'Audio Player' : 'Video Player']);\n }\n }\n Component.registerComponent('LoadingSpinner', LoadingSpinner);\n\n /**\n * @file button.js\n */\n\n /**\n * Base class for all buttons.\n *\n * @extends ClickableComponent\n */\n class Button extends ClickableComponent {\n /**\n * Create the `Button`s DOM element.\n *\n * @param {string} [tag=\"button\"]\n * The element's node type. This argument is IGNORED: no matter what\n * is passed, it will always create a `button` element.\n *\n * @param {Object} [props={}]\n * An object of properties that should be set on the element.\n *\n * @param {Object} [attributes={}]\n * An object of attributes that should be set on the element.\n *\n * @return {Element}\n * The element that gets created.\n */\n createEl(tag, props = {}, attributes = {}) {\n tag = 'button';\n props = Object.assign({\n className: this.buildCSSClass()\n }, props);\n\n // Add attributes for button element\n attributes = Object.assign({\n // Necessary since the default button type is \"submit\"\n type: 'button'\n }, attributes);\n const el = createEl(tag, props, attributes);\n if (!this.player_.options_.experimentalSvgIcons) {\n el.appendChild(createEl('span', {\n className: 'vjs-icon-placeholder'\n }, {\n 'aria-hidden': true\n }));\n }\n this.createControlTextEl(el);\n return el;\n }\n\n /**\n * Add a child `Component` inside of this `Button`.\n *\n * @param {string|Component} child\n * The name or instance of a child to add.\n *\n * @param {Object} [options={}]\n * The key/value store of options that will get passed to children of\n * the child.\n *\n * @return {Component}\n * The `Component` that gets added as a child. When using a string the\n * `Component` will get created by this process.\n *\n * @deprecated since version 5\n */\n addChild(child, options = {}) {\n const className = this.constructor.name;\n log.warn(`Adding an actionable (user controllable) child to a Button (${className}) is not supported; use a ClickableComponent instead.`);\n\n // Avoid the error message generated by ClickableComponent's addChild method\n return Component.prototype.addChild.call(this, child, options);\n }\n\n /**\n * Enable the `Button` element so that it can be activated or clicked. Use this with\n * {@link Button#disable}.\n */\n enable() {\n super.enable();\n this.el_.removeAttribute('disabled');\n }\n\n /**\n * Disable the `Button` element so that it cannot be activated or clicked. Use this with\n * {@link Button#enable}.\n */\n disable() {\n super.disable();\n this.el_.setAttribute('disabled', 'disabled');\n }\n\n /**\n * This gets called when a `Button` has focus and `keydown` is triggered via a key\n * press.\n *\n * @param {KeyboardEvent} event\n * The event that caused this function to get called.\n *\n * @listens keydown\n */\n handleKeyDown(event) {\n // Ignore Space or Enter key operation, which is handled by the browser for\n // a button - though not for its super class, ClickableComponent. Also,\n // prevent the event from propagating through the DOM and triggering Player\n // hotkeys. We do not preventDefault here because we _want_ the browser to\n // handle it.\n if (event.key === ' ' || event.key === 'Enter') {\n event.stopPropagation();\n return;\n }\n\n // Pass keypress handling up for unsupported keys\n super.handleKeyDown(event);\n }\n }\n Component.registerComponent('Button', Button);\n\n /**\n * @file big-play-button.js\n */\n\n /**\n * The initial play button that shows before the video has played. The hiding of the\n * `BigPlayButton` get done via CSS and `Player` states.\n *\n * @extends Button\n */\n class BigPlayButton extends Button {\n constructor(player, options) {\n super(player, options);\n this.mouseused_ = false;\n this.setIcon('play');\n this.on('mousedown', e => this.handleMouseDown(e));\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object. Always returns 'vjs-big-play-button'.\n */\n buildCSSClass() {\n return 'vjs-big-play-button';\n }\n\n /**\n * This gets called when a `BigPlayButton` \"clicked\". See {@link ClickableComponent}\n * for more detailed information on what a click can be.\n *\n * @param {KeyboardEvent|MouseEvent|TouchEvent} event\n * The `keydown`, `tap`, or `click` event that caused this function to be\n * called.\n *\n * @listens tap\n * @listens click\n */\n handleClick(event) {\n const playPromise = this.player_.play();\n\n // exit early if tapped or clicked via the mouse\n if (event.type === 'tap' || this.mouseused_ && 'clientX' in event && 'clientY' in event) {\n silencePromise(playPromise);\n if (this.player_.tech(true)) {\n this.player_.tech(true).focus();\n }\n return;\n }\n const cb = this.player_.getChild('controlBar');\n const playToggle = cb && cb.getChild('playToggle');\n if (!playToggle) {\n this.player_.tech(true).focus();\n return;\n }\n const playFocus = () => playToggle.focus();\n if (isPromise(playPromise)) {\n playPromise.then(playFocus, () => {});\n } else {\n this.setTimeout(playFocus, 1);\n }\n }\n\n /**\n * Event handler that is called when a `BigPlayButton` receives a\n * `keydown` event.\n *\n * @param {KeyboardEvent} event\n * The `keydown` event that caused this function to be called.\n *\n * @listens keydown\n */\n handleKeyDown(event) {\n this.mouseused_ = false;\n super.handleKeyDown(event);\n }\n\n /**\n * Handle `mousedown` events on the `BigPlayButton`.\n *\n * @param {MouseEvent} event\n * `mousedown` or `touchstart` event that triggered this function\n *\n * @listens mousedown\n */\n handleMouseDown(event) {\n this.mouseused_ = true;\n }\n }\n\n /**\n * The text that should display over the `BigPlayButton`s controls. Added to for localization.\n *\n * @type {string}\n * @protected\n */\n BigPlayButton.prototype.controlText_ = 'Play Video';\n Component.registerComponent('BigPlayButton', BigPlayButton);\n\n /**\n * @file close-button.js\n */\n\n /** @import Player from './player' */\n\n /**\n * The `CloseButton` is a `{@link Button}` that fires a `close` event when\n * it gets clicked.\n *\n * @extends Button\n */\n class CloseButton extends Button {\n /**\n * Creates an instance of the this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.setIcon('cancel');\n this.controlText(options && options.controlText || this.localize('Close'));\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-close-button ${super.buildCSSClass()}`;\n }\n\n /**\n * This gets called when a `CloseButton` gets clicked. See\n * {@link ClickableComponent#handleClick} for more information on when\n * this will be triggered\n *\n * @param {Event} event\n * The `keydown`, `tap`, or `click` event that caused this function to be\n * called.\n *\n * @listens tap\n * @listens click\n * @fires CloseButton#close\n */\n handleClick(event) {\n /**\n * Triggered when the a `CloseButton` is clicked.\n *\n * @event CloseButton#close\n * @type {Event}\n *\n * @property {boolean} [bubbles=false]\n * set to false so that the close event does not\n * bubble up to parents if there is no listener\n */\n this.trigger({\n type: 'close',\n bubbles: false\n });\n }\n /**\n * Event handler that is called when a `CloseButton` receives a\n * `keydown` event.\n *\n * By default, if the key is Esc, it will trigger a `click` event.\n *\n * @param {KeyboardEvent} event\n * The `keydown` event that caused this function to be called.\n *\n * @listens keydown\n */\n handleKeyDown(event) {\n // Esc button will trigger `click` event\n if (event.key === 'Escape') {\n event.preventDefault();\n event.stopPropagation();\n this.trigger('click');\n } else {\n // Pass keypress handling up for unsupported keys\n super.handleKeyDown(event);\n }\n }\n }\n Component.registerComponent('CloseButton', CloseButton);\n\n /**\n * @file play-toggle.js\n */\n\n /** @import Player from './player' */\n\n /**\n * Button to toggle between play and pause.\n *\n * @extends Button\n */\n class PlayToggle extends Button {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options={}]\n * The key/value store of player options.\n */\n constructor(player, options = {}) {\n super(player, options);\n\n // show or hide replay icon\n options.replay = options.replay === undefined || options.replay;\n this.setIcon('play');\n this.on(player, 'play', e => this.handlePlay(e));\n this.on(player, 'pause', e => this.handlePause(e));\n if (options.replay) {\n this.on(player, 'ended', e => this.handleEnded(e));\n }\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-play-control ${super.buildCSSClass()}`;\n }\n\n /**\n * This gets called when an `PlayToggle` is \"clicked\". See\n * {@link ClickableComponent} for more detailed information on what a click can be.\n *\n * @param {Event} [event]\n * The `keydown`, `tap`, or `click` event that caused this function to be\n * called.\n *\n * @listens tap\n * @listens click\n */\n handleClick(event) {\n if (this.player_.paused()) {\n silencePromise(this.player_.play());\n } else {\n this.player_.pause();\n }\n }\n\n /**\n * This gets called once after the video has ended and the user seeks so that\n * we can change the replay button back to a play button.\n *\n * @param {Event} [event]\n * The event that caused this function to run.\n *\n * @listens Player#seeked\n */\n handleSeeked(event) {\n this.removeClass('vjs-ended');\n if (this.player_.paused()) {\n this.handlePause(event);\n } else {\n this.handlePlay(event);\n }\n }\n\n /**\n * Add the vjs-playing class to the element so it can change appearance.\n *\n * @param {Event} [event]\n * The event that caused this function to run.\n *\n * @listens Player#play\n */\n handlePlay(event) {\n this.removeClass('vjs-ended', 'vjs-paused');\n this.addClass('vjs-playing');\n // change the button text to \"Pause\"\n this.setIcon('pause');\n this.controlText('Pause');\n }\n\n /**\n * Add the vjs-paused class to the element so it can change appearance.\n *\n * @param {Event} [event]\n * The event that caused this function to run.\n *\n * @listens Player#pause\n */\n handlePause(event) {\n this.removeClass('vjs-playing');\n this.addClass('vjs-paused');\n // change the button text to \"Play\"\n this.setIcon('play');\n this.controlText('Play');\n }\n\n /**\n * Add the vjs-ended class to the element so it can change appearance\n *\n * @param {Event} [event]\n * The event that caused this function to run.\n *\n * @listens Player#ended\n */\n handleEnded(event) {\n this.removeClass('vjs-playing');\n this.addClass('vjs-ended');\n // change the button text to \"Replay\"\n this.setIcon('replay');\n this.controlText('Replay');\n\n // on the next seek remove the replay button\n this.one(this.player_, 'seeked', e => this.handleSeeked(e));\n }\n }\n\n /**\n * The text that should display over the `PlayToggle`s controls. Added for localization.\n *\n * @type {string}\n * @protected\n */\n PlayToggle.prototype.controlText_ = 'Play';\n Component.registerComponent('PlayToggle', PlayToggle);\n\n /**\n * @file time-display.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * Displays time information about the video\n *\n * @extends Component\n */\n class TimeDisplay extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.on(player, ['timeupdate', 'ended', 'seeking'], e => this.update(e));\n this.updateTextNode_();\n }\n\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n const className = this.buildCSSClass();\n const el = super.createEl('div', {\n className: `${className} vjs-time-control vjs-control`\n });\n const span = createEl('span', {\n className: 'vjs-control-text',\n textContent: `${this.localize(this.labelText_)}\\u00a0`\n }, {\n role: 'presentation'\n });\n el.appendChild(span);\n this.contentEl_ = createEl('span', {\n className: `${className}-display`\n }, {\n // span elements have no implicit role, but some screen readers (notably VoiceOver)\n // treat them as a break between items in the DOM when using arrow keys\n // (or left-to-right swipes on iOS) to read contents of a page. Using\n // role='presentation' causes VoiceOver to NOT treat this span as a break.\n role: 'presentation'\n });\n el.appendChild(this.contentEl_);\n return el;\n }\n dispose() {\n this.contentEl_ = null;\n this.textNode_ = null;\n super.dispose();\n }\n\n /**\n * Updates the displayed time according to the `updateContent` function which is defined in the child class.\n *\n * @param {Event} [event]\n * The `timeupdate`, `ended` or `seeking` (if enableSmoothSeeking is true) event that caused this function to be called.\n */\n update(event) {\n if (!this.player_.options_.enableSmoothSeeking && event.type === 'seeking') {\n return;\n }\n this.updateContent(event);\n }\n\n /**\n * Updates the time display text node with a new time\n *\n * @param {number} [time=0] the time to update to\n *\n * @private\n */\n updateTextNode_(time = 0) {\n time = formatTime(time);\n if (this.formattedTime_ === time) {\n return;\n }\n this.formattedTime_ = time;\n this.requestNamedAnimationFrame('TimeDisplay#updateTextNode_', () => {\n if (!this.contentEl_) {\n return;\n }\n let oldNode = this.textNode_;\n if (oldNode && this.contentEl_.firstChild !== oldNode) {\n oldNode = null;\n log.warn('TimeDisplay#updateTextnode_: Prevented replacement of text node element since it was no longer a child of this node. Appending a new node instead.');\n }\n this.textNode_ = document.createTextNode(this.formattedTime_);\n if (!this.textNode_) {\n return;\n }\n if (oldNode) {\n this.contentEl_.replaceChild(this.textNode_, oldNode);\n } else {\n this.contentEl_.appendChild(this.textNode_);\n }\n });\n }\n\n /**\n * To be filled out in the child class, should update the displayed time\n * in accordance with the fact that the current time has changed.\n *\n * @param {Event} [event]\n * The `timeupdate` event that caused this to run.\n *\n * @listens Player#timeupdate\n */\n updateContent(event) {}\n }\n\n /**\n * The text that is added to the `TimeDisplay` for screen reader users.\n *\n * @type {string}\n * @private\n */\n TimeDisplay.prototype.labelText_ = 'Time';\n\n /**\n * The text that should display over the `TimeDisplay`s controls. Added to for localization.\n *\n * @type {string}\n * @protected\n *\n * @deprecated in v7; controlText_ is not used in non-active display Components\n */\n TimeDisplay.prototype.controlText_ = 'Time';\n Component.registerComponent('TimeDisplay', TimeDisplay);\n\n /**\n * @file current-time-display.js\n */\n\n /**\n * Displays the current time\n *\n * @extends Component\n */\n class CurrentTimeDisplay extends TimeDisplay {\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return 'vjs-current-time';\n }\n\n /**\n * Update current time display\n *\n * @param {Event} [event]\n * The `timeupdate` event that caused this function to run.\n *\n * @listens Player#timeupdate\n */\n updateContent(event) {\n // Allows for smooth scrubbing, when player can't keep up.\n let time;\n if (this.player_.ended()) {\n time = this.player_.duration();\n } else if (event && event.target && typeof event.target.pendingSeekTime === 'function') {\n time = event.target.pendingSeekTime();\n } else {\n time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();\n }\n this.updateTextNode_(time);\n }\n }\n\n /**\n * The text that is added to the `CurrentTimeDisplay` for screen reader users.\n *\n * @type {string}\n * @private\n */\n CurrentTimeDisplay.prototype.labelText_ = 'Current Time';\n\n /**\n * The text that should display over the `CurrentTimeDisplay`s controls. Added to for localization.\n *\n * @type {string}\n * @protected\n *\n * @deprecated in v7; controlText_ is not used in non-active display Components\n */\n CurrentTimeDisplay.prototype.controlText_ = 'Current Time';\n Component.registerComponent('CurrentTimeDisplay', CurrentTimeDisplay);\n\n /**\n * @file duration-display.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * Displays the duration\n *\n * @extends Component\n */\n class DurationDisplay extends TimeDisplay {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n const updateContent = e => this.updateContent(e);\n\n // we do not want to/need to throttle duration changes,\n // as they should always display the changed duration as\n // it has changed\n this.on(player, 'durationchange', updateContent);\n\n // Listen to loadstart because the player duration is reset when a new media element is loaded,\n // but the durationchange on the user agent will not fire.\n // @see [Spec]{@link https://www.w3.org/TR/2011/WD-html5-20110113/video.html#media-element-load-algorithm}\n this.on(player, 'loadstart', updateContent);\n\n // Also listen for timeupdate (in the parent) and loadedmetadata because removing those\n // listeners could have broken dependent applications/libraries. These\n // can likely be removed for 7.0.\n this.on(player, 'loadedmetadata', updateContent);\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return 'vjs-duration';\n }\n\n /**\n * Update duration time display.\n *\n * @param {Event} [event]\n * The `durationchange`, `timeupdate`, or `loadedmetadata` event that caused\n * this function to be called.\n *\n * @listens Player#durationchange\n * @listens Player#timeupdate\n * @listens Player#loadedmetadata\n */\n updateContent(event) {\n const duration = this.player_.duration();\n this.updateTextNode_(duration);\n }\n }\n\n /**\n * The text that is added to the `DurationDisplay` for screen reader users.\n *\n * @type {string}\n * @private\n */\n DurationDisplay.prototype.labelText_ = 'Duration';\n\n /**\n * The text that should display over the `DurationDisplay`s controls. Added to for localization.\n *\n * @type {string}\n * @protected\n *\n * @deprecated in v7; controlText_ is not used in non-active display Components\n */\n DurationDisplay.prototype.controlText_ = 'Duration';\n Component.registerComponent('DurationDisplay', DurationDisplay);\n\n /**\n * @file time-divider.js\n */\n\n /**\n * The separator between the current time and duration.\n * Can be hidden if it's not needed in the design.\n *\n * @extends Component\n */\n class TimeDivider extends Component {\n /**\n * Create the component's DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n const el = super.createEl('div', {\n className: 'vjs-time-control vjs-time-divider'\n }, {\n // this element and its contents can be hidden from assistive techs since\n // it is made extraneous by the announcement of the control text\n // for the current time and duration displays\n 'aria-hidden': true\n });\n const div = super.createEl('div');\n const span = super.createEl('span', {\n textContent: '/'\n });\n div.appendChild(span);\n el.appendChild(div);\n return el;\n }\n }\n Component.registerComponent('TimeDivider', TimeDivider);\n\n /**\n * @file remaining-time-display.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * Displays the time left in the video\n *\n * @extends Component\n */\n class RemainingTimeDisplay extends TimeDisplay {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.on(player, 'durationchange', e => this.updateContent(e));\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return 'vjs-remaining-time';\n }\n\n /**\n * Create the `Component`'s DOM element with the \"minus\" character prepend to the time\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n const el = super.createEl();\n if (this.options_.displayNegative !== false) {\n el.insertBefore(createEl('span', {}, {\n 'aria-hidden': true\n }, '-'), this.contentEl_);\n }\n return el;\n }\n\n /**\n * Update remaining time display.\n *\n * @param {Event} [event]\n * The `timeupdate` or `durationchange` event that caused this to run.\n *\n * @listens Player#timeupdate\n * @listens Player#durationchange\n */\n updateContent(event) {\n if (typeof this.player_.duration() !== 'number') {\n return;\n }\n let time;\n\n // @deprecated We should only use remainingTimeDisplay\n // as of video.js 7\n if (this.player_.ended()) {\n time = 0;\n } else if (this.player_.remainingTimeDisplay) {\n time = this.player_.remainingTimeDisplay();\n } else {\n time = this.player_.remainingTime();\n }\n this.updateTextNode_(time);\n }\n }\n\n /**\n * The text that is added to the `RemainingTimeDisplay` for screen reader users.\n *\n * @type {string}\n * @private\n */\n RemainingTimeDisplay.prototype.labelText_ = 'Remaining Time';\n\n /**\n * The text that should display over the `RemainingTimeDisplay`s controls. Added to for localization.\n *\n * @type {string}\n * @protected\n *\n * @deprecated in v7; controlText_ is not used in non-active display Components\n */\n RemainingTimeDisplay.prototype.controlText_ = 'Remaining Time';\n Component.registerComponent('RemainingTimeDisplay', RemainingTimeDisplay);\n\n /**\n * @file live-display.js\n */\n\n /** @import Player from './player' */\n\n // TODO - Future make it click to snap to live\n\n /**\n * Displays the live indicator when duration is Infinity.\n *\n * @extends Component\n */\n class LiveDisplay extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.updateShowing();\n this.on(this.player(), 'durationchange', e => this.updateShowing(e));\n }\n\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n const el = super.createEl('div', {\n className: 'vjs-live-control vjs-control'\n });\n this.contentEl_ = createEl('div', {\n className: 'vjs-live-display'\n }, {\n 'aria-live': 'off'\n });\n this.contentEl_.appendChild(createEl('span', {\n className: 'vjs-control-text',\n textContent: `${this.localize('Stream Type')}\\u00a0`\n }));\n this.contentEl_.appendChild(document.createTextNode(this.localize('LIVE')));\n el.appendChild(this.contentEl_);\n return el;\n }\n dispose() {\n this.contentEl_ = null;\n super.dispose();\n }\n\n /**\n * Check the duration to see if the LiveDisplay should be showing or not. Then show/hide\n * it accordingly\n *\n * @param {Event} [event]\n * The {@link Player#durationchange} event that caused this function to run.\n *\n * @listens Player#durationchange\n */\n updateShowing(event) {\n if (this.player().duration() === Infinity) {\n this.show();\n } else {\n this.hide();\n }\n }\n }\n Component.registerComponent('LiveDisplay', LiveDisplay);\n\n /**\n * @file seek-to-live.js\n */\n\n /** @import Player from './player' */\n\n /**\n * Displays the live indicator when duration is Infinity.\n *\n * @extends Component\n */\n class SeekToLive extends Button {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.updateLiveEdgeStatus();\n if (this.player_.liveTracker) {\n this.updateLiveEdgeStatusHandler_ = e => this.updateLiveEdgeStatus(e);\n this.on(this.player_.liveTracker, 'liveedgechange', this.updateLiveEdgeStatusHandler_);\n }\n }\n\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n const el = super.createEl('button', {\n className: 'vjs-seek-to-live-control vjs-control'\n });\n this.setIcon('circle', el);\n this.textEl_ = createEl('span', {\n className: 'vjs-seek-to-live-text',\n textContent: this.localize('LIVE')\n }, {\n 'aria-hidden': 'true'\n });\n el.appendChild(this.textEl_);\n return el;\n }\n\n /**\n * Update the state of this button if we are at the live edge\n * or not\n */\n updateLiveEdgeStatus() {\n // default to live edge\n if (!this.player_.liveTracker || this.player_.liveTracker.atLiveEdge()) {\n this.setAttribute('aria-disabled', true);\n this.addClass('vjs-at-live-edge');\n this.controlText('Seek to live, currently playing live');\n } else {\n this.setAttribute('aria-disabled', false);\n this.removeClass('vjs-at-live-edge');\n this.controlText('Seek to live, currently behind live');\n }\n }\n\n /**\n * On click bring us as near to the live point as possible.\n * This requires that we wait for the next `live-seekable-change`\n * event which will happen every segment length seconds.\n */\n handleClick() {\n this.player_.liveTracker.seekToLiveEdge();\n }\n\n /**\n * Dispose of the element and stop tracking\n */\n dispose() {\n if (this.player_.liveTracker) {\n this.off(this.player_.liveTracker, 'liveedgechange', this.updateLiveEdgeStatusHandler_);\n }\n this.textEl_ = null;\n super.dispose();\n }\n }\n /**\n * The text that should display over the `SeekToLive`s control. Added for localization.\n *\n * @type {string}\n * @protected\n */\n SeekToLive.prototype.controlText_ = 'Seek to live, currently playing live';\n Component.registerComponent('SeekToLive', SeekToLive);\n\n /**\n * @file num.js\n * @module num\n */\n\n /**\n * Keep a number between a min and a max value\n *\n * @param {number} number\n * The number to clamp\n *\n * @param {number} min\n * The minimum value\n * @param {number} max\n * The maximum value\n *\n * @return {number}\n * the clamped number\n */\n function clamp(number, min, max) {\n number = Number(number);\n return Math.min(max, Math.max(min, isNaN(number) ? min : number));\n }\n\n var Num = /*#__PURE__*/Object.freeze({\n __proto__: null,\n clamp: clamp\n });\n\n /**\n * @file slider.js\n */\n\n /** @import Player from '../player' */\n\n /**\n * The base functionality for a slider. Can be vertical or horizontal.\n * For instance the volume bar or the seek bar on a video is a slider.\n *\n * @extends Component\n */\n class Slider extends Component {\n /**\n * Create an instance of this class\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.handleMouseDown_ = e => this.handleMouseDown(e);\n this.handleMouseUp_ = e => this.handleMouseUp(e);\n this.handleKeyDown_ = e => this.handleKeyDown(e);\n this.handleClick_ = e => this.handleClick(e);\n this.handleMouseMove_ = e => this.handleMouseMove(e);\n this.update_ = e => this.update(e);\n\n // Set property names to bar to match with the child Slider class is looking for\n this.bar = this.getChild(this.options_.barName);\n\n // Set a horizontal or vertical class on the slider depending on the slider type\n this.vertical(!!this.options_.vertical);\n this.enable();\n }\n\n /**\n * Are controls are currently enabled for this slider or not.\n *\n * @return {boolean}\n * true if controls are enabled, false otherwise\n */\n enabled() {\n return this.enabled_;\n }\n\n /**\n * Enable controls for this slider if they are disabled\n */\n enable() {\n if (this.enabled()) {\n return;\n }\n this.on('mousedown', this.handleMouseDown_);\n this.on('touchstart', this.handleMouseDown_);\n this.on('keydown', this.handleKeyDown_);\n this.on('click', this.handleClick_);\n\n // TODO: deprecated, controlsvisible does not seem to be fired\n this.on(this.player_, 'controlsvisible', this.update);\n if (this.playerEvent) {\n this.on(this.player_, this.playerEvent, this.update);\n }\n this.removeClass('disabled');\n this.setAttribute('tabindex', 0);\n this.enabled_ = true;\n }\n\n /**\n * Disable controls for this slider if they are enabled\n */\n disable() {\n if (!this.enabled()) {\n return;\n }\n const doc = this.bar.el_.ownerDocument;\n this.off('mousedown', this.handleMouseDown_);\n this.off('touchstart', this.handleMouseDown_);\n this.off('keydown', this.handleKeyDown_);\n this.off('click', this.handleClick_);\n this.off(this.player_, 'controlsvisible', this.update_);\n this.off(doc, 'mousemove', this.handleMouseMove_);\n this.off(doc, 'mouseup', this.handleMouseUp_);\n this.off(doc, 'touchmove', this.handleMouseMove_);\n this.off(doc, 'touchend', this.handleMouseUp_);\n this.removeAttribute('tabindex');\n this.addClass('disabled');\n if (this.playerEvent) {\n this.off(this.player_, this.playerEvent, this.update);\n }\n this.enabled_ = false;\n }\n\n /**\n * Create the `Slider`s DOM element.\n *\n * @param {string} type\n * Type of element to create.\n *\n * @param {Object} [props={}]\n * List of properties in Object form.\n *\n * @param {Object} [attributes={}]\n * list of attributes in Object form.\n *\n * @return {Element}\n * The element that gets created.\n */\n createEl(type, props = {}, attributes = {}) {\n // Add the slider element class to all sub classes\n props.className = props.className + ' vjs-slider';\n props = Object.assign({\n tabIndex: 0\n }, props);\n attributes = Object.assign({\n 'role': 'slider',\n 'aria-valuenow': 0,\n 'aria-valuemin': 0,\n 'aria-valuemax': 100\n }, attributes);\n return super.createEl(type, props, attributes);\n }\n\n /**\n * Handle `mousedown` or `touchstart` events on the `Slider`.\n *\n * @param {MouseEvent} event\n * `mousedown` or `touchstart` event that triggered this function\n *\n * @listens mousedown\n * @listens touchstart\n * @fires Slider#slideractive\n */\n handleMouseDown(event) {\n const doc = this.bar.el_.ownerDocument;\n if (event.type === 'mousedown') {\n event.preventDefault();\n }\n // Do not call preventDefault() on touchstart in Chrome\n // to avoid console warnings. Use a 'touch-action: none' style\n // instead to prevent unintended scrolling.\n // https://developers.google.com/web/updates/2017/01/scrolling-intervention\n if (event.type === 'touchstart' && !IS_CHROME) {\n event.preventDefault();\n }\n blockTextSelection();\n this.addClass('vjs-sliding');\n /**\n * Triggered when the slider is in an active state\n *\n * @event Slider#slideractive\n * @type {MouseEvent}\n */\n this.trigger('slideractive');\n this.on(doc, 'mousemove', this.handleMouseMove_);\n this.on(doc, 'mouseup', this.handleMouseUp_);\n this.on(doc, 'touchmove', this.handleMouseMove_);\n this.on(doc, 'touchend', this.handleMouseUp_);\n this.handleMouseMove(event, true);\n }\n\n /**\n * Handle the `mousemove`, `touchmove`, and `mousedown` events on this `Slider`.\n * The `mousemove` and `touchmove` events will only only trigger this function during\n * `mousedown` and `touchstart`. This is due to {@link Slider#handleMouseDown} and\n * {@link Slider#handleMouseUp}.\n *\n * @param {MouseEvent} event\n * `mousedown`, `mousemove`, `touchstart`, or `touchmove` event that triggered\n * this function\n * @param {boolean} mouseDown this is a flag that should be set to true if `handleMouseMove` is called directly. It allows us to skip things that should not happen if coming from mouse down but should happen on regular mouse move handler. Defaults to false.\n *\n * @listens mousemove\n * @listens touchmove\n */\n handleMouseMove(event) {}\n\n /**\n * Handle `mouseup` or `touchend` events on the `Slider`.\n *\n * @param {MouseEvent} event\n * `mouseup` or `touchend` event that triggered this function.\n *\n * @listens touchend\n * @listens mouseup\n * @fires Slider#sliderinactive\n */\n handleMouseUp(event) {\n const doc = this.bar.el_.ownerDocument;\n unblockTextSelection();\n this.removeClass('vjs-sliding');\n /**\n * Triggered when the slider is no longer in an active state.\n *\n * @event Slider#sliderinactive\n * @type {Event}\n */\n this.trigger('sliderinactive');\n this.off(doc, 'mousemove', this.handleMouseMove_);\n this.off(doc, 'mouseup', this.handleMouseUp_);\n this.off(doc, 'touchmove', this.handleMouseMove_);\n this.off(doc, 'touchend', this.handleMouseUp_);\n this.update();\n }\n\n /**\n * Update the progress bar of the `Slider`.\n *\n * @return {number}\n * The percentage of progress the progress bar represents as a\n * number from 0 to 1.\n */\n update() {\n // In VolumeBar init we have a setTimeout for update that pops and update\n // to the end of the execution stack. The player is destroyed before then\n // update will cause an error\n // If there's no bar...\n if (!this.el_ || !this.bar) {\n return;\n }\n\n // clamp progress between 0 and 1\n // and only round to four decimal places, as we round to two below\n const progress = this.getProgress();\n if (progress === this.progress_) {\n return progress;\n }\n this.progress_ = progress;\n this.requestNamedAnimationFrame('Slider#update', () => {\n // Set the new bar width or height\n const sizeKey = this.vertical() ? 'height' : 'width';\n\n // Convert to a percentage for css value\n this.bar.el().style[sizeKey] = (progress * 100).toFixed(2) + '%';\n });\n return progress;\n }\n\n /**\n * Get the percentage of the bar that should be filled\n * but clamped and rounded.\n *\n * @return {number}\n * percentage filled that the slider is\n */\n getProgress() {\n return Number(clamp(this.getPercent(), 0, 1).toFixed(4));\n }\n\n /**\n * Calculate distance for slider\n *\n * @param {Event} event\n * The event that caused this function to run.\n *\n * @return {number}\n * The current position of the Slider.\n * - position.x for vertical `Slider`s\n * - position.y for horizontal `Slider`s\n */\n calculateDistance(event) {\n const position = getPointerPosition(this.el_, event);\n if (this.vertical()) {\n return position.y;\n }\n return position.x;\n }\n\n /**\n * Handle a `keydown` event on the `Slider`. Watches for left, right, up, and down\n * arrow keys. This function will only be called when the slider has focus. See\n * {@link Slider#handleFocus} and {@link Slider#handleBlur}.\n *\n * @param {KeyboardEvent} event\n * the `keydown` event that caused this function to run.\n *\n * @listens keydown\n */\n handleKeyDown(event) {\n const spatialNavOptions = this.options_.playerOptions.spatialNavigation;\n const spatialNavEnabled = spatialNavOptions && spatialNavOptions.enabled;\n const horizontalSeek = spatialNavOptions && spatialNavOptions.horizontalSeek;\n if (spatialNavEnabled) {\n if (horizontalSeek && event.key === 'ArrowLeft' || !horizontalSeek && event.key === 'ArrowDown') {\n event.preventDefault();\n event.stopPropagation();\n this.stepBack();\n } else if (horizontalSeek && event.key === 'ArrowRight' || !horizontalSeek && event.key === 'ArrowUp') {\n event.preventDefault();\n event.stopPropagation();\n this.stepForward();\n } else {\n if (this.pendingSeekTime()) {\n this.pendingSeekTime(null);\n this.userSeek_(this.player_.currentTime());\n }\n super.handleKeyDown(event);\n }\n\n // Left and Down Arrows\n } else if (event.key === 'ArrowLeft' || event.key === 'ArrowDown') {\n event.preventDefault();\n event.stopPropagation();\n this.stepBack();\n\n // Up and Right Arrows\n } else if (event.key === 'ArrowUp' || event.key === 'ArrowRight') {\n event.preventDefault();\n event.stopPropagation();\n this.stepForward();\n } else {\n // Pass keydown handling up for unsupported keys\n super.handleKeyDown(event);\n }\n }\n\n /**\n * Listener for click events on slider, used to prevent clicks\n * from bubbling up to parent elements like button menus.\n *\n * @param {Object} event\n * Event that caused this object to run\n */\n handleClick(event) {\n event.stopPropagation();\n event.preventDefault();\n }\n\n /**\n * Get/set if slider is horizontal for vertical\n *\n * @param {boolean} [bool]\n * - true if slider is vertical,\n * - false is horizontal\n *\n * @return {boolean}\n * - true if slider is vertical, and getting\n * - false if the slider is horizontal, and getting\n */\n vertical(bool) {\n if (bool === undefined) {\n return this.vertical_ || false;\n }\n this.vertical_ = !!bool;\n if (this.vertical_) {\n this.addClass('vjs-slider-vertical');\n } else {\n this.addClass('vjs-slider-horizontal');\n }\n }\n }\n Component.registerComponent('Slider', Slider);\n\n /**\n * @file load-progress-bar.js\n */\n\n /** @import Player from '../../player' */\n\n // get the percent width of a time compared to the total end\n const percentify = (time, end) => clamp(time / end * 100, 0, 100).toFixed(2) + '%';\n\n /**\n * Shows loading progress\n *\n * @extends Component\n */\n class LoadProgressBar extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.partEls_ = [];\n this.on(player, 'progress', e => this.update(e));\n }\n\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n const el = super.createEl('div', {\n className: 'vjs-load-progress'\n });\n const wrapper = createEl('span', {\n className: 'vjs-control-text'\n });\n const loadedText = createEl('span', {\n textContent: this.localize('Loaded')\n });\n const separator = document.createTextNode(': ');\n this.percentageEl_ = createEl('span', {\n className: 'vjs-control-text-loaded-percentage',\n textContent: '0%'\n });\n el.appendChild(wrapper);\n wrapper.appendChild(loadedText);\n wrapper.appendChild(separator);\n wrapper.appendChild(this.percentageEl_);\n return el;\n }\n dispose() {\n this.partEls_ = null;\n this.percentageEl_ = null;\n super.dispose();\n }\n\n /**\n * Update progress bar\n *\n * @param {Event} [event]\n * The `progress` event that caused this function to run.\n *\n * @listens Player#progress\n */\n update(event) {\n this.requestNamedAnimationFrame('LoadProgressBar#update', () => {\n const liveTracker = this.player_.liveTracker;\n const buffered = this.player_.buffered();\n const duration = liveTracker && liveTracker.isLive() ? liveTracker.seekableEnd() : this.player_.duration();\n const bufferedEnd = this.player_.bufferedEnd();\n const children = this.partEls_;\n const percent = percentify(bufferedEnd, duration);\n if (this.percent_ !== percent) {\n // update the width of the progress bar\n this.el_.style.width = percent;\n // update the control-text\n textContent(this.percentageEl_, percent);\n this.percent_ = percent;\n }\n\n // add child elements to represent the individual buffered time ranges\n for (let i = 0; i < buffered.length; i++) {\n const start = buffered.start(i);\n const end = buffered.end(i);\n let part = children[i];\n if (!part) {\n part = this.el_.appendChild(createEl());\n children[i] = part;\n }\n\n // only update if changed\n if (part.dataset.start === start && part.dataset.end === end) {\n continue;\n }\n part.dataset.start = start;\n part.dataset.end = end;\n\n // set the percent based on the width of the progress bar (bufferedEnd)\n part.style.left = percentify(start, bufferedEnd);\n part.style.width = percentify(end - start, bufferedEnd);\n }\n\n // remove unused buffered range elements\n for (let i = children.length; i > buffered.length; i--) {\n this.el_.removeChild(children[i - 1]);\n }\n children.length = buffered.length;\n });\n }\n }\n Component.registerComponent('LoadProgressBar', LoadProgressBar);\n\n /**\n * @file time-tooltip.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * Time tooltips display a time above the progress bar.\n *\n * @extends Component\n */\n class TimeTooltip extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The {@link Player} that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.update = throttle(bind_(this, this.update), UPDATE_REFRESH_INTERVAL);\n }\n\n /**\n * Create the time tooltip DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n return super.createEl('div', {\n className: 'vjs-time-tooltip'\n }, {\n 'aria-hidden': 'true'\n });\n }\n\n /**\n * Updates the position of the time tooltip relative to the `SeekBar`.\n *\n * @param {Object} seekBarRect\n * The `ClientRect` for the {@link SeekBar} element.\n *\n * @param {number} seekBarPoint\n * A number from 0 to 1, representing a horizontal reference point\n * from the left edge of the {@link SeekBar}\n */\n update(seekBarRect, seekBarPoint, content) {\n const tooltipRect = findPosition(this.el_);\n const playerRect = getBoundingClientRect(this.player_.el());\n const seekBarPointPx = seekBarRect.width * seekBarPoint;\n\n // do nothing if either rect isn't available\n // for example, if the player isn't in the DOM for testing\n if (!playerRect || !tooltipRect) {\n return;\n }\n\n // This is the space left of the `seekBarPoint` available within the bounds\n // of the player. We calculate any gap between the left edge of the player\n // and the left edge of the `SeekBar` and add the number of pixels in the\n // `SeekBar` before hitting the `seekBarPoint`\n let spaceLeftOfPoint = seekBarRect.left - playerRect.left + seekBarPointPx;\n\n // This is the space right of the `seekBarPoint` available within the bounds\n // of the player. We calculate the number of pixels from the `seekBarPoint`\n // to the right edge of the `SeekBar` and add to that any gap between the\n // right edge of the `SeekBar` and the player.\n let spaceRightOfPoint = seekBarRect.width - seekBarPointPx + (playerRect.right - seekBarRect.right);\n\n // spaceRightOfPoint is always NaN for mouse time display\n // because the seekbarRect does not have a right property. This causes\n // the mouse tool tip to be truncated when it's close to the right edge of the player.\n // In such cases, we ignore the `playerRect.right - seekBarRect.right` value when calculating.\n // For the sake of consistency, we ignore seekBarRect.left - playerRect.left for the left edge.\n if (!spaceRightOfPoint) {\n spaceRightOfPoint = seekBarRect.width - seekBarPointPx;\n spaceLeftOfPoint = seekBarPointPx;\n }\n // This is the number of pixels by which the tooltip will need to be pulled\n // further to the right to center it over the `seekBarPoint`.\n let pullTooltipBy = tooltipRect.width / 2;\n\n // Adjust the `pullTooltipBy` distance to the left or right depending on\n // the results of the space calculations above.\n if (spaceLeftOfPoint < pullTooltipBy) {\n pullTooltipBy += pullTooltipBy - spaceLeftOfPoint;\n } else if (spaceRightOfPoint < pullTooltipBy) {\n pullTooltipBy = spaceRightOfPoint;\n }\n\n // Due to the imprecision of decimal/ratio based calculations and varying\n // rounding behaviors, there are cases where the spacing adjustment is off\n // by a pixel or two. This adds insurance to these calculations.\n if (pullTooltipBy < 0) {\n pullTooltipBy = 0;\n } else if (pullTooltipBy > tooltipRect.width) {\n pullTooltipBy = tooltipRect.width;\n }\n\n // prevent small width fluctuations within 0.4px from\n // changing the value below.\n // This really helps for live to prevent the play\n // progress time tooltip from jittering\n pullTooltipBy = Math.round(pullTooltipBy);\n this.el_.style.right = `-${pullTooltipBy}px`;\n this.write(content);\n }\n\n /**\n * Write the time to the tooltip DOM element.\n *\n * @param {string} content\n * The formatted time for the tooltip.\n */\n write(content) {\n textContent(this.el_, content);\n }\n\n /**\n * Updates the position of the time tooltip relative to the `SeekBar`.\n *\n * @param {Object} seekBarRect\n * The `ClientRect` for the {@link SeekBar} element.\n *\n * @param {number} seekBarPoint\n * A number from 0 to 1, representing a horizontal reference point\n * from the left edge of the {@link SeekBar}\n *\n * @param {number} time\n * The time to update the tooltip to, not used during live playback\n *\n * @param {Function} cb\n * A function that will be called during the request animation frame\n * for tooltips that need to do additional animations from the default\n */\n updateTime(seekBarRect, seekBarPoint, time, cb) {\n this.requestNamedAnimationFrame('TimeTooltip#updateTime', () => {\n let content;\n const duration = this.player_.duration();\n if (this.player_.liveTracker && this.player_.liveTracker.isLive()) {\n const liveWindow = this.player_.liveTracker.liveWindow();\n const secondsBehind = liveWindow - seekBarPoint * liveWindow;\n content = (secondsBehind < 1 ? '' : '-') + formatTime(secondsBehind, liveWindow);\n } else {\n content = formatTime(time, duration);\n }\n this.update(seekBarRect, seekBarPoint, content);\n if (cb) {\n cb();\n }\n });\n }\n }\n Component.registerComponent('TimeTooltip', TimeTooltip);\n\n /**\n * @file play-progress-bar.js\n */\n\n /**\n * Used by {@link SeekBar} to display media playback progress as part of the\n * {@link ProgressControl}.\n *\n * @extends Component\n */\n class PlayProgressBar extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The {@link Player} that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.setIcon('circle');\n this.update = throttle(bind_(this, this.update), UPDATE_REFRESH_INTERVAL);\n }\n\n /**\n * Create the the DOM element for this class.\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n return super.createEl('div', {\n className: 'vjs-play-progress vjs-slider-bar'\n }, {\n 'aria-hidden': 'true'\n });\n }\n\n /**\n * Enqueues updates to its own DOM as well as the DOM of its\n * {@link TimeTooltip} child.\n *\n * @param {Object} seekBarRect\n * The `ClientRect` for the {@link SeekBar} element.\n *\n * @param {number} seekBarPoint\n * A number from 0 to 1, representing a horizontal reference point\n * from the left edge of the {@link SeekBar}\n *\n * @param {Event} [event]\n * The `timeupdate` event that caused this function to run.\n */\n update(seekBarRect, seekBarPoint, event) {\n const timeTooltip = this.getChild('timeTooltip');\n if (!timeTooltip) {\n return;\n }\n\n // Combined logic: if an event with a valid pendingSeekTime getter exists, use it.\n const time = event && event.target && typeof event.target.pendingSeekTime === 'function' ? event.target.pendingSeekTime() : this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();\n timeTooltip.updateTime(seekBarRect, seekBarPoint, time);\n }\n }\n\n /**\n * Default options for {@link PlayProgressBar}.\n *\n * @type {Object}\n * @private\n */\n PlayProgressBar.prototype.options_ = {\n children: []\n };\n\n // Time tooltips should not be added to a player on mobile devices\n if (!IS_IOS && !IS_ANDROID) {\n PlayProgressBar.prototype.options_.children.push('timeTooltip');\n }\n Component.registerComponent('PlayProgressBar', PlayProgressBar);\n\n /**\n * @file mouse-time-display.js\n */\n\n /**\n * The {@link MouseTimeDisplay} component tracks mouse movement over the\n * {@link ProgressControl}. It displays an indicator and a {@link TimeTooltip}\n * indicating the time which is represented by a given point in the\n * {@link ProgressControl}.\n *\n * @extends Component\n */\n class MouseTimeDisplay extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The {@link Player} that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.update = throttle(bind_(this, this.update), UPDATE_REFRESH_INTERVAL);\n }\n\n /**\n * Create the DOM element for this class.\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n return super.createEl('div', {\n className: 'vjs-mouse-display'\n });\n }\n\n /**\n * Enqueues updates to its own DOM as well as the DOM of its\n * {@link TimeTooltip} child.\n *\n * @param {Object} seekBarRect\n * The `ClientRect` for the {@link SeekBar} element.\n *\n * @param {number} seekBarPoint\n * A number from 0 to 1, representing a horizontal reference point\n * from the left edge of the {@link SeekBar}\n */\n update(seekBarRect, seekBarPoint) {\n const time = seekBarPoint * this.player_.duration();\n this.getChild('timeTooltip').updateTime(seekBarRect, seekBarPoint, time, () => {\n this.el_.style.left = `${seekBarRect.width * seekBarPoint}px`;\n });\n }\n }\n\n /**\n * Default options for `MouseTimeDisplay`\n *\n * @type {Object}\n * @private\n */\n MouseTimeDisplay.prototype.options_ = {\n children: ['timeTooltip']\n };\n Component.registerComponent('MouseTimeDisplay', MouseTimeDisplay);\n\n /**\n * @file seek-bar.js\n */\n\n /**\n * Seek bar and container for the progress bars. Uses {@link PlayProgressBar}\n * as its `bar`.\n *\n * @extends Slider\n */\n class SeekBar extends Slider {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n * @param {number} [options.stepSeconds=5]\n * The number of seconds to increment on keyboard control\n * @param {number} [options.pageMultiplier=12]\n * The multiplier of stepSeconds that PgUp/PgDown move the timeline.\n */\n constructor(player, options) {\n options = merge(SeekBar.prototype.options_, options);\n\n // Avoid mutating the prototype's `children` array by creating a copy\n options.children = [...options.children];\n const shouldDisableSeekWhileScrubbing = player.options_.disableSeekWhileScrubbingOnMobile && (IS_IOS || IS_ANDROID) || player.options_.disableSeekWhileScrubbingOnSTV;\n\n // Add the TimeTooltip as a child if we are on desktop, or on mobile with `disableSeekWhileScrubbingOnMobile: true`\n if (!IS_IOS && !IS_ANDROID || shouldDisableSeekWhileScrubbing) {\n options.children.splice(1, 0, 'mouseTimeDisplay');\n }\n super(player, options);\n this.shouldDisableSeekWhileScrubbing_ = shouldDisableSeekWhileScrubbing;\n this.pendingSeekTime_ = null;\n this.setEventHandlers_();\n }\n\n /**\n * Sets the event handlers\n *\n * @private\n */\n setEventHandlers_() {\n this.update_ = bind_(this, this.update);\n this.update = throttle(this.update_, UPDATE_REFRESH_INTERVAL);\n this.on(this.player_, ['durationchange', 'timeupdate'], this.update);\n this.on(this.player_, ['ended'], this.update_);\n if (this.player_.liveTracker) {\n this.on(this.player_.liveTracker, 'liveedgechange', this.update);\n }\n\n // when playing, let's ensure we smoothly update the play progress bar\n // via an interval\n this.updateInterval = null;\n this.enableIntervalHandler_ = e => this.enableInterval_(e);\n this.disableIntervalHandler_ = e => this.disableInterval_(e);\n this.on(this.player_, ['playing'], this.enableIntervalHandler_);\n this.on(this.player_, ['ended', 'pause', 'waiting'], this.disableIntervalHandler_);\n\n // we don't need to update the play progress if the document is hidden,\n // also, this causes the CPU to spike and eventually crash the page on IE11.\n if ('hidden' in document && 'visibilityState' in document) {\n this.on(document, 'visibilitychange', this.toggleVisibility_);\n }\n }\n toggleVisibility_(e) {\n if (document.visibilityState === 'hidden') {\n this.cancelNamedAnimationFrame('SeekBar#update');\n this.cancelNamedAnimationFrame('Slider#update');\n this.disableInterval_(e);\n } else {\n if (!this.player_.ended() && !this.player_.paused()) {\n this.enableInterval_();\n }\n\n // we just switched back to the page and someone may be looking, so, update ASAP\n this.update();\n }\n }\n enableInterval_() {\n if (this.updateInterval) {\n return;\n }\n this.updateInterval = this.setInterval(this.update, UPDATE_REFRESH_INTERVAL);\n }\n disableInterval_(e) {\n if (this.player_.liveTracker && this.player_.liveTracker.isLive() && e && e.type !== 'ended') {\n return;\n }\n if (!this.updateInterval) {\n return;\n }\n this.clearInterval(this.updateInterval);\n this.updateInterval = null;\n }\n\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n return super.createEl('div', {\n className: 'vjs-progress-holder'\n }, {\n 'aria-label': this.localize('Progress Bar')\n });\n }\n\n /**\n * This function updates the play progress bar and accessibility\n * attributes to whatever is passed in.\n *\n * @param {Event} [event]\n * The `timeupdate` or `ended` event that caused this to run.\n *\n * @listens Player#timeupdate\n *\n * @return {number}\n * The current percent at a number from 0-1\n */\n update(event) {\n // ignore updates while the tab is hidden\n if (document.visibilityState === 'hidden') {\n return;\n }\n const percent = super.update();\n this.requestNamedAnimationFrame('SeekBar#update', () => {\n const currentTime = this.player_.ended() ? this.player_.duration() : this.getCurrentTime_();\n const liveTracker = this.player_.liveTracker;\n let duration = this.player_.duration();\n if (liveTracker && liveTracker.isLive()) {\n duration = this.player_.liveTracker.liveCurrentTime();\n }\n if (this.percent_ !== percent) {\n // machine readable value of progress bar (percentage complete)\n this.el_.setAttribute('aria-valuenow', (percent * 100).toFixed(2));\n this.percent_ = percent;\n }\n if (this.currentTime_ !== currentTime || this.duration_ !== duration) {\n // human readable value of progress bar (time complete)\n this.el_.setAttribute('aria-valuetext', this.localize('progress bar timing: currentTime={1} duration={2}', [formatTime(currentTime, duration), formatTime(duration, duration)], '{1} of {2}'));\n this.currentTime_ = currentTime;\n this.duration_ = duration;\n }\n\n // update the progress bar time tooltip with the current time\n if (this.bar) {\n this.bar.update(getBoundingClientRect(this.el()), this.getProgress(), event);\n }\n });\n return percent;\n }\n\n /**\n * Prevent liveThreshold from causing seeks to seem like they\n * are not happening from a user perspective.\n *\n * @param {number} ct\n * current time to seek to\n */\n userSeek_(ct) {\n if (this.player_.liveTracker && this.player_.liveTracker.isLive()) {\n this.player_.liveTracker.nextSeekedFromUser();\n }\n this.player_.currentTime(ct);\n }\n\n /**\n * Get the value of current time but allows for smooth scrubbing,\n * when player can't keep up.\n *\n * @return {number}\n * The current time value to display\n *\n * @private\n */\n getCurrentTime_() {\n return this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();\n }\n\n /**\n * Getter and setter for pendingSeekTime.\n * Ensures the value is clamped between 0 and duration.\n *\n * @param {number|null} [time] - Optional. The new pending seek time, can be a number or null.\n * @return {number|null} - The current pending seek time.\n */\n pendingSeekTime(time) {\n if (time !== undefined) {\n if (time !== null) {\n const duration = this.player_.duration();\n this.pendingSeekTime_ = Math.max(0, Math.min(time, duration));\n } else {\n this.pendingSeekTime_ = null;\n }\n }\n return this.pendingSeekTime_;\n }\n\n /**\n * Get the percentage of media played so far.\n *\n * @return {number}\n * The percentage of media played so far (0 to 1).\n */\n getPercent() {\n // If we have a pending seek time, we are scrubbing on mobile and should set the slider percent\n // to reflect the current scrub location.\n if (this.pendingSeekTime() !== null) {\n return this.pendingSeekTime() / this.player_.duration();\n }\n const currentTime = this.getCurrentTime_();\n let percent;\n const liveTracker = this.player_.liveTracker;\n if (liveTracker && liveTracker.isLive()) {\n percent = (currentTime - liveTracker.seekableStart()) / liveTracker.liveWindow();\n\n // prevent the percent from changing at the live edge\n if (liveTracker.atLiveEdge()) {\n percent = 1;\n }\n } else {\n percent = currentTime / this.player_.duration();\n }\n return percent;\n }\n\n /**\n * Handle mouse down on seek bar\n *\n * @param {MouseEvent} event\n * The `mousedown` event that caused this to run.\n *\n * @listens mousedown\n */\n handleMouseDown(event) {\n if (!isSingleLeftClick(event)) {\n return;\n }\n\n // Stop event propagation to prevent double fire in progress-control.js\n event.stopPropagation();\n this.videoWasPlaying = !this.player_.paused();\n\n // Don't pause if we are on mobile and `disableSeekWhileScrubbingOnMobile: true`.\n // In that case, playback should continue while the player scrubs to a new location.\n if (!this.shouldDisableSeekWhileScrubbing_) {\n this.player_.pause();\n }\n super.handleMouseDown(event);\n }\n\n /**\n * Handle mouse move on seek bar\n *\n * @param {MouseEvent} event\n * The `mousemove` event that caused this to run.\n * @param {boolean} mouseDown this is a flag that should be set to true if `handleMouseMove` is called directly. It allows us to skip things that should not happen if coming from mouse down but should happen on regular mouse move handler. Defaults to false\n *\n * @listens mousemove\n */\n handleMouseMove(event, mouseDown = false) {\n if (!isSingleLeftClick(event) || isNaN(this.player_.duration())) {\n return;\n }\n if (!mouseDown && !this.player_.scrubbing()) {\n this.player_.scrubbing(true);\n }\n let newTime;\n const distance = this.calculateDistance(event);\n const liveTracker = this.player_.liveTracker;\n if (!liveTracker || !liveTracker.isLive()) {\n newTime = distance * this.player_.duration();\n\n // Don't let video end while scrubbing.\n if (newTime === this.player_.duration()) {\n newTime = newTime - 0.1;\n }\n } else {\n if (distance >= 0.99) {\n liveTracker.seekToLiveEdge();\n return;\n }\n const seekableStart = liveTracker.seekableStart();\n const seekableEnd = liveTracker.liveCurrentTime();\n newTime = seekableStart + distance * liveTracker.liveWindow();\n\n // Don't let video end while scrubbing.\n if (newTime >= seekableEnd) {\n newTime = seekableEnd;\n }\n\n // Compensate for precision differences so that currentTime is not less\n // than seekable start\n if (newTime <= seekableStart) {\n newTime = seekableStart + 0.1;\n }\n\n // On android seekableEnd can be Infinity sometimes,\n // this will cause newTime to be Infinity, which is\n // not a valid currentTime.\n if (newTime === Infinity) {\n return;\n }\n }\n\n // if on mobile and `disableSeekWhileScrubbingOnMobile: true`, keep track of the desired seek point but we won't initiate the seek until 'touchend'\n if (this.shouldDisableSeekWhileScrubbing_) {\n this.pendingSeekTime(newTime);\n } else {\n this.userSeek_(newTime);\n }\n if (this.player_.options_.enableSmoothSeeking) {\n this.update();\n }\n }\n enable() {\n super.enable();\n const mouseTimeDisplay = this.getChild('mouseTimeDisplay');\n if (!mouseTimeDisplay) {\n return;\n }\n mouseTimeDisplay.show();\n }\n disable() {\n super.disable();\n const mouseTimeDisplay = this.getChild('mouseTimeDisplay');\n if (!mouseTimeDisplay) {\n return;\n }\n mouseTimeDisplay.hide();\n }\n\n /**\n * Handle mouse up on seek bar\n *\n * @param {MouseEvent} event\n * The `mouseup` event that caused this to run.\n *\n * @listens mouseup\n */\n handleMouseUp(event) {\n super.handleMouseUp(event);\n\n // Stop event propagation to prevent double fire in progress-control.js\n if (event) {\n event.stopPropagation();\n }\n this.player_.scrubbing(false);\n\n // If we have a pending seek time, then we have finished scrubbing on mobile and should initiate a seek.\n if (this.pendingSeekTime() !== null) {\n this.userSeek_(this.pendingSeekTime());\n this.pendingSeekTime(null);\n }\n\n /**\n * Trigger timeupdate because we're done seeking and the time has changed.\n * This is particularly useful for if the player is paused to time the time displays.\n *\n * @event Tech#timeupdate\n * @type {Event}\n */\n this.player_.trigger({\n type: 'timeupdate',\n target: this,\n manuallyTriggered: true\n });\n if (this.videoWasPlaying) {\n silencePromise(this.player_.play());\n } else {\n // We're done seeking and the time has changed.\n // If the player is paused, make sure we display the correct time on the seek bar.\n this.update_();\n }\n }\n\n /**\n * Handles pending seek time when `disableSeekWhileScrubbingOnSTV` is enabled.\n *\n * @param {number} stepAmount - The number of seconds to step (positive for forward, negative for backward).\n */\n handlePendingSeek_(stepAmount) {\n if (!this.player_.paused()) {\n this.player_.pause();\n }\n const currentPos = this.pendingSeekTime() !== null ? this.pendingSeekTime() : this.player_.currentTime();\n this.pendingSeekTime(currentPos + stepAmount);\n this.player_.trigger({\n type: 'timeupdate',\n target: this,\n manuallyTriggered: true\n });\n }\n\n /**\n * Move more quickly fast forward for keyboard-only users\n */\n stepForward() {\n // if `disableSeekWhileScrubbingOnSTV: true`, keep track of the desired seek point but we won't initiate the seek\n if (this.shouldDisableSeekWhileScrubbing_) {\n this.handlePendingSeek_(this.options().stepSeconds);\n } else {\n this.userSeek_(this.player_.currentTime() + this.options().stepSeconds);\n }\n }\n\n /**\n * Move more quickly rewind for keyboard-only users\n */\n stepBack() {\n // if `disableSeekWhileScrubbingOnSTV: true`, keep track of the desired seek point but we won't initiate the seek\n if (this.shouldDisableSeekWhileScrubbing_) {\n this.handlePendingSeek_(-this.options().stepSeconds);\n } else {\n this.userSeek_(this.player_.currentTime() - this.options().stepSeconds);\n }\n }\n\n /**\n * Toggles the playback state of the player\n * This gets called when enter or space is used on the seekbar\n *\n * @param {KeyboardEvent} event\n * The `keydown` event that caused this function to be called\n *\n */\n handleAction(event) {\n if (this.pendingSeekTime() !== null) {\n this.userSeek_(this.pendingSeekTime());\n this.pendingSeekTime(null);\n }\n if (this.player_.paused()) {\n this.player_.play();\n } else {\n this.player_.pause();\n }\n }\n\n /**\n * Called when this SeekBar has focus and a key gets pressed down.\n * Supports the following keys:\n *\n * Space or Enter key fire a click event\n * Home key moves to start of the timeline\n * End key moves to end of the timeline\n * Digit \"0\" through \"9\" keys move to 0%, 10% ... 80%, 90% of the timeline\n * PageDown key moves back a larger step than ArrowDown\n * PageUp key moves forward a large step\n *\n * @param {KeyboardEvent} event\n * The `keydown` event that caused this function to be called.\n *\n * @listens keydown\n */\n handleKeyDown(event) {\n const liveTracker = this.player_.liveTracker;\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault();\n event.stopPropagation();\n this.handleAction(event);\n } else if (event.key === 'Home') {\n event.preventDefault();\n event.stopPropagation();\n this.userSeek_(0);\n } else if (event.key === 'End') {\n event.preventDefault();\n event.stopPropagation();\n if (liveTracker && liveTracker.isLive()) {\n this.userSeek_(liveTracker.liveCurrentTime());\n } else {\n this.userSeek_(this.player_.duration());\n }\n } else if (/^[0-9]$/.test(event.key)) {\n event.preventDefault();\n event.stopPropagation();\n const gotoFraction = parseInt(event.key, 10) * 0.1;\n if (liveTracker && liveTracker.isLive()) {\n this.userSeek_(liveTracker.seekableStart() + liveTracker.liveWindow() * gotoFraction);\n } else {\n this.userSeek_(this.player_.duration() * gotoFraction);\n }\n } else if (event.key === 'PageDown') {\n event.preventDefault();\n event.stopPropagation();\n this.userSeek_(this.player_.currentTime() - this.options().stepSeconds * this.options().pageMultiplier);\n } else if (event.key === 'PageUp') {\n event.preventDefault();\n event.stopPropagation();\n this.userSeek_(this.player_.currentTime() + this.options().stepSeconds * this.options().pageMultiplier);\n } else {\n // Pass keydown handling up for unsupported keys\n super.handleKeyDown(event);\n }\n }\n dispose() {\n this.disableInterval_();\n this.off(this.player_, ['durationchange', 'timeupdate'], this.update);\n this.off(this.player_, ['ended'], this.update_);\n if (this.player_.liveTracker) {\n this.off(this.player_.liveTracker, 'liveedgechange', this.update);\n }\n this.off(this.player_, ['playing'], this.enableIntervalHandler_);\n this.off(this.player_, ['ended', 'pause', 'waiting'], this.disableIntervalHandler_);\n\n // we don't need to update the play progress if the document is hidden,\n // also, this causes the CPU to spike and eventually crash the page on IE11.\n if ('hidden' in document && 'visibilityState' in document) {\n this.off(document, 'visibilitychange', this.toggleVisibility_);\n }\n super.dispose();\n }\n }\n\n /**\n * Default options for the `SeekBar`\n *\n * @type {Object}\n * @private\n */\n SeekBar.prototype.options_ = {\n children: ['loadProgressBar', 'playProgressBar'],\n barName: 'playProgressBar',\n stepSeconds: 5,\n pageMultiplier: 12\n };\n Component.registerComponent('SeekBar', SeekBar);\n\n /**\n * @file progress-control.js\n */\n\n /**\n * The Progress Control component contains the seek bar, load progress,\n * and play progress.\n *\n * @extends Component\n */\n class ProgressControl extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.handleMouseMove = throttle(bind_(this, this.handleMouseMove), UPDATE_REFRESH_INTERVAL);\n this.throttledHandleMouseSeek = throttle(bind_(this, this.handleMouseSeek), UPDATE_REFRESH_INTERVAL);\n this.handleMouseUpHandler_ = e => this.handleMouseUp(e);\n this.handleMouseDownHandler_ = e => this.handleMouseDown(e);\n this.enable();\n }\n\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n return super.createEl('div', {\n className: 'vjs-progress-control vjs-control'\n });\n }\n\n /**\n * When the mouse moves over the `ProgressControl`, the pointer position\n * gets passed down to the `MouseTimeDisplay` component.\n *\n * @param {Event} event\n * The `mousemove` event that caused this function to run.\n *\n * @listen mousemove\n */\n handleMouseMove(event) {\n const seekBar = this.getChild('seekBar');\n if (!seekBar) {\n return;\n }\n const playProgressBar = seekBar.getChild('playProgressBar');\n const mouseTimeDisplay = seekBar.getChild('mouseTimeDisplay');\n if (!playProgressBar && !mouseTimeDisplay) {\n return;\n }\n const seekBarEl = seekBar.el();\n const seekBarRect = findPosition(seekBarEl);\n let seekBarPoint = getPointerPosition(seekBarEl, event).x;\n\n // The default skin has a gap on either side of the `SeekBar`. This means\n // that it's possible to trigger this behavior outside the boundaries of\n // the `SeekBar`. This ensures we stay within it at all times.\n seekBarPoint = clamp(seekBarPoint, 0, 1);\n if (mouseTimeDisplay) {\n mouseTimeDisplay.update(seekBarRect, seekBarPoint);\n }\n if (playProgressBar) {\n playProgressBar.update(seekBarRect, seekBar.getProgress());\n }\n }\n\n /**\n * A throttled version of the {@link ProgressControl#handleMouseSeek} listener.\n *\n * @method ProgressControl#throttledHandleMouseSeek\n * @param {Event} event\n * The `mousemove` event that caused this function to run.\n *\n * @listen mousemove\n * @listen touchmove\n */\n\n /**\n * Handle `mousemove` or `touchmove` events on the `ProgressControl`.\n *\n * @param {Event} event\n * `mousedown` or `touchstart` event that triggered this function\n *\n * @listens mousemove\n * @listens touchmove\n */\n handleMouseSeek(event) {\n const seekBar = this.getChild('seekBar');\n if (seekBar) {\n seekBar.handleMouseMove(event);\n }\n }\n\n /**\n * Are controls are currently enabled for this progress control.\n *\n * @return {boolean}\n * true if controls are enabled, false otherwise\n */\n enabled() {\n return this.enabled_;\n }\n\n /**\n * Disable all controls on the progress control and its children\n */\n disable() {\n this.children().forEach(child => child.disable && child.disable());\n if (!this.enabled()) {\n return;\n }\n this.off(['mousedown', 'touchstart'], this.handleMouseDownHandler_);\n this.off(this.el_, ['mousemove', 'touchmove'], this.handleMouseMove);\n this.removeListenersAddedOnMousedownAndTouchstart();\n this.addClass('disabled');\n this.enabled_ = false;\n\n // Restore normal playback state if controls are disabled while scrubbing\n if (this.player_.scrubbing()) {\n const seekBar = this.getChild('seekBar');\n this.player_.scrubbing(false);\n if (seekBar.videoWasPlaying) {\n silencePromise(this.player_.play());\n }\n }\n }\n\n /**\n * Enable all controls on the progress control and its children\n */\n enable() {\n this.children().forEach(child => child.enable && child.enable());\n if (this.enabled()) {\n return;\n }\n this.on(['mousedown', 'touchstart'], this.handleMouseDownHandler_);\n this.on(this.el_, ['mousemove', 'touchmove'], this.handleMouseMove);\n this.removeClass('disabled');\n this.enabled_ = true;\n }\n\n /**\n * Cleanup listeners after the user finishes interacting with the progress controls\n */\n removeListenersAddedOnMousedownAndTouchstart() {\n const doc = this.el_.ownerDocument;\n this.off(doc, 'mousemove', this.throttledHandleMouseSeek);\n this.off(doc, 'touchmove', this.throttledHandleMouseSeek);\n this.off(doc, 'mouseup', this.handleMouseUpHandler_);\n this.off(doc, 'touchend', this.handleMouseUpHandler_);\n }\n\n /**\n * Handle `mousedown` or `touchstart` events on the `ProgressControl`.\n *\n * @param {Event} event\n * `mousedown` or `touchstart` event that triggered this function\n *\n * @listens mousedown\n * @listens touchstart\n */\n handleMouseDown(event) {\n const doc = this.el_.ownerDocument;\n const seekBar = this.getChild('seekBar');\n if (seekBar) {\n seekBar.handleMouseDown(event);\n }\n this.on(doc, 'mousemove', this.throttledHandleMouseSeek);\n this.on(doc, 'touchmove', this.throttledHandleMouseSeek);\n this.on(doc, 'mouseup', this.handleMouseUpHandler_);\n this.on(doc, 'touchend', this.handleMouseUpHandler_);\n }\n\n /**\n * Handle `mouseup` or `touchend` events on the `ProgressControl`.\n *\n * @param {Event} event\n * `mouseup` or `touchend` event that triggered this function.\n *\n * @listens touchend\n * @listens mouseup\n */\n handleMouseUp(event) {\n const seekBar = this.getChild('seekBar');\n if (seekBar) {\n seekBar.handleMouseUp(event);\n }\n this.removeListenersAddedOnMousedownAndTouchstart();\n }\n }\n\n /**\n * Default options for `ProgressControl`\n *\n * @type {Object}\n * @private\n */\n ProgressControl.prototype.options_ = {\n children: ['seekBar']\n };\n Component.registerComponent('ProgressControl', ProgressControl);\n\n /**\n * @file picture-in-picture-toggle.js\n */\n\n /** @import Player from './player' */\n\n /**\n * Toggle Picture-in-Picture mode\n *\n * @extends Button\n */\n class PictureInPictureToggle extends Button {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @listens Player#enterpictureinpicture\n * @listens Player#leavepictureinpicture\n */\n constructor(player, options) {\n super(player, options);\n this.setIcon('picture-in-picture-enter');\n this.on(player, ['enterpictureinpicture', 'leavepictureinpicture'], e => this.handlePictureInPictureChange(e));\n this.on(player, ['disablepictureinpicturechanged', 'loadedmetadata'], e => this.handlePictureInPictureEnabledChange(e));\n this.on(player, ['loadedmetadata', 'audioonlymodechange', 'audiopostermodechange'], () => this.handlePictureInPictureAudioModeChange());\n\n // TODO: Deactivate button on player emptied event.\n this.disable();\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-picture-in-picture-control vjs-hidden ${super.buildCSSClass()}`;\n }\n\n /**\n * Displays or hides the button depending on the audio mode detection.\n * Exits picture-in-picture if it is enabled when switching to audio mode.\n */\n handlePictureInPictureAudioModeChange() {\n // This audio detection will not detect HLS or DASH audio-only streams because there was no reliable way to detect them at the time\n const isSourceAudio = this.player_.currentType().substring(0, 5) === 'audio';\n const isAudioMode = isSourceAudio || this.player_.audioPosterMode() || this.player_.audioOnlyMode();\n if (!isAudioMode) {\n this.show();\n return;\n }\n if (this.player_.isInPictureInPicture()) {\n this.player_.exitPictureInPicture();\n }\n this.hide();\n }\n\n /**\n * Enables or disables button based on availability of a Picture-In-Picture mode.\n *\n * Enabled if\n * - `player.options().enableDocumentPictureInPicture` is true and\n * window.documentPictureInPicture is available; or\n * - `player.disablePictureInPicture()` is false and\n * element.requestPictureInPicture is available\n */\n handlePictureInPictureEnabledChange() {\n if (document.pictureInPictureEnabled && this.player_.disablePictureInPicture() === false || this.player_.options_.enableDocumentPictureInPicture && 'documentPictureInPicture' in window) {\n this.enable();\n } else {\n this.disable();\n }\n }\n\n /**\n * Handles enterpictureinpicture and leavepictureinpicture on the player and change control text accordingly.\n *\n * @param {Event} [event]\n * The {@link Player#enterpictureinpicture} or {@link Player#leavepictureinpicture} event that caused this function to be\n * called.\n *\n * @listens Player#enterpictureinpicture\n * @listens Player#leavepictureinpicture\n */\n handlePictureInPictureChange(event) {\n if (this.player_.isInPictureInPicture()) {\n this.setIcon('picture-in-picture-exit');\n this.controlText('Exit Picture-in-Picture');\n } else {\n this.setIcon('picture-in-picture-enter');\n this.controlText('Picture-in-Picture');\n }\n this.handlePictureInPictureEnabledChange();\n }\n\n /**\n * This gets called when an `PictureInPictureToggle` is \"clicked\". See\n * {@link ClickableComponent} for more detailed information on what a click can be.\n *\n * @param {Event} [event]\n * The `keydown`, `tap`, or `click` event that caused this function to be\n * called.\n *\n * @listens tap\n * @listens click\n */\n handleClick(event) {\n if (!this.player_.isInPictureInPicture()) {\n this.player_.requestPictureInPicture();\n } else {\n this.player_.exitPictureInPicture();\n }\n }\n\n /**\n * Show the `Component`s element if it is hidden by removing the\n * 'vjs-hidden' class name from it only in browsers that support the Picture-in-Picture API.\n */\n show() {\n // Does not allow to display the pictureInPictureToggle in browsers that do not support the Picture-in-Picture API, e.g. Firefox.\n if (typeof document.exitPictureInPicture !== 'function') {\n return;\n }\n super.show();\n }\n }\n\n /**\n * The text that should display over the `PictureInPictureToggle`s controls. Added for localization.\n *\n * @type {string}\n * @protected\n */\n PictureInPictureToggle.prototype.controlText_ = 'Picture-in-Picture';\n Component.registerComponent('PictureInPictureToggle', PictureInPictureToggle);\n\n /**\n * @file fullscreen-toggle.js\n */\n\n /** @import Player from './player' */\n\n /**\n * Toggle fullscreen video\n *\n * @extends Button\n */\n class FullscreenToggle extends Button {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.setIcon('fullscreen-enter');\n this.on(player, 'fullscreenchange', e => this.handleFullscreenChange(e));\n if (document[player.fsApi_.fullscreenEnabled] === false) {\n this.disable();\n }\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-fullscreen-control ${super.buildCSSClass()}`;\n }\n\n /**\n * Handles fullscreenchange on the player and change control text accordingly.\n *\n * @param {Event} [event]\n * The {@link Player#fullscreenchange} event that caused this function to be\n * called.\n *\n * @listens Player#fullscreenchange\n */\n handleFullscreenChange(event) {\n if (this.player_.isFullscreen()) {\n this.controlText('Exit Fullscreen');\n this.setIcon('fullscreen-exit');\n } else {\n this.controlText('Fullscreen');\n this.setIcon('fullscreen-enter');\n }\n }\n\n /**\n * This gets called when an `FullscreenToggle` is \"clicked\". See\n * {@link ClickableComponent} for more detailed information on what a click can be.\n *\n * @param {Event} [event]\n * The `keydown`, `tap`, or `click` event that caused this function to be\n * called.\n *\n * @listens tap\n * @listens click\n */\n handleClick(event) {\n if (!this.player_.isFullscreen()) {\n this.player_.requestFullscreen();\n } else {\n this.player_.exitFullscreen();\n }\n }\n }\n\n /**\n * The text that should display over the `FullscreenToggle`s controls. Added for localization.\n *\n * @type {string}\n * @protected\n */\n FullscreenToggle.prototype.controlText_ = 'Fullscreen';\n Component.registerComponent('FullscreenToggle', FullscreenToggle);\n\n /** @import Component from '../../component' */\n /** @import Player from '../../player' */\n\n /**\n * Check if volume control is supported and if it isn't hide the\n * `Component` that was passed using the `vjs-hidden` class.\n *\n * @param {Component} self\n * The component that should be hidden if volume is unsupported\n *\n * @param {Player} player\n * A reference to the player\n *\n * @private\n */\n const checkVolumeSupport = function (self, player) {\n // hide volume controls when they're not supported by the current tech\n if (player.tech_ && !player.tech_.featuresVolumeControl) {\n self.addClass('vjs-hidden');\n }\n self.on(player, 'loadstart', function () {\n if (!player.tech_.featuresVolumeControl) {\n self.addClass('vjs-hidden');\n } else {\n self.removeClass('vjs-hidden');\n }\n });\n };\n\n /**\n * @file volume-level.js\n */\n\n /**\n * Shows volume level\n *\n * @extends Component\n */\n class VolumeLevel extends Component {\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n const el = super.createEl('div', {\n className: 'vjs-volume-level'\n });\n this.setIcon('circle', el);\n el.appendChild(super.createEl('span', {\n className: 'vjs-control-text'\n }));\n return el;\n }\n }\n Component.registerComponent('VolumeLevel', VolumeLevel);\n\n /**\n * @file volume-level-tooltip.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * Volume level tooltips display a volume above or side by side the volume bar.\n *\n * @extends Component\n */\n class VolumeLevelTooltip extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The {@link Player} that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.update = throttle(bind_(this, this.update), UPDATE_REFRESH_INTERVAL);\n }\n\n /**\n * Create the volume tooltip DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n return super.createEl('div', {\n className: 'vjs-volume-tooltip'\n }, {\n 'aria-hidden': 'true'\n });\n }\n\n /**\n * Updates the position of the tooltip relative to the `VolumeBar` and\n * its content text.\n *\n * @param {Object} rangeBarRect\n * The `ClientRect` for the {@link VolumeBar} element.\n *\n * @param {number} rangeBarPoint\n * A number from 0 to 1, representing a horizontal/vertical reference point\n * from the left edge of the {@link VolumeBar}\n *\n * @param {boolean} vertical\n * Referees to the Volume control position\n * in the control bar{@link VolumeControl}\n *\n */\n update(rangeBarRect, rangeBarPoint, vertical, content) {\n if (!vertical) {\n const tooltipRect = getBoundingClientRect(this.el_);\n const playerRect = getBoundingClientRect(this.player_.el());\n const volumeBarPointPx = rangeBarRect.width * rangeBarPoint;\n if (!playerRect || !tooltipRect) {\n return;\n }\n const spaceLeftOfPoint = rangeBarRect.left - playerRect.left + volumeBarPointPx;\n const spaceRightOfPoint = rangeBarRect.width - volumeBarPointPx + (playerRect.right - rangeBarRect.right);\n let pullTooltipBy = tooltipRect.width / 2;\n if (spaceLeftOfPoint < pullTooltipBy) {\n pullTooltipBy += pullTooltipBy - spaceLeftOfPoint;\n } else if (spaceRightOfPoint < pullTooltipBy) {\n pullTooltipBy = spaceRightOfPoint;\n }\n if (pullTooltipBy < 0) {\n pullTooltipBy = 0;\n } else if (pullTooltipBy > tooltipRect.width) {\n pullTooltipBy = tooltipRect.width;\n }\n this.el_.style.right = `-${pullTooltipBy}px`;\n }\n this.write(`${content}%`);\n }\n\n /**\n * Write the volume to the tooltip DOM element.\n *\n * @param {string} content\n * The formatted volume for the tooltip.\n */\n write(content) {\n textContent(this.el_, content);\n }\n\n /**\n * Updates the position of the volume tooltip relative to the `VolumeBar`.\n *\n * @param {Object} rangeBarRect\n * The `ClientRect` for the {@link VolumeBar} element.\n *\n * @param {number} rangeBarPoint\n * A number from 0 to 1, representing a horizontal/vertical reference point\n * from the left edge of the {@link VolumeBar}\n *\n * @param {boolean} vertical\n * Referees to the Volume control position\n * in the control bar{@link VolumeControl}\n *\n * @param {number} volume\n * The volume level to update the tooltip to\n *\n * @param {Function} cb\n * A function that will be called during the request animation frame\n * for tooltips that need to do additional animations from the default\n */\n updateVolume(rangeBarRect, rangeBarPoint, vertical, volume, cb) {\n this.requestNamedAnimationFrame('VolumeLevelTooltip#updateVolume', () => {\n this.update(rangeBarRect, rangeBarPoint, vertical, volume.toFixed(0));\n if (cb) {\n cb();\n }\n });\n }\n }\n Component.registerComponent('VolumeLevelTooltip', VolumeLevelTooltip);\n\n /**\n * @file mouse-volume-level-display.js\n */\n\n /**\n * The {@link MouseVolumeLevelDisplay} component tracks mouse movement over the\n * {@link VolumeControl}. It displays an indicator and a {@link VolumeLevelTooltip}\n * indicating the volume level which is represented by a given point in the\n * {@link VolumeBar}.\n *\n * @extends Component\n */\n class MouseVolumeLevelDisplay extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The {@link Player} that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.update = throttle(bind_(this, this.update), UPDATE_REFRESH_INTERVAL);\n }\n\n /**\n * Create the DOM element for this class.\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n return super.createEl('div', {\n className: 'vjs-mouse-display'\n });\n }\n\n /**\n * Enquires updates to its own DOM as well as the DOM of its\n * {@link VolumeLevelTooltip} child.\n *\n * @param {Object} rangeBarRect\n * The `ClientRect` for the {@link VolumeBar} element.\n *\n * @param {number} rangeBarPoint\n * A number from 0 to 1, representing a horizontal/vertical reference point\n * from the left edge of the {@link VolumeBar}\n *\n * @param {boolean} vertical\n * Referees to the Volume control position\n * in the control bar{@link VolumeControl}\n *\n */\n update(rangeBarRect, rangeBarPoint, vertical) {\n const volume = 100 * rangeBarPoint;\n this.getChild('volumeLevelTooltip').updateVolume(rangeBarRect, rangeBarPoint, vertical, volume, () => {\n if (vertical) {\n this.el_.style.bottom = `${rangeBarRect.height * rangeBarPoint}px`;\n } else {\n this.el_.style.left = `${rangeBarRect.width * rangeBarPoint}px`;\n }\n });\n }\n }\n\n /**\n * Default options for `MouseVolumeLevelDisplay`\n *\n * @type {Object}\n * @private\n */\n MouseVolumeLevelDisplay.prototype.options_ = {\n children: ['volumeLevelTooltip']\n };\n Component.registerComponent('MouseVolumeLevelDisplay', MouseVolumeLevelDisplay);\n\n /**\n * @file volume-bar.js\n */\n\n /**\n * The bar that contains the volume level and can be clicked on to adjust the level\n *\n * @extends Slider\n */\n class VolumeBar extends Slider {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.on('slideractive', e => this.updateLastVolume_(e));\n this.on(player, 'volumechange', e => this.updateARIAAttributes(e));\n player.ready(() => this.updateARIAAttributes());\n }\n\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n return super.createEl('div', {\n className: 'vjs-volume-bar vjs-slider-bar'\n }, {\n 'aria-label': this.localize('Volume Level'),\n 'aria-live': 'polite'\n });\n }\n\n /**\n * Handle mouse down on volume bar\n *\n * @param {Event} event\n * The `mousedown` event that caused this to run.\n *\n * @listens mousedown\n */\n handleMouseDown(event) {\n if (!isSingleLeftClick(event)) {\n return;\n }\n super.handleMouseDown(event);\n }\n\n /**\n * Handle movement events on the {@link VolumeMenuButton}.\n *\n * @param {Event} event\n * The event that caused this function to run.\n *\n * @listens mousemove\n */\n handleMouseMove(event) {\n const mouseVolumeLevelDisplay = this.getChild('mouseVolumeLevelDisplay');\n if (mouseVolumeLevelDisplay) {\n const volumeBarEl = this.el();\n const volumeBarRect = getBoundingClientRect(volumeBarEl);\n const vertical = this.vertical();\n let volumeBarPoint = getPointerPosition(volumeBarEl, event);\n volumeBarPoint = vertical ? volumeBarPoint.y : volumeBarPoint.x;\n // The default skin has a gap on either side of the `VolumeBar`. This means\n // that it's possible to trigger this behavior outside the boundaries of\n // the `VolumeBar`. This ensures we stay within it at all times.\n volumeBarPoint = clamp(volumeBarPoint, 0, 1);\n mouseVolumeLevelDisplay.update(volumeBarRect, volumeBarPoint, vertical);\n }\n if (!isSingleLeftClick(event)) {\n return;\n }\n this.checkMuted();\n this.player_.volume(this.calculateDistance(event));\n }\n\n /**\n * If the player is muted unmute it.\n */\n checkMuted() {\n if (this.player_.muted()) {\n this.player_.muted(false);\n }\n }\n\n /**\n * Get percent of volume level\n *\n * @return {number}\n * Volume level percent as a decimal number.\n */\n getPercent() {\n if (this.player_.muted()) {\n return 0;\n }\n return this.player_.volume();\n }\n\n /**\n * Increase volume level for keyboard users\n */\n stepForward() {\n this.checkMuted();\n this.player_.volume(this.player_.volume() + 0.1);\n }\n\n /**\n * Decrease volume level for keyboard users\n */\n stepBack() {\n this.checkMuted();\n this.player_.volume(this.player_.volume() - 0.1);\n }\n\n /**\n * Update ARIA accessibility attributes\n *\n * @param {Event} [event]\n * The `volumechange` event that caused this function to run.\n *\n * @listens Player#volumechange\n */\n updateARIAAttributes(event) {\n const ariaValue = this.player_.muted() ? 0 : this.volumeAsPercentage_();\n this.el_.setAttribute('aria-valuenow', ariaValue);\n this.el_.setAttribute('aria-valuetext', ariaValue + '%');\n }\n\n /**\n * Returns the current value of the player volume as a percentage\n *\n * @private\n */\n volumeAsPercentage_() {\n return Math.round(this.player_.volume() * 100);\n }\n\n /**\n * When user starts dragging the VolumeBar, store the volume and listen for\n * the end of the drag. When the drag ends, if the volume was set to zero,\n * set lastVolume to the stored volume.\n *\n * @listens slideractive\n * @private\n */\n updateLastVolume_() {\n const volumeBeforeDrag = this.player_.volume();\n this.one('sliderinactive', () => {\n if (this.player_.volume() === 0) {\n this.player_.lastVolume_(volumeBeforeDrag);\n }\n });\n }\n }\n\n /**\n * Default options for the `VolumeBar`\n *\n * @type {Object}\n * @private\n */\n VolumeBar.prototype.options_ = {\n children: ['volumeLevel'],\n barName: 'volumeLevel'\n };\n\n // MouseVolumeLevelDisplay tooltip should not be added to a player on mobile devices\n if (!IS_IOS && !IS_ANDROID) {\n VolumeBar.prototype.options_.children.splice(0, 0, 'mouseVolumeLevelDisplay');\n }\n\n /**\n * Call the update event for this Slider when this event happens on the player.\n *\n * @type {string}\n */\n VolumeBar.prototype.playerEvent = 'volumechange';\n Component.registerComponent('VolumeBar', VolumeBar);\n\n /**\n * @file volume-control.js\n */\n\n /**\n * The component for controlling the volume level\n *\n * @extends Component\n */\n class VolumeControl extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options={}]\n * The key/value store of player options.\n */\n constructor(player, options = {}) {\n options.vertical = options.vertical || false;\n\n // Pass the vertical option down to the VolumeBar if\n // the VolumeBar is turned on.\n if (typeof options.volumeBar === 'undefined' || isPlain(options.volumeBar)) {\n options.volumeBar = options.volumeBar || {};\n options.volumeBar.vertical = options.vertical;\n }\n super(player, options);\n\n // hide this control if volume support is missing\n checkVolumeSupport(this, player);\n this.throttledHandleMouseMove = throttle(bind_(this, this.handleMouseMove), UPDATE_REFRESH_INTERVAL);\n this.handleMouseUpHandler_ = e => this.handleMouseUp(e);\n this.on('mousedown', e => this.handleMouseDown(e));\n this.on('touchstart', e => this.handleMouseDown(e));\n this.on('mousemove', e => this.handleMouseMove(e));\n\n // while the slider is active (the mouse has been pressed down and\n // is dragging) or in focus we do not want to hide the VolumeBar\n this.on(this.volumeBar, ['focus', 'slideractive'], () => {\n this.volumeBar.addClass('vjs-slider-active');\n this.addClass('vjs-slider-active');\n this.trigger('slideractive');\n });\n this.on(this.volumeBar, ['blur', 'sliderinactive'], () => {\n this.volumeBar.removeClass('vjs-slider-active');\n this.removeClass('vjs-slider-active');\n this.trigger('sliderinactive');\n });\n }\n\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n let orientationClass = 'vjs-volume-horizontal';\n if (this.options_.vertical) {\n orientationClass = 'vjs-volume-vertical';\n }\n return super.createEl('div', {\n className: `vjs-volume-control vjs-control ${orientationClass}`\n });\n }\n\n /**\n * Handle `mousedown` or `touchstart` events on the `VolumeControl`.\n *\n * @param {Event} event\n * `mousedown` or `touchstart` event that triggered this function\n *\n * @listens mousedown\n * @listens touchstart\n */\n handleMouseDown(event) {\n const doc = this.el_.ownerDocument;\n this.on(doc, 'mousemove', this.throttledHandleMouseMove);\n this.on(doc, 'touchmove', this.throttledHandleMouseMove);\n this.on(doc, 'mouseup', this.handleMouseUpHandler_);\n this.on(doc, 'touchend', this.handleMouseUpHandler_);\n }\n\n /**\n * Handle `mouseup` or `touchend` events on the `VolumeControl`.\n *\n * @param {Event} event\n * `mouseup` or `touchend` event that triggered this function.\n *\n * @listens touchend\n * @listens mouseup\n */\n handleMouseUp(event) {\n const doc = this.el_.ownerDocument;\n this.off(doc, 'mousemove', this.throttledHandleMouseMove);\n this.off(doc, 'touchmove', this.throttledHandleMouseMove);\n this.off(doc, 'mouseup', this.handleMouseUpHandler_);\n this.off(doc, 'touchend', this.handleMouseUpHandler_);\n }\n\n /**\n * Handle `mousedown` or `touchstart` events on the `VolumeControl`.\n *\n * @param {Event} event\n * `mousedown` or `touchstart` event that triggered this function\n *\n * @listens mousedown\n * @listens touchstart\n */\n handleMouseMove(event) {\n this.volumeBar.handleMouseMove(event);\n }\n }\n\n /**\n * Default options for the `VolumeControl`\n *\n * @type {Object}\n * @private\n */\n VolumeControl.prototype.options_ = {\n children: ['volumeBar']\n };\n Component.registerComponent('VolumeControl', VolumeControl);\n\n /** @import Component from '../../component' */\n /** @import Player from '../../player' */\n\n /**\n * Check if muting volume is supported and if it isn't hide the mute toggle\n * button.\n *\n * @param {Component} self\n * A reference to the mute toggle button\n *\n * @param {Player} player\n * A reference to the player\n *\n * @private\n */\n const checkMuteSupport = function (self, player) {\n // hide mute toggle button if it's not supported by the current tech\n if (player.tech_ && !player.tech_.featuresMuteControl) {\n self.addClass('vjs-hidden');\n }\n self.on(player, 'loadstart', function () {\n if (!player.tech_.featuresMuteControl) {\n self.addClass('vjs-hidden');\n } else {\n self.removeClass('vjs-hidden');\n }\n });\n };\n\n /**\n * @file mute-toggle.js\n */\n\n /** @import Player from './player' */\n\n /**\n * A button component for muting the audio.\n *\n * @extends Button\n */\n class MuteToggle extends Button {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n\n // hide this control if volume support is missing\n checkMuteSupport(this, player);\n this.on(player, ['loadstart', 'volumechange'], e => this.update(e));\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-mute-control ${super.buildCSSClass()}`;\n }\n\n /**\n * This gets called when an `MuteToggle` is \"clicked\". See\n * {@link ClickableComponent} for more detailed information on what a click can be.\n *\n * @param {Event} [event]\n * The `keydown`, `tap`, or `click` event that caused this function to be\n * called.\n *\n * @listens tap\n * @listens click\n */\n handleClick(event) {\n const vol = this.player_.volume();\n const lastVolume = this.player_.lastVolume_();\n if (vol === 0) {\n const volumeToSet = lastVolume < 0.1 ? 0.1 : lastVolume;\n this.player_.volume(volumeToSet);\n this.player_.muted(false);\n } else {\n this.player_.muted(this.player_.muted() ? false : true);\n }\n }\n\n /**\n * Update the `MuteToggle` button based on the state of `volume` and `muted`\n * on the player.\n *\n * @param {Event} [event]\n * The {@link Player#loadstart} event if this function was called\n * through an event.\n *\n * @listens Player#loadstart\n * @listens Player#volumechange\n */\n update(event) {\n this.updateIcon_();\n this.updateControlText_();\n }\n\n /**\n * Update the appearance of the `MuteToggle` icon.\n *\n * Possible states (given `level` variable below):\n * - 0: crossed out\n * - 1: zero bars of volume\n * - 2: one bar of volume\n * - 3: two bars of volume\n *\n * @private\n */\n updateIcon_() {\n const vol = this.player_.volume();\n let level = 3;\n this.setIcon('volume-high');\n\n // in iOS when a player is loaded with muted attribute\n // and volume is changed with a native mute button\n // we want to make sure muted state is updated\n if (IS_IOS && this.player_.tech_ && this.player_.tech_.el_) {\n this.player_.muted(this.player_.tech_.el_.muted);\n }\n if (vol === 0 || this.player_.muted()) {\n this.setIcon('volume-mute');\n level = 0;\n } else if (vol < 0.33) {\n this.setIcon('volume-low');\n level = 1;\n } else if (vol < 0.67) {\n this.setIcon('volume-medium');\n level = 2;\n }\n removeClass(this.el_, [0, 1, 2, 3].reduce((str, i) => str + `${i ? ' ' : ''}vjs-vol-${i}`, ''));\n addClass(this.el_, `vjs-vol-${level}`);\n }\n\n /**\n * If `muted` has changed on the player, update the control text\n * (`title` attribute on `vjs-mute-control` element and content of\n * `vjs-control-text` element).\n *\n * @private\n */\n updateControlText_() {\n const soundOff = this.player_.muted() || this.player_.volume() === 0;\n const text = soundOff ? 'Unmute' : 'Mute';\n if (this.controlText() !== text) {\n this.controlText(text);\n }\n }\n }\n\n /**\n * The text that should display over the `MuteToggle`s controls. Added for localization.\n *\n * @type {string}\n * @protected\n */\n MuteToggle.prototype.controlText_ = 'Mute';\n Component.registerComponent('MuteToggle', MuteToggle);\n\n /**\n * @file volume-control.js\n */\n\n /**\n * A Component to contain the MuteToggle and VolumeControl so that\n * they can work together.\n *\n * @extends Component\n */\n class VolumePanel extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options={}]\n * The key/value store of player options.\n */\n constructor(player, options = {}) {\n if (typeof options.inline !== 'undefined') {\n options.inline = options.inline;\n } else {\n options.inline = true;\n }\n\n // pass the inline option down to the VolumeControl as vertical if\n // the VolumeControl is on.\n if (typeof options.volumeControl === 'undefined' || isPlain(options.volumeControl)) {\n options.volumeControl = options.volumeControl || {};\n options.volumeControl.vertical = !options.inline;\n }\n super(player, options);\n\n // this handler is used by mouse handler methods below\n this.handleKeyPressHandler_ = e => this.handleKeyPress(e);\n this.on(player, ['loadstart'], e => this.volumePanelState_(e));\n this.on(this.muteToggle, 'keyup', e => this.handleKeyPress(e));\n this.on(this.volumeControl, 'keyup', e => this.handleVolumeControlKeyUp(e));\n this.on('keydown', e => this.handleKeyPress(e));\n this.on('mouseover', e => this.handleMouseOver(e));\n this.on('mouseout', e => this.handleMouseOut(e));\n\n // while the slider is active (the mouse has been pressed down and\n // is dragging) we do not want to hide the VolumeBar\n this.on(this.volumeControl, ['slideractive'], this.sliderActive_);\n this.on(this.volumeControl, ['sliderinactive'], this.sliderInactive_);\n }\n\n /**\n * Add vjs-slider-active class to the VolumePanel\n *\n * @listens VolumeControl#slideractive\n * @private\n */\n sliderActive_() {\n this.addClass('vjs-slider-active');\n }\n\n /**\n * Removes vjs-slider-active class to the VolumePanel\n *\n * @listens VolumeControl#sliderinactive\n * @private\n */\n sliderInactive_() {\n this.removeClass('vjs-slider-active');\n }\n\n /**\n * Adds vjs-hidden or vjs-mute-toggle-only to the VolumePanel\n * depending on MuteToggle and VolumeControl state\n *\n * @listens Player#loadstart\n * @private\n */\n volumePanelState_() {\n // hide volume panel if neither volume control or mute toggle\n // are displayed\n if (this.volumeControl.hasClass('vjs-hidden') && this.muteToggle.hasClass('vjs-hidden')) {\n this.addClass('vjs-hidden');\n }\n\n // if only mute toggle is visible we don't want\n // volume panel expanding when hovered or active\n if (this.volumeControl.hasClass('vjs-hidden') && !this.muteToggle.hasClass('vjs-hidden')) {\n this.addClass('vjs-mute-toggle-only');\n }\n }\n\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n let orientationClass = 'vjs-volume-panel-horizontal';\n if (!this.options_.inline) {\n orientationClass = 'vjs-volume-panel-vertical';\n }\n return super.createEl('div', {\n className: `vjs-volume-panel vjs-control ${orientationClass}`\n });\n }\n\n /**\n * Dispose of the `volume-panel` and all child components.\n */\n dispose() {\n this.handleMouseOut();\n super.dispose();\n }\n\n /**\n * Handles `keyup` events on the `VolumeControl`, looking for ESC, which closes\n * the volume panel and sets focus on `MuteToggle`.\n *\n * @param {Event} event\n * The `keyup` event that caused this function to be called.\n *\n * @listens keyup\n */\n handleVolumeControlKeyUp(event) {\n if (event.key === 'Escape') {\n this.muteToggle.focus();\n }\n }\n\n /**\n * This gets called when a `VolumePanel` gains hover via a `mouseover` event.\n * Turns on listening for `mouseover` event. When they happen it\n * calls `this.handleMouseOver`.\n *\n * @param {Event} event\n * The `mouseover` event that caused this function to be called.\n *\n * @listens mouseover\n */\n handleMouseOver(event) {\n this.addClass('vjs-hover');\n on(document, 'keyup', this.handleKeyPressHandler_);\n }\n\n /**\n * This gets called when a `VolumePanel` gains hover via a `mouseout` event.\n * Turns on listening for `mouseout` event. When they happen it\n * calls `this.handleMouseOut`.\n *\n * @param {Event} event\n * The `mouseout` event that caused this function to be called.\n *\n * @listens mouseout\n */\n handleMouseOut(event) {\n this.removeClass('vjs-hover');\n off(document, 'keyup', this.handleKeyPressHandler_);\n }\n\n /**\n * Handles `keyup` event on the document or `keydown` event on the `VolumePanel`,\n * looking for ESC, which hides the `VolumeControl`.\n *\n * @param {Event} event\n * The keypress that triggered this event.\n *\n * @listens keydown | keyup\n */\n handleKeyPress(event) {\n if (event.key === 'Escape') {\n this.handleMouseOut();\n }\n }\n }\n\n /**\n * Default options for the `VolumeControl`\n *\n * @type {Object}\n * @private\n */\n VolumePanel.prototype.options_ = {\n children: ['muteToggle', 'volumeControl']\n };\n Component.registerComponent('VolumePanel', VolumePanel);\n\n /**\n * Button to skip forward a configurable amount of time\n * through a video. Renders in the control bar.\n *\n * e.g. options: {controlBar: {skipButtons: forward: 5}}\n *\n * @extends Button\n */\n class SkipForward extends Button {\n constructor(player, options) {\n super(player, options);\n this.validOptions = [5, 10, 30];\n this.skipTime = this.getSkipForwardTime();\n if (this.skipTime && this.validOptions.includes(this.skipTime)) {\n this.setIcon(`forward-${this.skipTime}`);\n this.controlText(this.localize('Skip forward {1} seconds', [this.skipTime.toLocaleString(player.language())]));\n this.show();\n } else {\n this.hide();\n }\n }\n getSkipForwardTime() {\n const playerOptions = this.options_.playerOptions;\n return playerOptions.controlBar && playerOptions.controlBar.skipButtons && playerOptions.controlBar.skipButtons.forward;\n }\n buildCSSClass() {\n return `vjs-skip-forward-${this.getSkipForwardTime()} ${super.buildCSSClass()}`;\n }\n\n /**\n * On click, skips forward in the duration/seekable range by a configurable amount of seconds.\n * If the time left in the duration/seekable range is less than the configured 'skip forward' time,\n * skips to end of duration/seekable range.\n *\n * Handle a click on a `SkipForward` button\n *\n * @param {EventTarget~Event} event\n * The `click` event that caused this function\n * to be called\n */\n handleClick(event) {\n if (isNaN(this.player_.duration())) {\n return;\n }\n const currentVideoTime = this.player_.currentTime();\n const liveTracker = this.player_.liveTracker;\n const duration = liveTracker && liveTracker.isLive() ? liveTracker.seekableEnd() : this.player_.duration();\n let newTime;\n if (currentVideoTime + this.skipTime <= duration) {\n newTime = currentVideoTime + this.skipTime;\n } else {\n newTime = duration;\n }\n this.player_.currentTime(newTime);\n }\n\n /**\n * Update control text on languagechange\n */\n handleLanguagechange() {\n this.controlText(this.localize('Skip forward {1} seconds', [this.skipTime]));\n }\n }\n SkipForward.prototype.controlText_ = 'Skip Forward';\n Component.registerComponent('SkipForward', SkipForward);\n\n /**\n * Button to skip backward a configurable amount of time\n * through a video. Renders in the control bar.\n *\n * * e.g. options: {controlBar: {skipButtons: backward: 5}}\n *\n * @extends Button\n */\n class SkipBackward extends Button {\n constructor(player, options) {\n super(player, options);\n this.validOptions = [5, 10, 30];\n this.skipTime = this.getSkipBackwardTime();\n if (this.skipTime && this.validOptions.includes(this.skipTime)) {\n this.setIcon(`replay-${this.skipTime}`);\n this.controlText(this.localize('Skip backward {1} seconds', [this.skipTime.toLocaleString(player.language())]));\n this.show();\n } else {\n this.hide();\n }\n }\n getSkipBackwardTime() {\n const playerOptions = this.options_.playerOptions;\n return playerOptions.controlBar && playerOptions.controlBar.skipButtons && playerOptions.controlBar.skipButtons.backward;\n }\n buildCSSClass() {\n return `vjs-skip-backward-${this.getSkipBackwardTime()} ${super.buildCSSClass()}`;\n }\n\n /**\n * On click, skips backward in the video by a configurable amount of seconds.\n * If the current time in the video is less than the configured 'skip backward' time,\n * skips to beginning of video or seekable range.\n *\n * Handle a click on a `SkipBackward` button\n *\n * @param {EventTarget~Event} event\n * The `click` event that caused this function\n * to be called\n */\n handleClick(event) {\n const currentVideoTime = this.player_.currentTime();\n const liveTracker = this.player_.liveTracker;\n const seekableStart = liveTracker && liveTracker.isLive() && liveTracker.seekableStart();\n let newTime;\n if (seekableStart && currentVideoTime - this.skipTime <= seekableStart) {\n newTime = seekableStart;\n } else if (currentVideoTime >= this.skipTime) {\n newTime = currentVideoTime - this.skipTime;\n } else {\n newTime = 0;\n }\n this.player_.currentTime(newTime);\n }\n\n /**\n * Update control text on languagechange\n */\n handleLanguagechange() {\n this.controlText(this.localize('Skip backward {1} seconds', [this.skipTime]));\n }\n }\n SkipBackward.prototype.controlText_ = 'Skip Backward';\n Component.registerComponent('SkipBackward', SkipBackward);\n\n /**\n * @file menu.js\n */\n\n /** @import Player from '../player' */\n\n /**\n * The Menu component is used to build popup menus, including subtitle and\n * captions selection menus.\n *\n * @extends Component\n */\n class Menu extends Component {\n /**\n * Create an instance of this class.\n *\n * @param {Player} player\n * the player that this component should attach to\n *\n * @param {Object} [options]\n * Object of option names and values\n *\n */\n constructor(player, options) {\n super(player, options);\n if (options) {\n this.menuButton_ = options.menuButton;\n }\n this.focusedChild_ = -1;\n this.on('keydown', e => this.handleKeyDown(e));\n\n // All the menu item instances share the same blur handler provided by the menu container.\n this.boundHandleBlur_ = e => this.handleBlur(e);\n this.boundHandleTapClick_ = e => this.handleTapClick(e);\n }\n\n /**\n * Add event listeners to the {@link MenuItem}.\n *\n * @param {Object} component\n * The instance of the `MenuItem` to add listeners to.\n *\n */\n addEventListenerForItem(component) {\n if (!(component instanceof Component)) {\n return;\n }\n this.on(component, 'blur', this.boundHandleBlur_);\n this.on(component, ['tap', 'click'], this.boundHandleTapClick_);\n }\n\n /**\n * Remove event listeners from the {@link MenuItem}.\n *\n * @param {Object} component\n * The instance of the `MenuItem` to remove listeners.\n *\n */\n removeEventListenerForItem(component) {\n if (!(component instanceof Component)) {\n return;\n }\n this.off(component, 'blur', this.boundHandleBlur_);\n this.off(component, ['tap', 'click'], this.boundHandleTapClick_);\n }\n\n /**\n * This method will be called indirectly when the component has been added\n * before the component adds to the new menu instance by `addItem`.\n * In this case, the original menu instance will remove the component\n * by calling `removeChild`.\n *\n * @param {Object} component\n * The instance of the `MenuItem`\n */\n removeChild(component) {\n if (typeof component === 'string') {\n component = this.getChild(component);\n }\n this.removeEventListenerForItem(component);\n super.removeChild(component);\n }\n\n /**\n * Add a {@link MenuItem} to the menu.\n *\n * @param {Object|string} component\n * The name or instance of the `MenuItem` to add.\n *\n */\n addItem(component) {\n const childComponent = this.addChild(component);\n if (childComponent) {\n this.addEventListenerForItem(childComponent);\n }\n }\n\n /**\n * Create the `Menu`s DOM element.\n *\n * @return {Element}\n * the element that was created\n */\n createEl() {\n const contentElType = this.options_.contentElType || 'ul';\n this.contentEl_ = createEl(contentElType, {\n className: 'vjs-menu-content'\n });\n this.contentEl_.setAttribute('role', 'menu');\n const el = super.createEl('div', {\n append: this.contentEl_,\n className: 'vjs-menu'\n });\n el.appendChild(this.contentEl_);\n\n // Prevent clicks from bubbling up. Needed for Menu Buttons,\n // where a click on the parent is significant\n on(el, 'click', function (event) {\n event.preventDefault();\n event.stopImmediatePropagation();\n });\n return el;\n }\n dispose() {\n this.contentEl_ = null;\n this.boundHandleBlur_ = null;\n this.boundHandleTapClick_ = null;\n super.dispose();\n }\n\n /**\n * Called when a `MenuItem` loses focus.\n *\n * @param {Event} event\n * The `blur` event that caused this function to be called.\n *\n * @listens blur\n */\n handleBlur(event) {\n const relatedTarget = event.relatedTarget || document.activeElement;\n\n // Close menu popup when a user clicks outside the menu\n if (!this.children().some(element => {\n return element.el() === relatedTarget;\n })) {\n const btn = this.menuButton_;\n if (btn && btn.buttonPressed_ && relatedTarget !== btn.el().firstChild) {\n btn.unpressButton();\n }\n }\n }\n\n /**\n * Called when a `MenuItem` gets clicked or tapped.\n *\n * @param {Event} event\n * The `click` or `tap` event that caused this function to be called.\n *\n * @listens click,tap\n */\n handleTapClick(event) {\n // Unpress the associated MenuButton, and move focus back to it\n if (this.menuButton_) {\n this.menuButton_.unpressButton();\n const childComponents = this.children();\n if (!Array.isArray(childComponents)) {\n return;\n }\n const foundComponent = childComponents.filter(component => component.el() === event.target)[0];\n if (!foundComponent) {\n return;\n }\n\n // don't focus menu button if item is a caption settings item\n // because focus will move elsewhere\n if (foundComponent.name() !== 'CaptionSettingsMenuItem') {\n this.menuButton_.focus();\n }\n }\n }\n\n /**\n * Handle a `keydown` event on this menu. This listener is added in the constructor.\n *\n * @param {KeyboardEvent} event\n * A `keydown` event that happened on the menu.\n *\n * @listens keydown\n */\n handleKeyDown(event) {\n // Left and Down Arrows\n if (event.key === 'ArrowLeft' || event.key === 'ArrowDown') {\n event.preventDefault();\n event.stopPropagation();\n this.stepForward();\n\n // Up and Right Arrows\n } else if (event.key === 'ArrowRight' || event.key === 'ArrowUp') {\n event.preventDefault();\n event.stopPropagation();\n this.stepBack();\n }\n }\n\n /**\n * Move to next (lower) menu item for keyboard users.\n */\n stepForward() {\n let stepChild = 0;\n if (this.focusedChild_ !== undefined) {\n stepChild = this.focusedChild_ + 1;\n }\n this.focus(stepChild);\n }\n\n /**\n * Move to previous (higher) menu item for keyboard users.\n */\n stepBack() {\n let stepChild = 0;\n if (this.focusedChild_ !== undefined) {\n stepChild = this.focusedChild_ - 1;\n }\n this.focus(stepChild);\n }\n\n /**\n * Set focus on a {@link MenuItem} in the `Menu`.\n *\n * @param {Object|string} [item=0]\n * Index of child item set focus on.\n */\n focus(item = 0) {\n const children = this.children().slice();\n const haveTitle = children.length && children[0].hasClass('vjs-menu-title');\n if (haveTitle) {\n children.shift();\n }\n if (children.length > 0) {\n if (item < 0) {\n item = 0;\n } else if (item >= children.length) {\n item = children.length - 1;\n }\n this.focusedChild_ = item;\n children[item].el_.focus();\n }\n }\n }\n Component.registerComponent('Menu', Menu);\n\n /**\n * @file menu-button.js\n */\n\n /** @import Player from '../player' */\n\n /**\n * A `MenuButton` class for any popup {@link Menu}.\n *\n * @extends Component\n */\n class MenuButton extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options={}]\n * The key/value store of player options.\n */\n constructor(player, options = {}) {\n super(player, options);\n this.menuButton_ = new Button(player, options);\n this.menuButton_.controlText(this.controlText_);\n this.menuButton_.el_.setAttribute('aria-haspopup', 'true');\n\n // Add buildCSSClass values to the button, not the wrapper\n const buttonClass = Button.prototype.buildCSSClass();\n this.menuButton_.el_.className = this.buildCSSClass() + ' ' + buttonClass;\n this.menuButton_.removeClass('vjs-control');\n this.addChild(this.menuButton_);\n this.update();\n this.enabled_ = true;\n const handleClick = e => this.handleClick(e);\n this.handleMenuKeyUp_ = e => this.handleMenuKeyUp(e);\n this.on(this.menuButton_, 'tap', handleClick);\n this.on(this.menuButton_, 'click', handleClick);\n this.on(this.menuButton_, 'keydown', e => this.handleKeyDown(e));\n this.on(this.menuButton_, 'mouseenter', () => {\n this.addClass('vjs-hover');\n this.menu.show();\n on(document, 'keyup', this.handleMenuKeyUp_);\n });\n this.on('mouseleave', e => this.handleMouseLeave(e));\n this.on('keydown', e => this.handleSubmenuKeyDown(e));\n }\n\n /**\n * Update the menu based on the current state of its items.\n */\n update() {\n const menu = this.createMenu();\n if (this.menu) {\n this.menu.dispose();\n this.removeChild(this.menu);\n }\n this.menu = menu;\n this.addChild(menu);\n\n /**\n * Track the state of the menu button\n *\n * @type {Boolean}\n * @private\n */\n this.buttonPressed_ = false;\n this.menuButton_.el_.setAttribute('aria-expanded', 'false');\n if (this.items && this.items.length <= this.hideThreshold_) {\n this.hide();\n this.menu.contentEl_.removeAttribute('role');\n } else {\n this.show();\n this.menu.contentEl_.setAttribute('role', 'menu');\n }\n }\n\n /**\n * Create the menu and add all items to it.\n *\n * @return {Menu}\n * The constructed menu\n */\n createMenu() {\n const menu = new Menu(this.player_, {\n menuButton: this\n });\n\n /**\n * Hide the menu if the number of items is less than or equal to this threshold. This defaults\n * to 0 and whenever we add items which can be hidden to the menu we'll increment it. We list\n * it here because every time we run `createMenu` we need to reset the value.\n *\n * @protected\n * @type {Number}\n */\n this.hideThreshold_ = 0;\n\n // Add a title list item to the top\n if (this.options_.title) {\n const titleEl = createEl('li', {\n className: 'vjs-menu-title',\n textContent: toTitleCase(this.options_.title),\n tabIndex: -1\n });\n const titleComponent = new Component(this.player_, {\n el: titleEl\n });\n menu.addItem(titleComponent);\n }\n this.items = this.createItems();\n if (this.items) {\n // Add menu items to the menu\n for (let i = 0; i < this.items.length; i++) {\n menu.addItem(this.items[i]);\n }\n }\n return menu;\n }\n\n /**\n * Create the list of menu items. Specific to each subclass.\n *\n * @abstract\n */\n createItems() {}\n\n /**\n * Create the `MenuButtons`s DOM element.\n *\n * @return {Element}\n * The element that gets created.\n */\n createEl() {\n return super.createEl('div', {\n className: this.buildWrapperCSSClass()\n }, {});\n }\n\n /**\n * Overwrites the `setIcon` method from `Component`.\n * In this case, we want the icon to be appended to the menuButton.\n *\n * @param {string} name\n * The icon name to be added.\n */\n setIcon(name) {\n super.setIcon(name, this.menuButton_.el_);\n }\n\n /**\n * Allow sub components to stack CSS class names for the wrapper element\n *\n * @return {string}\n * The constructed wrapper DOM `className`\n */\n buildWrapperCSSClass() {\n let menuButtonClass = 'vjs-menu-button';\n\n // If the inline option is passed, we want to use different styles altogether.\n if (this.options_.inline === true) {\n menuButtonClass += '-inline';\n } else {\n menuButtonClass += '-popup';\n }\n\n // TODO: Fix the CSS so that this isn't necessary\n const buttonClass = Button.prototype.buildCSSClass();\n return `vjs-menu-button ${menuButtonClass} ${buttonClass} ${super.buildCSSClass()}`;\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n let menuButtonClass = 'vjs-menu-button';\n\n // If the inline option is passed, we want to use different styles altogether.\n if (this.options_.inline === true) {\n menuButtonClass += '-inline';\n } else {\n menuButtonClass += '-popup';\n }\n return `vjs-menu-button ${menuButtonClass} ${super.buildCSSClass()}`;\n }\n\n /**\n * Get or set the localized control text that will be used for accessibility.\n *\n * > NOTE: This will come from the internal `menuButton_` element.\n *\n * @param {string} [text]\n * Control text for element.\n *\n * @param {Element} [el=this.menuButton_.el()]\n * Element to set the title on.\n *\n * @return {string}\n * - The control text when getting\n */\n controlText(text, el = this.menuButton_.el()) {\n return this.menuButton_.controlText(text, el);\n }\n\n /**\n * Dispose of the `menu-button` and all child components.\n */\n dispose() {\n this.handleMouseLeave();\n super.dispose();\n }\n\n /**\n * Handle a click on a `MenuButton`.\n * See {@link ClickableComponent#handleClick} for instances where this is called.\n *\n * @param {Event} event\n * The `keydown`, `tap`, or `click` event that caused this function to be\n * called.\n *\n * @listens tap\n * @listens click\n */\n handleClick(event) {\n if (this.buttonPressed_) {\n this.unpressButton();\n } else {\n this.pressButton();\n }\n }\n\n /**\n * Handle `mouseleave` for `MenuButton`.\n *\n * @param {Event} event\n * The `mouseleave` event that caused this function to be called.\n *\n * @listens mouseleave\n */\n handleMouseLeave(event) {\n this.removeClass('vjs-hover');\n off(document, 'keyup', this.handleMenuKeyUp_);\n }\n\n /**\n * Set the focus to the actual button, not to this element\n */\n focus() {\n this.menuButton_.focus();\n }\n\n /**\n * Remove the focus from the actual button, not this element\n */\n blur() {\n this.menuButton_.blur();\n }\n\n /**\n * Handle tab, escape, down arrow, and up arrow keys for `MenuButton`. See\n * {@link ClickableComponent#handleKeyDown} for instances where this is called.\n *\n * @param {Event} event\n * The `keydown` event that caused this function to be called.\n *\n * @listens keydown\n */\n handleKeyDown(event) {\n // Escape or Tab unpress the 'button'\n if (event.key === 'Escape' || event.key === 'Tab') {\n if (this.buttonPressed_) {\n this.unpressButton();\n }\n\n // Don't preventDefault for Tab key - we still want to lose focus\n if (!event.key === 'Tab') {\n event.preventDefault();\n // Set focus back to the menu button's button\n this.menuButton_.focus();\n }\n // Up Arrow or Down Arrow also 'press' the button to open the menu\n } else if (event.key === 'Up' || event.key === 'Down' && !(this.player_.options_.playerOptions.spatialNavigation && this.player_.options_.playerOptions.spatialNavigation.enabled)) {\n if (!this.buttonPressed_) {\n event.preventDefault();\n this.pressButton();\n }\n }\n }\n\n /**\n * Handle a `keyup` event on a `MenuButton`. The listener for this is added in\n * the constructor.\n *\n * @param {Event} event\n * Key press event\n *\n * @listens keyup\n */\n handleMenuKeyUp(event) {\n // Escape hides popup menu\n if (event.key === 'Escape' || event.key === 'Tab') {\n this.removeClass('vjs-hover');\n }\n }\n\n /**\n * This method name now delegates to `handleSubmenuKeyDown`. This means\n * anyone calling `handleSubmenuKeyPress` will not see their method calls\n * stop working.\n *\n * @param {Event} event\n * The event that caused this function to be called.\n */\n handleSubmenuKeyPress(event) {\n this.handleSubmenuKeyDown(event);\n }\n\n /**\n * Handle a `keydown` event on a sub-menu. The listener for this is added in\n * the constructor.\n *\n * @param {Event} event\n * Key press event\n *\n * @listens keydown\n */\n handleSubmenuKeyDown(event) {\n // Escape or Tab unpress the 'button'\n if (event.key === 'Escape' || event.key === 'Tab') {\n if (this.buttonPressed_) {\n this.unpressButton();\n }\n // Don't preventDefault for Tab key - we still want to lose focus\n if (!event.key === 'Tab') {\n event.preventDefault();\n // Set focus back to the menu button's button\n this.menuButton_.focus();\n }\n }\n }\n\n /**\n * Put the current `MenuButton` into a pressed state.\n */\n pressButton() {\n if (this.enabled_) {\n this.buttonPressed_ = true;\n this.menu.show();\n this.menu.lockShowing();\n this.menuButton_.el_.setAttribute('aria-expanded', 'true');\n\n // set the focus into the submenu, except on iOS where it is resulting in\n // undesired scrolling behavior when the player is in an iframe\n if (IS_IOS && isInFrame()) {\n // Return early so that the menu isn't focused\n return;\n }\n this.menu.focus();\n }\n }\n\n /**\n * Take the current `MenuButton` out of a pressed state.\n */\n unpressButton() {\n if (this.enabled_) {\n this.buttonPressed_ = false;\n this.menu.unlockShowing();\n this.menu.hide();\n this.menuButton_.el_.setAttribute('aria-expanded', 'false');\n }\n }\n\n /**\n * Disable the `MenuButton`. Don't allow it to be clicked.\n */\n disable() {\n this.unpressButton();\n this.enabled_ = false;\n this.addClass('vjs-disabled');\n this.menuButton_.disable();\n }\n\n /**\n * Enable the `MenuButton`. Allow it to be clicked.\n */\n enable() {\n this.enabled_ = true;\n this.removeClass('vjs-disabled');\n this.menuButton_.enable();\n }\n }\n Component.registerComponent('MenuButton', MenuButton);\n\n /**\n * @file track-button.js\n */\n\n /** @import Player from './player' */\n\n /**\n * The base class for buttons that toggle specific track types (e.g. subtitles).\n *\n * @extends MenuButton\n */\n class TrackButton extends MenuButton {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n const tracks = options.tracks;\n super(player, options);\n if (this.items.length <= 1) {\n this.hide();\n }\n if (!tracks) {\n return;\n }\n const updateHandler = bind_(this, this.update);\n tracks.addEventListener('removetrack', updateHandler);\n tracks.addEventListener('addtrack', updateHandler);\n tracks.addEventListener('labelchange', updateHandler);\n this.player_.on('ready', updateHandler);\n this.player_.on('dispose', function () {\n tracks.removeEventListener('removetrack', updateHandler);\n tracks.removeEventListener('addtrack', updateHandler);\n tracks.removeEventListener('labelchange', updateHandler);\n });\n }\n }\n Component.registerComponent('TrackButton', TrackButton);\n\n /**\n * @file menu-item.js\n */\n\n /** @import Player from '../player' */\n\n /**\n * The component for a menu item. `<li>`\n *\n * @extends ClickableComponent\n */\n class MenuItem extends ClickableComponent {\n /**\n * Creates an instance of the this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options={}]\n * The key/value store of player options.\n *\n */\n constructor(player, options) {\n super(player, options);\n this.selectable = options.selectable;\n this.isSelected_ = options.selected || false;\n this.multiSelectable = options.multiSelectable;\n this.selected(this.isSelected_);\n if (this.selectable) {\n if (this.multiSelectable) {\n this.el_.setAttribute('role', 'menuitemcheckbox');\n } else {\n this.el_.setAttribute('role', 'menuitemradio');\n }\n } else {\n this.el_.setAttribute('role', 'menuitem');\n }\n }\n\n /**\n * Create the `MenuItem's DOM element\n *\n * @param {string} [type=li]\n * Element's node type, not actually used, always set to `li`.\n *\n * @param {Object} [props={}]\n * An object of properties that should be set on the element\n *\n * @param {Object} [attrs={}]\n * An object of attributes that should be set on the element\n *\n * @return {Element}\n * The element that gets created.\n */\n createEl(type, props, attrs) {\n // The control is textual, not just an icon\n this.nonIconControl = true;\n const el = super.createEl('li', Object.assign({\n className: 'vjs-menu-item',\n tabIndex: -1\n }, props), attrs);\n\n // swap icon with menu item text.\n const menuItemEl = createEl('span', {\n className: 'vjs-menu-item-text',\n textContent: this.localize(this.options_.label)\n });\n\n // If using SVG icons, the element with vjs-icon-placeholder will be added separately.\n if (this.player_.options_.experimentalSvgIcons) {\n el.appendChild(menuItemEl);\n } else {\n el.replaceChild(menuItemEl, el.querySelector('.vjs-icon-placeholder'));\n }\n return el;\n }\n\n /**\n * Ignore keys which are used by the menu, but pass any other ones up. See\n * {@link ClickableComponent#handleKeyDown} for instances where this is called.\n *\n * @param {KeyboardEvent} event\n * The `keydown` event that caused this function to be called.\n *\n * @listens keydown\n */\n handleKeyDown(event) {\n if (!['Tab', 'Escape', 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'ArrowDown'].includes(event.key)) {\n // Pass keydown handling up for unused keys\n super.handleKeyDown(event);\n }\n }\n\n /**\n * Any click on a `MenuItem` puts it into the selected state.\n * See {@link ClickableComponent#handleClick} for instances where this is called.\n *\n * @param {Event} event\n * The `keydown`, `tap`, or `click` event that caused this function to be\n * called.\n *\n * @listens tap\n * @listens click\n */\n handleClick(event) {\n this.selected(true);\n }\n\n /**\n * Set the state for this menu item as selected or not.\n *\n * @param {boolean} selected\n * if the menu item is selected or not\n */\n selected(selected) {\n if (this.selectable) {\n if (selected) {\n this.addClass('vjs-selected');\n this.el_.setAttribute('aria-checked', 'true');\n // aria-checked isn't fully supported by browsers/screen readers,\n // so indicate selected state to screen reader in the control text.\n this.controlText(', selected');\n this.isSelected_ = true;\n } else {\n this.removeClass('vjs-selected');\n this.el_.setAttribute('aria-checked', 'false');\n // Indicate un-selected state to screen reader\n this.controlText('');\n this.isSelected_ = false;\n }\n }\n }\n }\n Component.registerComponent('MenuItem', MenuItem);\n\n /**\n * @file text-track-menu-item.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * The specific menu item type for selecting a language within a text track kind\n *\n * @extends MenuItem\n */\n class TextTrackMenuItem extends MenuItem {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n const track = options.track;\n const tracks = player.textTracks();\n\n // Modify options for parent MenuItem class's init.\n options.label = track.label || track.language || 'Unknown';\n options.selected = track.mode === 'showing';\n super(player, options);\n this.track = track;\n // Determine the relevant kind(s) of tracks for this component and filter\n // out empty kinds.\n this.kinds = (options.kinds || [options.kind || this.track.kind]).filter(Boolean);\n const changeHandler = (...args) => {\n this.handleTracksChange.apply(this, args);\n };\n const selectedLanguageChangeHandler = (...args) => {\n this.handleSelectedLanguageChange.apply(this, args);\n };\n player.on(['loadstart', 'texttrackchange'], changeHandler);\n tracks.addEventListener('change', changeHandler);\n tracks.addEventListener('selectedlanguagechange', selectedLanguageChangeHandler);\n this.on('dispose', function () {\n player.off(['loadstart', 'texttrackchange'], changeHandler);\n tracks.removeEventListener('change', changeHandler);\n tracks.removeEventListener('selectedlanguagechange', selectedLanguageChangeHandler);\n });\n\n // iOS7 doesn't dispatch change events to TextTrackLists when an\n // associated track's mode changes. Without something like\n // Object.observe() (also not present on iOS7), it's not\n // possible to detect changes to the mode attribute and polyfill\n // the change event. As a poor substitute, we manually dispatch\n // change events whenever the controls modify the mode.\n if (tracks.onchange === undefined) {\n let event;\n this.on(['tap', 'click'], function () {\n if (typeof window.Event !== 'object') {\n // Android 2.3 throws an Illegal Constructor error for window.Event\n try {\n event = new window.Event('change');\n } catch (err) {\n // continue regardless of error\n }\n }\n if (!event) {\n event = document.createEvent('Event');\n event.initEvent('change', true, true);\n }\n tracks.dispatchEvent(event);\n });\n }\n\n // set the default state based on current tracks\n this.handleTracksChange();\n }\n\n /**\n * This gets called when an `TextTrackMenuItem` is \"clicked\". See\n * {@link ClickableComponent} for more detailed information on what a click can be.\n *\n * @param {Event} event\n * The `keydown`, `tap`, or `click` event that caused this function to be\n * called.\n *\n * @listens tap\n * @listens click\n */\n handleClick(event) {\n const referenceTrack = this.track;\n const tracks = this.player_.textTracks();\n super.handleClick(event);\n if (!tracks) {\n return;\n }\n for (let i = 0; i < tracks.length; i++) {\n const track = tracks[i];\n\n // If the track from the text tracks list is not of the right kind,\n // skip it. We do not want to affect tracks of incompatible kind(s).\n if (this.kinds.indexOf(track.kind) === -1) {\n continue;\n }\n\n // If this text track is the component's track and it is not showing,\n // set it to showing.\n if (track === referenceTrack) {\n if (track.mode !== 'showing') {\n track.mode = 'showing';\n }\n\n // If this text track is not the component's track and it is not\n // disabled, set it to disabled.\n } else if (track.mode !== 'disabled') {\n track.mode = 'disabled';\n }\n }\n }\n\n /**\n * Handle text track list change\n *\n * @param {Event} event\n * The `change` event that caused this function to be called.\n *\n * @listens TextTrackList#change\n */\n handleTracksChange(event) {\n const shouldBeSelected = this.track.mode === 'showing';\n\n // Prevent redundant selected() calls because they may cause\n // screen readers to read the appended control text unnecessarily\n if (shouldBeSelected !== this.isSelected_) {\n this.selected(shouldBeSelected);\n }\n }\n handleSelectedLanguageChange(event) {\n if (this.track.mode === 'showing') {\n const selectedLanguage = this.player_.cache_.selectedLanguage;\n\n // Don't replace the kind of track across the same language\n if (selectedLanguage && selectedLanguage.enabled && selectedLanguage.language === this.track.language && selectedLanguage.kind !== this.track.kind) {\n return;\n }\n this.player_.cache_.selectedLanguage = {\n enabled: true,\n language: this.track.language,\n kind: this.track.kind\n };\n }\n }\n dispose() {\n // remove reference to track object on dispose\n this.track = null;\n super.dispose();\n }\n }\n Component.registerComponent('TextTrackMenuItem', TextTrackMenuItem);\n\n /**\n * @file off-text-track-menu-item.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * A special menu item for turning off a specific type of text track\n *\n * @extends TextTrackMenuItem\n */\n class OffTextTrackMenuItem extends TextTrackMenuItem {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n // Create pseudo track info\n // Requires options['kind']\n options.track = {\n player,\n // it is no longer necessary to store `kind` or `kinds` on the track itself\n // since they are now stored in the `kinds` property of all instances of\n // TextTrackMenuItem, but this will remain for backwards compatibility\n kind: options.kind,\n kinds: options.kinds,\n default: false,\n mode: 'disabled'\n };\n if (!options.kinds) {\n options.kinds = [options.kind];\n }\n if (options.label) {\n options.track.label = options.label;\n } else {\n options.track.label = options.kinds.join(' and ') + ' off';\n }\n\n // MenuItem is selectable\n options.selectable = true;\n // MenuItem is NOT multiSelectable (i.e. only one can be marked \"selected\" at a time)\n options.multiSelectable = false;\n super(player, options);\n }\n\n /**\n * Handle text track change\n *\n * @param {Event} event\n * The event that caused this function to run\n */\n handleTracksChange(event) {\n const tracks = this.player().textTracks();\n let shouldBeSelected = true;\n for (let i = 0, l = tracks.length; i < l; i++) {\n const track = tracks[i];\n if (this.options_.kinds.indexOf(track.kind) > -1 && track.mode === 'showing') {\n shouldBeSelected = false;\n break;\n }\n }\n\n // Prevent redundant selected() calls because they may cause\n // screen readers to read the appended control text unnecessarily\n if (shouldBeSelected !== this.isSelected_) {\n this.selected(shouldBeSelected);\n }\n }\n handleSelectedLanguageChange(event) {\n const tracks = this.player().textTracks();\n let allHidden = true;\n for (let i = 0, l = tracks.length; i < l; i++) {\n const track = tracks[i];\n if (['captions', 'descriptions', 'subtitles'].indexOf(track.kind) > -1 && track.mode === 'showing') {\n allHidden = false;\n break;\n }\n }\n if (allHidden) {\n this.player_.cache_.selectedLanguage = {\n enabled: false\n };\n }\n }\n\n /**\n * Update control text and label on languagechange\n */\n handleLanguagechange() {\n this.$('.vjs-menu-item-text').textContent = this.player_.localize(this.options_.label);\n super.handleLanguagechange();\n }\n }\n Component.registerComponent('OffTextTrackMenuItem', OffTextTrackMenuItem);\n\n /**\n * @file text-track-button.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * The base class for buttons that toggle specific text track types (e.g. subtitles)\n *\n * @extends MenuButton\n */\n class TextTrackButton extends TrackButton {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options={}]\n * The key/value store of player options.\n */\n constructor(player, options = {}) {\n options.tracks = player.textTracks();\n super(player, options);\n }\n\n /**\n * Create a menu item for each text track\n *\n * @param {TextTrackMenuItem[]} [items=[]]\n * Existing array of items to use during creation\n *\n * @return {TextTrackMenuItem[]}\n * Array of menu items that were created\n */\n createItems(items = [], TrackMenuItem = TextTrackMenuItem) {\n // Label is an override for the [track] off label\n // USed to localise captions/subtitles\n let label;\n if (this.label_) {\n label = `${this.label_} off`;\n }\n // Add an OFF menu item to turn all tracks off\n items.push(new OffTextTrackMenuItem(this.player_, {\n kinds: this.kinds_,\n kind: this.kind_,\n label\n }));\n this.hideThreshold_ += 1;\n const tracks = this.player_.textTracks();\n if (!Array.isArray(this.kinds_)) {\n this.kinds_ = [this.kind_];\n }\n for (let i = 0; i < tracks.length; i++) {\n const track = tracks[i];\n\n // only add tracks that are of an appropriate kind and have a label\n if (this.kinds_.indexOf(track.kind) > -1) {\n const item = new TrackMenuItem(this.player_, {\n track,\n kinds: this.kinds_,\n kind: this.kind_,\n // MenuItem is selectable\n selectable: true,\n // MenuItem is NOT multiSelectable (i.e. only one can be marked \"selected\" at a time)\n multiSelectable: false\n });\n item.addClass(`vjs-${track.kind}-menu-item`);\n items.push(item);\n }\n }\n return items;\n }\n }\n Component.registerComponent('TextTrackButton', TextTrackButton);\n\n /**\n * @file chapters-track-menu-item.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * The chapter track menu item\n *\n * @extends MenuItem\n */\n class ChaptersTrackMenuItem extends MenuItem {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n const track = options.track;\n const cue = options.cue;\n const currentTime = player.currentTime();\n\n // Modify options for parent MenuItem class's init.\n options.selectable = true;\n options.multiSelectable = false;\n options.label = cue.text;\n options.selected = cue.startTime <= currentTime && currentTime < cue.endTime;\n super(player, options);\n this.track = track;\n this.cue = cue;\n }\n\n /**\n * This gets called when an `ChaptersTrackMenuItem` is \"clicked\". See\n * {@link ClickableComponent} for more detailed information on what a click can be.\n *\n * @param {Event} [event]\n * The `keydown`, `tap`, or `click` event that caused this function to be\n * called.\n *\n * @listens tap\n * @listens click\n */\n handleClick(event) {\n super.handleClick();\n this.player_.currentTime(this.cue.startTime);\n }\n }\n Component.registerComponent('ChaptersTrackMenuItem', ChaptersTrackMenuItem);\n\n /**\n * @file chapters-button.js\n */\n\n /** @import Player from '../../player' */\n /** @import Menu from '../../menu/menu' */\n /** @import TextTrack from '../../tracks/text-track' */\n /** @import TextTrackMenuItem from '../text-track-controls/text-track-menu-item' */\n\n /**\n * The button component for toggling and selecting chapters\n * Chapters act much differently than other text tracks\n * Cues are navigation vs. other tracks of alternative languages\n *\n * @extends TextTrackButton\n */\n class ChaptersButton extends TextTrackButton {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {Function} [ready]\n * The function to call when this function is ready.\n */\n constructor(player, options, ready) {\n super(player, options, ready);\n this.setIcon('chapters');\n this.selectCurrentItem_ = () => {\n this.items.forEach(item => {\n item.selected(this.track_.activeCues[0] === item.cue);\n });\n };\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-chapters-button ${super.buildCSSClass()}`;\n }\n buildWrapperCSSClass() {\n return `vjs-chapters-button ${super.buildWrapperCSSClass()}`;\n }\n\n /**\n * Update the menu based on the current state of its items.\n *\n * @param {Event} [event]\n * An event that triggered this function to run.\n *\n * @listens TextTrackList#addtrack\n * @listens TextTrackList#removetrack\n * @listens TextTrackList#change\n */\n update(event) {\n if (event && event.track && event.track.kind !== 'chapters') {\n return;\n }\n const track = this.findChaptersTrack();\n if (track !== this.track_) {\n this.setTrack(track);\n super.update();\n } else if (!this.items || track && track.cues && track.cues.length !== this.items.length) {\n // Update the menu initially or if the number of cues has changed since set\n super.update();\n }\n }\n\n /**\n * Set the currently selected track for the chapters button.\n *\n * @param {TextTrack} track\n * The new track to select. Nothing will change if this is the currently selected\n * track.\n */\n setTrack(track) {\n if (this.track_ === track) {\n return;\n }\n if (!this.updateHandler_) {\n this.updateHandler_ = this.update.bind(this);\n }\n\n // here this.track_ refers to the old track instance\n if (this.track_) {\n const remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(this.track_);\n if (remoteTextTrackEl) {\n remoteTextTrackEl.removeEventListener('load', this.updateHandler_);\n }\n this.track_.removeEventListener('cuechange', this.selectCurrentItem_);\n this.track_ = null;\n }\n this.track_ = track;\n\n // here this.track_ refers to the new track instance\n if (this.track_) {\n this.track_.mode = 'hidden';\n const remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(this.track_);\n if (remoteTextTrackEl) {\n remoteTextTrackEl.addEventListener('load', this.updateHandler_);\n }\n this.track_.addEventListener('cuechange', this.selectCurrentItem_);\n }\n }\n\n /**\n * Find the track object that is currently in use by this ChaptersButton\n *\n * @return {TextTrack|undefined}\n * The current track or undefined if none was found.\n */\n findChaptersTrack() {\n const tracks = this.player_.textTracks() || [];\n for (let i = tracks.length - 1; i >= 0; i--) {\n // We will always choose the last track as our chaptersTrack\n const track = tracks[i];\n if (track.kind === this.kind_) {\n return track;\n }\n }\n }\n\n /**\n * Get the caption for the ChaptersButton based on the track label. This will also\n * use the current tracks localized kind as a fallback if a label does not exist.\n *\n * @return {string}\n * The tracks current label or the localized track kind.\n */\n getMenuCaption() {\n if (this.track_ && this.track_.label) {\n return this.track_.label;\n }\n return this.localize(toTitleCase(this.kind_));\n }\n\n /**\n * Create menu from chapter track\n *\n * @return {Menu}\n * New menu for the chapter buttons\n */\n createMenu() {\n this.options_.title = this.getMenuCaption();\n return super.createMenu();\n }\n\n /**\n * Create a menu item for each text track\n *\n * @return {TextTrackMenuItem[]}\n * Array of menu items\n */\n createItems() {\n const items = [];\n if (!this.track_) {\n return items;\n }\n const cues = this.track_.cues;\n if (!cues) {\n return items;\n }\n for (let i = 0, l = cues.length; i < l; i++) {\n const cue = cues[i];\n const mi = new ChaptersTrackMenuItem(this.player_, {\n track: this.track_,\n cue\n });\n items.push(mi);\n }\n return items;\n }\n }\n\n /**\n * `kind` of TextTrack to look for to associate it with this menu.\n *\n * @type {string}\n * @private\n */\n ChaptersButton.prototype.kind_ = 'chapters';\n\n /**\n * The text that should display over the `ChaptersButton`s controls. Added for localization.\n *\n * @type {string}\n * @protected\n */\n ChaptersButton.prototype.controlText_ = 'Chapters';\n Component.registerComponent('ChaptersButton', ChaptersButton);\n\n /**\n * @file descriptions-button.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * The button component for toggling and selecting descriptions\n *\n * @extends TextTrackButton\n */\n class DescriptionsButton extends TextTrackButton {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {Function} [ready]\n * The function to call when this component is ready.\n */\n constructor(player, options, ready) {\n super(player, options, ready);\n this.setIcon('audio-description');\n const tracks = player.textTracks();\n const changeHandler = bind_(this, this.handleTracksChange);\n tracks.addEventListener('change', changeHandler);\n this.on('dispose', function () {\n tracks.removeEventListener('change', changeHandler);\n });\n }\n\n /**\n * Handle text track change\n *\n * @param {Event} event\n * The event that caused this function to run\n *\n * @listens TextTrackList#change\n */\n handleTracksChange(event) {\n const tracks = this.player().textTracks();\n let disabled = false;\n\n // Check whether a track of a different kind is showing\n for (let i = 0, l = tracks.length; i < l; i++) {\n const track = tracks[i];\n if (track.kind !== this.kind_ && track.mode === 'showing') {\n disabled = true;\n break;\n }\n }\n\n // If another track is showing, disable this menu button\n if (disabled) {\n this.disable();\n } else {\n this.enable();\n }\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-descriptions-button ${super.buildCSSClass()}`;\n }\n buildWrapperCSSClass() {\n return `vjs-descriptions-button ${super.buildWrapperCSSClass()}`;\n }\n }\n\n /**\n * `kind` of TextTrack to look for to associate it with this menu.\n *\n * @type {string}\n * @private\n */\n DescriptionsButton.prototype.kind_ = 'descriptions';\n\n /**\n * The text that should display over the `DescriptionsButton`s controls. Added for localization.\n *\n * @type {string}\n * @protected\n */\n DescriptionsButton.prototype.controlText_ = 'Descriptions';\n Component.registerComponent('DescriptionsButton', DescriptionsButton);\n\n /**\n * @file subtitles-button.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * The button component for toggling and selecting subtitles\n *\n * @extends TextTrackButton\n */\n class SubtitlesButton extends TextTrackButton {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {Function} [ready]\n * The function to call when this component is ready.\n */\n constructor(player, options, ready) {\n super(player, options, ready);\n this.setIcon('subtitles');\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-subtitles-button ${super.buildCSSClass()}`;\n }\n buildWrapperCSSClass() {\n return `vjs-subtitles-button ${super.buildWrapperCSSClass()}`;\n }\n }\n\n /**\n * `kind` of TextTrack to look for to associate it with this menu.\n *\n * @type {string}\n * @private\n */\n SubtitlesButton.prototype.kind_ = 'subtitles';\n\n /**\n * The text that should display over the `SubtitlesButton`s controls. Added for localization.\n *\n * @type {string}\n * @protected\n */\n SubtitlesButton.prototype.controlText_ = 'Subtitles';\n Component.registerComponent('SubtitlesButton', SubtitlesButton);\n\n /**\n * @file caption-settings-menu-item.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * The menu item for caption track settings menu\n *\n * @extends TextTrackMenuItem\n */\n class CaptionSettingsMenuItem extends TextTrackMenuItem {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n options.track = {\n player,\n kind: options.kind,\n label: options.kind + ' settings',\n selectable: false,\n default: false,\n mode: 'disabled'\n };\n\n // CaptionSettingsMenuItem has no concept of 'selected'\n options.selectable = false;\n options.name = 'CaptionSettingsMenuItem';\n super(player, options);\n this.addClass('vjs-texttrack-settings');\n this.controlText(', opens ' + options.kind + ' settings dialog');\n }\n\n /**\n * This gets called when an `CaptionSettingsMenuItem` is \"clicked\". See\n * {@link ClickableComponent} for more detailed information on what a click can be.\n *\n * @param {Event} [event]\n * The `keydown`, `tap`, or `click` event that caused this function to be\n * called.\n *\n * @listens tap\n * @listens click\n */\n handleClick(event) {\n this.player().getChild('textTrackSettings').open();\n }\n\n /**\n * Update control text and label on languagechange\n */\n handleLanguagechange() {\n this.$('.vjs-menu-item-text').textContent = this.player_.localize(this.options_.kind + ' settings');\n super.handleLanguagechange();\n }\n }\n Component.registerComponent('CaptionSettingsMenuItem', CaptionSettingsMenuItem);\n\n /**\n * @file captions-button.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * The button component for toggling and selecting captions\n *\n * @extends TextTrackButton\n */\n class CaptionsButton extends TextTrackButton {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {Function} [ready]\n * The function to call when this component is ready.\n */\n constructor(player, options, ready) {\n super(player, options, ready);\n this.setIcon('captions');\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-captions-button ${super.buildCSSClass()}`;\n }\n buildWrapperCSSClass() {\n return `vjs-captions-button ${super.buildWrapperCSSClass()}`;\n }\n\n /**\n * Create caption menu items\n *\n * @return {CaptionSettingsMenuItem[]}\n * The array of current menu items.\n */\n createItems() {\n const items = [];\n if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks) && this.player().getChild('textTrackSettings')) {\n items.push(new CaptionSettingsMenuItem(this.player_, {\n kind: this.kind_\n }));\n this.hideThreshold_ += 1;\n }\n return super.createItems(items);\n }\n }\n\n /**\n * `kind` of TextTrack to look for to associate it with this menu.\n *\n * @type {string}\n * @private\n */\n CaptionsButton.prototype.kind_ = 'captions';\n\n /**\n * The text that should display over the `CaptionsButton`s controls. Added for localization.\n *\n * @type {string}\n * @protected\n */\n CaptionsButton.prototype.controlText_ = 'Captions';\n Component.registerComponent('CaptionsButton', CaptionsButton);\n\n /**\n * @file subs-caps-menu-item.js\n */\n\n /**\n * SubsCapsMenuItem has an [cc] icon to distinguish captions from subtitles\n * in the SubsCapsMenu.\n *\n * @extends TextTrackMenuItem\n */\n class SubsCapsMenuItem extends TextTrackMenuItem {\n createEl(type, props, attrs) {\n const el = super.createEl(type, props, attrs);\n const parentSpan = el.querySelector('.vjs-menu-item-text');\n if (this.options_.track.kind === 'captions') {\n if (this.player_.options_.experimentalSvgIcons) {\n this.setIcon('captions', el);\n } else {\n parentSpan.appendChild(createEl('span', {\n className: 'vjs-icon-placeholder'\n }, {\n 'aria-hidden': true\n }));\n }\n parentSpan.appendChild(createEl('span', {\n className: 'vjs-control-text',\n // space added as the text will visually flow with the\n // label\n textContent: ` ${this.localize('Captions')}`\n }));\n }\n return el;\n }\n }\n Component.registerComponent('SubsCapsMenuItem', SubsCapsMenuItem);\n\n /**\n * @file sub-caps-button.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * The button component for toggling and selecting captions and/or subtitles\n *\n * @extends TextTrackButton\n */\n class SubsCapsButton extends TextTrackButton {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {Function} [ready]\n * The function to call when this component is ready.\n */\n constructor(player, options = {}) {\n super(player, options);\n\n // Although North America uses \"captions\" in most cases for\n // \"captions and subtitles\" other locales use \"subtitles\"\n this.label_ = 'subtitles';\n this.setIcon('subtitles');\n if (['en', 'en-us', 'en-ca', 'fr-ca'].indexOf(this.player_.language_) > -1) {\n this.label_ = 'captions';\n this.setIcon('captions');\n }\n this.menuButton_.controlText(toTitleCase(this.label_));\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-subs-caps-button ${super.buildCSSClass()}`;\n }\n buildWrapperCSSClass() {\n return `vjs-subs-caps-button ${super.buildWrapperCSSClass()}`;\n }\n\n /**\n * Create caption/subtitles menu items\n *\n * @return {CaptionSettingsMenuItem[]}\n * The array of current menu items.\n */\n createItems() {\n let items = [];\n if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks) && this.player().getChild('textTrackSettings')) {\n items.push(new CaptionSettingsMenuItem(this.player_, {\n kind: this.label_\n }));\n this.hideThreshold_ += 1;\n }\n items = super.createItems(items, SubsCapsMenuItem);\n return items;\n }\n }\n\n /**\n * `kind`s of TextTrack to look for to associate it with this menu.\n *\n * @type {array}\n * @private\n */\n SubsCapsButton.prototype.kinds_ = ['captions', 'subtitles'];\n\n /**\n * The text that should display over the `SubsCapsButton`s controls.\n *\n *\n * @type {string}\n * @protected\n */\n SubsCapsButton.prototype.controlText_ = 'Subtitles';\n Component.registerComponent('SubsCapsButton', SubsCapsButton);\n\n /**\n * @file audio-track-menu-item.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * An {@link AudioTrack} {@link MenuItem}\n *\n * @extends MenuItem\n */\n class AudioTrackMenuItem extends MenuItem {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n const track = options.track;\n const tracks = player.audioTracks();\n\n // Modify options for parent MenuItem class's init.\n options.label = track.label || track.language || 'Unknown';\n options.selected = track.enabled;\n super(player, options);\n this.track = track;\n this.addClass(`vjs-${track.kind}-menu-item`);\n const changeHandler = (...args) => {\n this.handleTracksChange.apply(this, args);\n };\n tracks.addEventListener('change', changeHandler);\n this.on('dispose', () => {\n tracks.removeEventListener('change', changeHandler);\n });\n }\n createEl(type, props, attrs) {\n const el = super.createEl(type, props, attrs);\n const parentSpan = el.querySelector('.vjs-menu-item-text');\n if (['main-desc', 'descriptions'].indexOf(this.options_.track.kind) >= 0) {\n parentSpan.appendChild(createEl('span', {\n className: 'vjs-icon-placeholder'\n }, {\n 'aria-hidden': true\n }));\n parentSpan.appendChild(createEl('span', {\n className: 'vjs-control-text',\n textContent: ' ' + this.localize('Descriptions')\n }));\n }\n return el;\n }\n\n /**\n * This gets called when an `AudioTrackMenuItem is \"clicked\". See {@link ClickableComponent}\n * for more detailed information on what a click can be.\n *\n * @param {Event} [event]\n * The `keydown`, `tap`, or `click` event that caused this function to be\n * called.\n *\n * @listens tap\n * @listens click\n */\n handleClick(event) {\n super.handleClick(event);\n\n // the audio track list will automatically toggle other tracks\n // off for us.\n this.track.enabled = true;\n\n // when native audio tracks are used, we want to make sure that other tracks are turned off\n if (this.player_.tech_.featuresNativeAudioTracks) {\n const tracks = this.player_.audioTracks();\n for (let i = 0; i < tracks.length; i++) {\n const track = tracks[i];\n\n // skip the current track since we enabled it above\n if (track === this.track) {\n continue;\n }\n track.enabled = track === this.track;\n }\n }\n }\n\n /**\n * Handle any {@link AudioTrack} change.\n *\n * @param {Event} [event]\n * The {@link AudioTrackList#change} event that caused this to run.\n *\n * @listens AudioTrackList#change\n */\n handleTracksChange(event) {\n this.selected(this.track.enabled);\n }\n }\n Component.registerComponent('AudioTrackMenuItem', AudioTrackMenuItem);\n\n /**\n * @file audio-track-button.js\n */\n\n /**\n * The base class for buttons that toggle specific {@link AudioTrack} types.\n *\n * @extends TrackButton\n */\n class AudioTrackButton extends TrackButton {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options={}]\n * The key/value store of player options.\n */\n constructor(player, options = {}) {\n options.tracks = player.audioTracks();\n super(player, options);\n this.setIcon('audio');\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-audio-button ${super.buildCSSClass()}`;\n }\n buildWrapperCSSClass() {\n return `vjs-audio-button ${super.buildWrapperCSSClass()}`;\n }\n\n /**\n * Create a menu item for each audio track\n *\n * @param {AudioTrackMenuItem[]} [items=[]]\n * An array of existing menu items to use.\n *\n * @return {AudioTrackMenuItem[]}\n * An array of menu items\n */\n createItems(items = []) {\n // if there's only one audio track, there no point in showing it\n this.hideThreshold_ = 1;\n const tracks = this.player_.audioTracks();\n for (let i = 0; i < tracks.length; i++) {\n const track = tracks[i];\n items.push(new AudioTrackMenuItem(this.player_, {\n track,\n // MenuItem is selectable\n selectable: true,\n // MenuItem is NOT multiSelectable (i.e. only one can be marked \"selected\" at a time)\n multiSelectable: false\n }));\n }\n return items;\n }\n }\n\n /**\n * The text that should display over the `AudioTrackButton`s controls. Added for localization.\n *\n * @type {string}\n * @protected\n */\n AudioTrackButton.prototype.controlText_ = 'Audio Track';\n Component.registerComponent('AudioTrackButton', AudioTrackButton);\n\n /**\n * @file playback-rate-menu-item.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * The specific menu item type for selecting a playback rate.\n *\n * @extends MenuItem\n */\n class PlaybackRateMenuItem extends MenuItem {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n const label = options.rate;\n const rate = parseFloat(label, 10);\n\n // Modify options for parent MenuItem class's init.\n options.label = label;\n options.selected = rate === player.playbackRate();\n options.selectable = true;\n options.multiSelectable = false;\n super(player, options);\n this.label = label;\n this.rate = rate;\n this.on(player, 'ratechange', e => this.update(e));\n }\n\n /**\n * This gets called when an `PlaybackRateMenuItem` is \"clicked\". See\n * {@link ClickableComponent} for more detailed information on what a click can be.\n *\n * @param {Event} [event]\n * The `keydown`, `tap`, or `click` event that caused this function to be\n * called.\n *\n * @listens tap\n * @listens click\n */\n handleClick(event) {\n super.handleClick();\n this.player().playbackRate(this.rate);\n }\n\n /**\n * Update the PlaybackRateMenuItem when the playbackrate changes.\n *\n * @param {Event} [event]\n * The `ratechange` event that caused this function to run.\n *\n * @listens Player#ratechange\n */\n update(event) {\n this.selected(this.player().playbackRate() === this.rate);\n }\n }\n\n /**\n * The text that should display over the `PlaybackRateMenuItem`s controls. Added for localization.\n *\n * @type {string}\n * @private\n */\n PlaybackRateMenuItem.prototype.contentElType = 'button';\n Component.registerComponent('PlaybackRateMenuItem', PlaybackRateMenuItem);\n\n /**\n * @file playback-rate-menu-button.js\n */\n\n /** @import Player from '../../player' */\n\n /**\n * The component for controlling the playback rate.\n *\n * @extends MenuButton\n */\n class PlaybackRateMenuButton extends MenuButton {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.menuButton_.el_.setAttribute('aria-describedby', this.labelElId_);\n this.updateVisibility();\n this.updateLabel();\n this.on(player, 'loadstart', e => this.updateVisibility(e));\n this.on(player, 'ratechange', e => this.updateLabel(e));\n this.on(player, 'playbackrateschange', e => this.handlePlaybackRateschange(e));\n }\n\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n const el = super.createEl();\n this.labelElId_ = 'vjs-playback-rate-value-label-' + this.id_;\n this.labelEl_ = createEl('div', {\n className: 'vjs-playback-rate-value',\n id: this.labelElId_,\n textContent: '1x'\n });\n el.appendChild(this.labelEl_);\n return el;\n }\n dispose() {\n this.labelEl_ = null;\n super.dispose();\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-playback-rate ${super.buildCSSClass()}`;\n }\n buildWrapperCSSClass() {\n return `vjs-playback-rate ${super.buildWrapperCSSClass()}`;\n }\n\n /**\n * Create the list of menu items. Specific to each subclass.\n *\n */\n createItems() {\n const rates = this.playbackRates();\n const items = [];\n for (let i = rates.length - 1; i >= 0; i--) {\n items.push(new PlaybackRateMenuItem(this.player(), {\n rate: rates[i] + 'x'\n }));\n }\n return items;\n }\n\n /**\n * On playbackrateschange, update the menu to account for the new items.\n *\n * @listens Player#playbackrateschange\n */\n handlePlaybackRateschange(event) {\n this.update();\n }\n\n /**\n * Get possible playback rates\n *\n * @return {Array}\n * All possible playback rates\n */\n playbackRates() {\n const player = this.player();\n return player.playbackRates && player.playbackRates() || [];\n }\n\n /**\n * Get whether playback rates is supported by the tech\n * and an array of playback rates exists\n *\n * @return {boolean}\n * Whether changing playback rate is supported\n */\n playbackRateSupported() {\n return this.player().tech_ && this.player().tech_.featuresPlaybackRate && this.playbackRates() && this.playbackRates().length > 0;\n }\n\n /**\n * Hide playback rate controls when they're no playback rate options to select\n *\n * @param {Event} [event]\n * The event that caused this function to run.\n *\n * @listens Player#loadstart\n */\n updateVisibility(event) {\n if (this.playbackRateSupported()) {\n this.removeClass('vjs-hidden');\n } else {\n this.addClass('vjs-hidden');\n }\n }\n\n /**\n * Update button label when rate changed\n *\n * @param {Event} [event]\n * The event that caused this function to run.\n *\n * @listens Player#ratechange\n */\n updateLabel(event) {\n if (this.playbackRateSupported()) {\n this.labelEl_.textContent = this.player().playbackRate() + 'x';\n }\n }\n }\n\n /**\n * The text that should display over the `PlaybackRateMenuButton`s controls.\n *\n * Added for localization.\n *\n * @type {string}\n * @protected\n */\n PlaybackRateMenuButton.prototype.controlText_ = 'Playback Rate';\n Component.registerComponent('PlaybackRateMenuButton', PlaybackRateMenuButton);\n\n /**\n * @file spacer.js\n */\n\n /**\n * Just an empty spacer element that can be used as an append point for plugins, etc.\n * Also can be used to create space between elements when necessary.\n *\n * @extends Component\n */\n class Spacer extends Component {\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-spacer ${super.buildCSSClass()}`;\n }\n\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl(tag = 'div', props = {}, attributes = {}) {\n if (!props.className) {\n props.className = this.buildCSSClass();\n }\n return super.createEl(tag, props, attributes);\n }\n }\n Component.registerComponent('Spacer', Spacer);\n\n /**\n * @file custom-control-spacer.js\n */\n\n /**\n * Spacer specifically meant to be used as an insertion point for new plugins, etc.\n *\n * @extends Spacer\n */\n class CustomControlSpacer extends Spacer {\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n */\n buildCSSClass() {\n return `vjs-custom-control-spacer ${super.buildCSSClass()}`;\n }\n\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n return super.createEl('div', {\n className: this.buildCSSClass(),\n // No-flex/table-cell mode requires there be some content\n // in the cell to fill the remaining space of the table.\n textContent: '\\u00a0'\n });\n }\n }\n Component.registerComponent('CustomControlSpacer', CustomControlSpacer);\n\n /**\n * @file control-bar.js\n */\n\n /**\n * Container of main controls.\n *\n * @extends Component\n */\n class ControlBar extends Component {\n /**\n * Create the `Component`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n return super.createEl('div', {\n className: 'vjs-control-bar',\n dir: 'ltr'\n });\n }\n }\n\n /**\n * Default options for `ControlBar`\n *\n * @type {Object}\n * @private\n */\n ControlBar.prototype.options_ = {\n children: ['playToggle', 'skipBackward', 'skipForward', 'volumePanel', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'seekToLive', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'descriptionsButton', 'subsCapsButton', 'audioTrackButton', 'pictureInPictureToggle', 'fullscreenToggle']\n };\n Component.registerComponent('ControlBar', ControlBar);\n\n /**\n * @file error-display.js\n */\n\n /** @import Player from './player' */\n\n /**\n * A display that indicates an error has occurred. This means that the video\n * is unplayable.\n *\n * @extends ModalDialog\n */\n class ErrorDisplay extends ModalDialog {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n super(player, options);\n this.on(player, 'error', e => {\n this.open(e);\n });\n }\n\n /**\n * Builds the default DOM `className`.\n *\n * @return {string}\n * The DOM `className` for this object.\n *\n * @deprecated Since version 5.\n */\n buildCSSClass() {\n return `vjs-error-display ${super.buildCSSClass()}`;\n }\n\n /**\n * Gets the localized error message based on the `Player`s error.\n *\n * @return {string}\n * The `Player`s error message localized or an empty string.\n */\n content() {\n const error = this.player().error();\n return error ? this.localize(error.message) : '';\n }\n }\n\n /**\n * The default options for an `ErrorDisplay`.\n *\n * @private\n */\n ErrorDisplay.prototype.options_ = Object.assign({}, ModalDialog.prototype.options_, {\n pauseOnOpen: false,\n fillAlways: true,\n temporary: false,\n uncloseable: true\n });\n Component.registerComponent('ErrorDisplay', ErrorDisplay);\n\n /** @import Player from './player' */\n /** @import { ContentDescriptor } from '../utils/dom' */\n\n /**\n * Creates DOM element of 'select' & its options.\n *\n * @extends Component\n */\n class TextTrackSelect extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {ContentDescriptor} [options.content=undefined]\n * Provide customized content for this modal.\n *\n * @param {string} [options.legendId]\n * A text with part of an string to create atribute of aria-labelledby.\n *\n * @param {string} [options.id]\n * A text with part of an string to create atribute of aria-labelledby.\n *\n * @param {Array} [options.SelectOptions]\n * Array that contains the value & textContent of for each of the\n * options elements.\n */\n constructor(player, options = {}) {\n super(player, options);\n this.el_.setAttribute('aria-labelledby', this.selectLabelledbyIds);\n }\n\n /**\n * Create the `TextTrackSelect`'s DOM element\n *\n * @return {Element}\n * The DOM element that gets created.\n */\n createEl() {\n this.selectLabelledbyIds = [this.options_.legendId, this.options_.labelId].join(' ').trim();\n\n // Create select & inner options\n const selectoptions = createEl('select', {\n id: this.options_.id\n }, {}, this.options_.SelectOptions.map(optionText => {\n // Constructs an id for the <option>.\n // For the colour settings that have two <selects> with a <label> each, generates an id based off the label value\n // For font size/family and edge style with one <select> and no <label>, generates an id with a guid\n const optionId = (this.options_.labelId ? this.options_.labelId : `vjs-track-option-${newGUID()}`) + '-' + optionText[1].replace(/\\W+/g, '');\n const option = createEl('option', {\n id: optionId,\n value: this.localize(optionText[0]),\n textContent: this.localize(optionText[1])\n });\n option.setAttribute('aria-labelledby', `${this.selectLabelledbyIds} ${optionId}`);\n return option;\n }));\n return selectoptions;\n }\n }\n Component.registerComponent('TextTrackSelect', TextTrackSelect);\n\n /** @import Player from './player' */\n /** @import { ContentDescriptor } from '../utils/dom' */\n\n /**\n * Creates fieldset section of 'TextTrackSettings'.\n * Manganes two versions of fieldsets, one for type of 'colors'\n * & the other for 'font', Component adds diferent DOM elements\n * to that fieldset depending on the type.\n *\n * @extends Component\n */\n class TextTrackFieldset extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {ContentDescriptor} [options.content=undefined]\n * Provide customized content for this modal.\n *\n * @param {string} [options.legendId]\n * A text with part of an string to create atribute of aria-labelledby.\n * It passes to 'TextTrackSelect'.\n *\n * @param {string} [options.id]\n * A text with part of an string to create atribute of aria-labelledby.\n * It passes to 'TextTrackSelect'.\n *\n * @param {string} [options.legendText]\n * A text to use as the text content of the legend element.\n *\n * @param {Array} [options.selects]\n * Array that contains the selects that are use to create 'selects'\n * components.\n *\n * @param {Array} [options.SelectOptions]\n * Array that contains the value & textContent of for each of the\n * options elements, it passes to 'TextTrackSelect'.\n *\n * @param {string} [options.type]\n * Conditions if some DOM elements will be added to the fieldset\n * component.\n *\n * @param {Object} [options.selectConfigs]\n * Object with the following properties that are the selects configurations:\n * backgroundColor, backgroundOpacity, color, edgeStyle, fontFamily,\n * fontPercent, textOpacity, windowColor, windowOpacity.\n * These properties are use to configure the 'TextTrackSelect' Component.\n */\n constructor(player, options = {}) {\n super(player, options);\n\n // Add Components & DOM Elements\n const legendElement = createEl('legend', {\n textContent: this.localize(this.options_.legendText),\n id: this.options_.legendId\n });\n this.el().appendChild(legendElement);\n const selects = this.options_.selects;\n\n // Iterate array of selects to create 'selects' components\n for (const i of selects) {\n const selectConfig = this.options_.selectConfigs[i];\n const selectClassName = selectConfig.className;\n const id = selectConfig.id.replace('%s', this.options_.id_);\n let span = null;\n const guid = `vjs_select_${newGUID()}`;\n\n // Conditionally create span to add on the component\n if (this.options_.type === 'colors') {\n span = createEl('span', {\n className: selectClassName\n });\n const label = createEl('label', {\n id,\n className: 'vjs-label',\n textContent: this.localize(selectConfig.label)\n });\n label.setAttribute('for', guid);\n span.appendChild(label);\n }\n const textTrackSelect = new TextTrackSelect(player, {\n SelectOptions: selectConfig.options,\n legendId: this.options_.legendId,\n id: guid,\n labelId: id\n });\n this.addChild(textTrackSelect);\n\n // Conditionally append to 'select' component to conditionally created span\n if (this.options_.type === 'colors') {\n span.appendChild(textTrackSelect.el());\n this.el().appendChild(span);\n }\n }\n }\n\n /**\n * Create the `TextTrackFieldset`'s DOM element\n *\n * @return {Element}\n * The DOM element that gets created.\n */\n createEl() {\n const el = createEl('fieldset', {\n // Prefixing classes of elements within a player with \"vjs-\"\n // is a convention used in Video.js.\n className: this.options_.className\n });\n return el;\n }\n }\n Component.registerComponent('TextTrackFieldset', TextTrackFieldset);\n\n /** @import Player from './player' */\n /** @import { ContentDescriptor } from '../utils/dom' */\n\n /**\n * The component 'TextTrackSettingsColors' displays a set of 'fieldsets'\n * using the component 'TextTrackFieldset'.\n *\n * @extends Component\n */\n class TextTrackSettingsColors extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {ContentDescriptor} [options.content=undefined]\n * Provide customized content for this modal.\n *\n * @param {Array} [options.fieldSets]\n * Array that contains the configurations for the selects.\n *\n * @param {Object} [options.selectConfigs]\n * Object with the following properties that are the select confugations:\n * backgroundColor, backgroundOpacity, color, edgeStyle, fontFamily,\n * fontPercent, textOpacity, windowColor, windowOpacity.\n * it passes to 'TextTrackFieldset'.\n */\n constructor(player, options = {}) {\n super(player, options);\n const id_ = this.options_.textTrackComponentid;\n\n // createElFgColor_\n const ElFgColorFieldset = new TextTrackFieldset(player, {\n id_,\n legendId: `captions-text-legend-${id_}`,\n legendText: this.localize('Text'),\n className: 'vjs-fg vjs-track-setting',\n selects: this.options_.fieldSets[0],\n selectConfigs: this.options_.selectConfigs,\n type: 'colors'\n });\n this.addChild(ElFgColorFieldset);\n\n // createElBgColor_\n const ElBgColorFieldset = new TextTrackFieldset(player, {\n id_,\n legendId: `captions-background-${id_}`,\n legendText: this.localize('Text Background'),\n className: 'vjs-bg vjs-track-setting',\n selects: this.options_.fieldSets[1],\n selectConfigs: this.options_.selectConfigs,\n type: 'colors'\n });\n this.addChild(ElBgColorFieldset);\n\n // createElWinColor_\n const ElWinColorFieldset = new TextTrackFieldset(player, {\n id_,\n legendId: `captions-window-${id_}`,\n legendText: this.localize('Caption Area Background'),\n className: 'vjs-window vjs-track-setting',\n selects: this.options_.fieldSets[2],\n selectConfigs: this.options_.selectConfigs,\n type: 'colors'\n });\n this.addChild(ElWinColorFieldset);\n }\n\n /**\n * Create the `TextTrackSettingsColors`'s DOM element\n *\n * @return {Element}\n * The DOM element that gets created.\n */\n createEl() {\n const el = createEl('div', {\n className: 'vjs-track-settings-colors'\n });\n return el;\n }\n }\n Component.registerComponent('TextTrackSettingsColors', TextTrackSettingsColors);\n\n /** @import Player from './player' */\n /** @import { ContentDescriptor } from '../utils/dom' */\n\n /**\n * The component 'TextTrackSettingsFont' displays a set of 'fieldsets'\n * using the component 'TextTrackFieldset'.\n *\n * @extends Component\n */\n class TextTrackSettingsFont extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {ContentDescriptor} [options.content=undefined]\n * Provide customized content for this modal.\n *\n * @param {Array} [options.fieldSets]\n * Array that contains the configurations for the selects.\n *\n * @param {Object} [options.selectConfigs]\n * Object with the following properties that are the select confugations:\n * backgroundColor, backgroundOpacity, color, edgeStyle, fontFamily,\n * fontPercent, textOpacity, windowColor, windowOpacity.\n * it passes to 'TextTrackFieldset'.\n */\n constructor(player, options = {}) {\n super(player, options);\n const id_ = this.options_.textTrackComponentid;\n const ElFgColorFieldset = new TextTrackFieldset(player, {\n id_,\n legendId: `captions-font-size-${id_}`,\n legendText: 'Font Size',\n className: 'vjs-font-percent vjs-track-setting',\n selects: this.options_.fieldSets[0],\n selectConfigs: this.options_.selectConfigs,\n type: 'font'\n });\n this.addChild(ElFgColorFieldset);\n const ElBgColorFieldset = new TextTrackFieldset(player, {\n id_,\n legendId: `captions-edge-style-${id_}`,\n legendText: this.localize('Text Edge Style'),\n className: 'vjs-edge-style vjs-track-setting',\n selects: this.options_.fieldSets[1],\n selectConfigs: this.options_.selectConfigs,\n type: 'font'\n });\n this.addChild(ElBgColorFieldset);\n const ElWinColorFieldset = new TextTrackFieldset(player, {\n id_,\n legendId: `captions-font-family-${id_}`,\n legendText: this.localize('Font Family'),\n className: 'vjs-font-family vjs-track-setting',\n selects: this.options_.fieldSets[2],\n selectConfigs: this.options_.selectConfigs,\n type: 'font'\n });\n this.addChild(ElWinColorFieldset);\n }\n\n /**\n * Create the `TextTrackSettingsFont`'s DOM element\n *\n * @return {Element}\n * The DOM element that gets created.\n */\n createEl() {\n const el = createEl('div', {\n className: 'vjs-track-settings-font'\n });\n return el;\n }\n }\n Component.registerComponent('TextTrackSettingsFont', TextTrackSettingsFont);\n\n /**\n * Buttons of reset & done that modal 'TextTrackSettings'\n * uses as part of its content.\n *\n * 'Reset': Resets all settings on 'TextTrackSettings'.\n * 'Done': Closes 'TextTrackSettings' modal.\n *\n * @extends Component\n */\n class TrackSettingsControls extends Component {\n constructor(player, options = {}) {\n super(player, options);\n\n // Create DOM elements\n const resetButton = new Button(player, {\n controlText: this.localize('restore all settings to the default values'),\n className: 'vjs-default-button'\n });\n resetButton.el().classList.remove('vjs-control', 'vjs-button');\n resetButton.el().textContent = this.localize('Reset');\n this.addChild(resetButton);\n const doneText = this.localize('Done');\n const doneButton = new Button(player, {\n controlText: doneText,\n className: 'vjs-done-button'\n });\n\n // Remove unrequired style classes\n doneButton.el().classList.remove('vjs-control', 'vjs-button');\n doneButton.el().textContent = doneText;\n this.addChild(doneButton);\n }\n\n /**\n * Create the `TrackSettingsControls`'s DOM element\n *\n * @return {Element}\n * The DOM element that gets created.\n */\n createEl() {\n const el = createEl('div', {\n className: 'vjs-track-settings-controls'\n });\n return el;\n }\n }\n Component.registerComponent('TrackSettingsControls', TrackSettingsControls);\n\n /**\n * @file text-track-settings.js\n */\n\n /** @import Player from '../player' */\n\n const LOCAL_STORAGE_KEY = 'vjs-text-track-settings';\n const COLOR_BLACK = ['#000', 'Black'];\n const COLOR_BLUE = ['#00F', 'Blue'];\n const COLOR_CYAN = ['#0FF', 'Cyan'];\n const COLOR_GREEN = ['#0F0', 'Green'];\n const COLOR_MAGENTA = ['#F0F', 'Magenta'];\n const COLOR_RED = ['#F00', 'Red'];\n const COLOR_WHITE = ['#FFF', 'White'];\n const COLOR_YELLOW = ['#FF0', 'Yellow'];\n const OPACITY_OPAQUE = ['1', 'Opaque'];\n const OPACITY_SEMI = ['0.5', 'Semi-Transparent'];\n const OPACITY_TRANS = ['0', 'Transparent'];\n\n // Configuration for the various <select> elements in the DOM of this component.\n //\n // Possible keys include:\n //\n // `default`:\n // The default option index. Only needs to be provided if not zero.\n // `parser`:\n // A function which is used to parse the value from the selected option in\n // a customized way.\n // `selector`:\n // The selector used to find the associated <select> element.\n const selectConfigs = {\n backgroundColor: {\n selector: '.vjs-bg-color > select',\n id: 'captions-background-color-%s',\n label: 'Color',\n options: [COLOR_BLACK, COLOR_WHITE, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_YELLOW, COLOR_MAGENTA, COLOR_CYAN],\n className: 'vjs-bg-color'\n },\n backgroundOpacity: {\n selector: '.vjs-bg-opacity > select',\n id: 'captions-background-opacity-%s',\n label: 'Opacity',\n options: [OPACITY_OPAQUE, OPACITY_SEMI, OPACITY_TRANS],\n className: 'vjs-bg-opacity vjs-opacity'\n },\n color: {\n selector: '.vjs-text-color > select',\n id: 'captions-foreground-color-%s',\n label: 'Color',\n options: [COLOR_WHITE, COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_YELLOW, COLOR_MAGENTA, COLOR_CYAN],\n className: 'vjs-text-color'\n },\n edgeStyle: {\n selector: '.vjs-edge-style > select',\n id: '',\n label: 'Text Edge Style',\n options: [['none', 'None'], ['raised', 'Raised'], ['depressed', 'Depressed'], ['uniform', 'Uniform'], ['dropshadow', 'Drop shadow']]\n },\n fontFamily: {\n selector: '.vjs-font-family > select',\n id: '',\n label: 'Font Family',\n options: [['proportionalSansSerif', 'Proportional Sans-Serif'], ['monospaceSansSerif', 'Monospace Sans-Serif'], ['proportionalSerif', 'Proportional Serif'], ['monospaceSerif', 'Monospace Serif'], ['casual', 'Casual'], ['script', 'Script'], ['small-caps', 'Small Caps']]\n },\n fontPercent: {\n selector: '.vjs-font-percent > select',\n id: '',\n label: 'Font Size',\n options: [['0.50', '50%'], ['0.75', '75%'], ['1.00', '100%'], ['1.25', '125%'], ['1.50', '150%'], ['1.75', '175%'], ['2.00', '200%'], ['3.00', '300%'], ['4.00', '400%']],\n default: 2,\n parser: v => v === '1.00' ? null : Number(v)\n },\n textOpacity: {\n selector: '.vjs-text-opacity > select',\n id: 'captions-foreground-opacity-%s',\n label: 'Opacity',\n options: [OPACITY_OPAQUE, OPACITY_SEMI],\n className: 'vjs-text-opacity vjs-opacity'\n },\n // Options for this object are defined below.\n windowColor: {\n selector: '.vjs-window-color > select',\n id: 'captions-window-color-%s',\n label: 'Color',\n className: 'vjs-window-color'\n },\n // Options for this object are defined below.\n windowOpacity: {\n selector: '.vjs-window-opacity > select',\n id: 'captions-window-opacity-%s',\n label: 'Opacity',\n options: [OPACITY_TRANS, OPACITY_SEMI, OPACITY_OPAQUE],\n className: 'vjs-window-opacity vjs-opacity'\n }\n };\n selectConfigs.windowColor.options = selectConfigs.backgroundColor.options;\n\n /**\n * Get the actual value of an option.\n *\n * @param {string} value\n * The value to get\n *\n * @param {Function} [parser]\n * Optional function to adjust the value.\n *\n * @return {*}\n * - Will be `undefined` if no value exists\n * - Will be `undefined` if the given value is \"none\".\n * - Will be the actual value otherwise.\n *\n * @private\n */\n function parseOptionValue(value, parser) {\n if (parser) {\n value = parser(value);\n }\n if (value && value !== 'none') {\n return value;\n }\n }\n\n /**\n * Gets the value of the selected <option> element within a <select> element.\n *\n * @param {Element} el\n * the element to look in\n *\n * @param {Function} [parser]\n * Optional function to adjust the value.\n *\n * @return {*}\n * - Will be `undefined` if no value exists\n * - Will be `undefined` if the given value is \"none\".\n * - Will be the actual value otherwise.\n *\n * @private\n */\n function getSelectedOptionValue(el, parser) {\n const value = el.options[el.options.selectedIndex].value;\n return parseOptionValue(value, parser);\n }\n\n /**\n * Sets the selected <option> element within a <select> element based on a\n * given value.\n *\n * @param {Element} el\n * The element to look in.\n *\n * @param {string} value\n * the property to look on.\n *\n * @param {Function} [parser]\n * Optional function to adjust the value before comparing.\n *\n * @private\n */\n function setSelectedOption(el, value, parser) {\n if (!value) {\n return;\n }\n for (let i = 0; i < el.options.length; i++) {\n if (parseOptionValue(el.options[i].value, parser) === value) {\n el.selectedIndex = i;\n break;\n }\n }\n }\n\n /**\n * Manipulate Text Tracks settings.\n *\n * @extends ModalDialog\n */\n class TextTrackSettings extends ModalDialog {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n */\n constructor(player, options) {\n options.temporary = false;\n super(player, options);\n this.updateDisplay = this.updateDisplay.bind(this);\n\n // fill the modal and pretend we have opened it\n this.fill();\n this.hasBeenOpened_ = this.hasBeenFilled_ = true;\n this.renderModalComponents(player);\n this.endDialog = createEl('p', {\n className: 'vjs-control-text',\n textContent: this.localize('End of dialog window.')\n });\n this.el().appendChild(this.endDialog);\n this.setDefaults();\n\n // Grab `persistTextTrackSettings` from the player options if not passed in child options\n if (options.persistTextTrackSettings === undefined) {\n this.options_.persistTextTrackSettings = this.options_.playerOptions.persistTextTrackSettings;\n }\n this.bindFunctionsToSelectsAndButtons();\n if (this.options_.persistTextTrackSettings) {\n this.restoreSettings();\n }\n }\n renderModalComponents(player) {\n const textTrackSettingsColors = new TextTrackSettingsColors(player, {\n textTrackComponentid: this.id_,\n selectConfigs,\n fieldSets: [['color', 'textOpacity'], ['backgroundColor', 'backgroundOpacity'], ['windowColor', 'windowOpacity']]\n });\n this.addChild(textTrackSettingsColors);\n const textTrackSettingsFont = new TextTrackSettingsFont(player, {\n textTrackComponentid: this.id_,\n selectConfigs,\n fieldSets: [['fontPercent'], ['edgeStyle'], ['fontFamily']]\n });\n this.addChild(textTrackSettingsFont);\n const trackSettingsControls = new TrackSettingsControls(player);\n this.addChild(trackSettingsControls);\n }\n bindFunctionsToSelectsAndButtons() {\n this.on(this.$('.vjs-done-button'), ['click', 'tap'], () => {\n this.saveSettings();\n this.close();\n });\n this.on(this.$('.vjs-default-button'), ['click', 'tap'], () => {\n this.setDefaults();\n this.updateDisplay();\n });\n each(selectConfigs, config => {\n this.on(this.$(config.selector), 'change', this.updateDisplay);\n });\n }\n dispose() {\n this.endDialog = null;\n super.dispose();\n }\n label() {\n return this.localize('Caption Settings Dialog');\n }\n description() {\n return this.localize('Beginning of dialog window. Escape will cancel and close the window.');\n }\n buildCSSClass() {\n return super.buildCSSClass() + ' vjs-text-track-settings';\n }\n\n /**\n * Gets an object of text track settings (or null).\n *\n * @return {Object}\n * An object with config values parsed from the DOM or localStorage.\n */\n getValues() {\n return reduce(selectConfigs, (accum, config, key) => {\n const value = getSelectedOptionValue(this.$(config.selector), config.parser);\n if (value !== undefined) {\n accum[key] = value;\n }\n return accum;\n }, {});\n }\n\n /**\n * Sets text track settings from an object of values.\n *\n * @param {Object} values\n * An object with config values parsed from the DOM or localStorage.\n */\n setValues(values) {\n each(selectConfigs, (config, key) => {\n setSelectedOption(this.$(config.selector), values[key], config.parser);\n });\n }\n\n /**\n * Sets all `<select>` elements to their default values.\n */\n setDefaults() {\n each(selectConfigs, config => {\n const index = config.hasOwnProperty('default') ? config.default : 0;\n this.$(config.selector).selectedIndex = index;\n });\n }\n\n /**\n * Restore texttrack settings from localStorage\n */\n restoreSettings() {\n let values;\n try {\n values = JSON.parse(window.localStorage.getItem(LOCAL_STORAGE_KEY));\n } catch (err) {\n log.warn(err);\n }\n if (values) {\n this.setValues(values);\n }\n }\n\n /**\n * Save text track settings to localStorage\n */\n saveSettings() {\n if (!this.options_.persistTextTrackSettings) {\n return;\n }\n const values = this.getValues();\n try {\n if (Object.keys(values).length) {\n window.localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(values));\n } else {\n window.localStorage.removeItem(LOCAL_STORAGE_KEY);\n }\n } catch (err) {\n log.warn(err);\n }\n }\n\n /**\n * Update display of text track settings\n */\n updateDisplay() {\n const ttDisplay = this.player_.getChild('textTrackDisplay');\n if (ttDisplay) {\n ttDisplay.updateDisplay();\n }\n }\n\n /**\n * Repopulate dialog with new localizations on languagechange\n */\n handleLanguagechange() {\n this.fill();\n this.renderModalComponents(this.player_);\n this.bindFunctionsToSelectsAndButtons();\n }\n }\n Component.registerComponent('TextTrackSettings', TextTrackSettings);\n\n /**\n * @file resize-manager.js\n */\n\n /**\n * A Resize Manager. It is in charge of triggering `playerresize` on the player in the right conditions.\n *\n * It'll either create an iframe and use a debounced resize handler on it or use the new {@link https://wicg.github.io/ResizeObserver/|ResizeObserver}.\n *\n * If the ResizeObserver is available natively, it will be used. A polyfill can be passed in as an option.\n * If a `playerresize` event is not needed, the ResizeManager component can be removed from the player, see the example below.\n *\n * @example <caption>How to disable the resize manager</caption>\n * const player = videojs('#vid', {\n * resizeManager: false\n * });\n *\n * @see {@link https://wicg.github.io/ResizeObserver/|ResizeObserver specification}\n *\n * @extends Component\n */\n class ResizeManager extends Component {\n /**\n * Create the ResizeManager.\n *\n * @param {Object} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of ResizeManager options.\n *\n * @param {Object} [options.ResizeObserver]\n * A polyfill for ResizeObserver can be passed in here.\n * If this is set to null it will ignore the native ResizeObserver and fall back to the iframe fallback.\n */\n constructor(player, options) {\n let RESIZE_OBSERVER_AVAILABLE = options.ResizeObserver || window.ResizeObserver;\n\n // if `null` was passed, we want to disable the ResizeObserver\n if (options.ResizeObserver === null) {\n RESIZE_OBSERVER_AVAILABLE = false;\n }\n\n // Only create an element when ResizeObserver isn't available\n const options_ = merge({\n createEl: !RESIZE_OBSERVER_AVAILABLE,\n reportTouchActivity: false\n }, options);\n super(player, options_);\n this.ResizeObserver = options.ResizeObserver || window.ResizeObserver;\n this.loadListener_ = null;\n this.resizeObserver_ = null;\n this.debouncedHandler_ = debounce(() => {\n this.resizeHandler();\n }, 100, false, this);\n if (RESIZE_OBSERVER_AVAILABLE) {\n this.resizeObserver_ = new this.ResizeObserver(this.debouncedHandler_);\n this.resizeObserver_.observe(player.el());\n } else {\n this.loadListener_ = () => {\n if (!this.el_ || !this.el_.contentWindow) {\n return;\n }\n const debouncedHandler_ = this.debouncedHandler_;\n let unloadListener_ = this.unloadListener_ = function () {\n off(this, 'resize', debouncedHandler_);\n off(this, 'unload', unloadListener_);\n unloadListener_ = null;\n };\n\n // safari and edge can unload the iframe before resizemanager dispose\n // we have to dispose of event handlers correctly before that happens\n on(this.el_.contentWindow, 'unload', unloadListener_);\n on(this.el_.contentWindow, 'resize', debouncedHandler_);\n };\n this.one('load', this.loadListener_);\n }\n }\n createEl() {\n return super.createEl('iframe', {\n className: 'vjs-resize-manager',\n tabIndex: -1,\n title: this.localize('No content')\n }, {\n 'aria-hidden': 'true'\n });\n }\n\n /**\n * Called when a resize is triggered on the iframe or a resize is observed via the ResizeObserver\n *\n * @fires Player#playerresize\n */\n resizeHandler() {\n /**\n * Called when the player size has changed\n *\n * @event Player#playerresize\n * @type {Event}\n */\n // make sure player is still around to trigger\n // prevents this from causing an error after dispose\n if (!this.player_ || !this.player_.trigger) {\n return;\n }\n this.player_.trigger('playerresize');\n }\n dispose() {\n if (this.debouncedHandler_) {\n this.debouncedHandler_.cancel();\n }\n if (this.resizeObserver_) {\n if (this.player_.el()) {\n this.resizeObserver_.unobserve(this.player_.el());\n }\n this.resizeObserver_.disconnect();\n }\n if (this.loadListener_) {\n this.off('load', this.loadListener_);\n }\n if (this.el_ && this.el_.contentWindow && this.unloadListener_) {\n this.unloadListener_.call(this.el_.contentWindow);\n }\n this.ResizeObserver = null;\n this.resizeObserver = null;\n this.debouncedHandler_ = null;\n this.loadListener_ = null;\n super.dispose();\n }\n }\n Component.registerComponent('ResizeManager', ResizeManager);\n\n /** @import Player from './player' */\n\n const defaults$1 = {\n trackingThreshold: 20,\n liveTolerance: 15\n };\n\n /*\n track when we are at the live edge, and other helpers for live playback */\n\n /**\n * A class for checking live current time and determining when the player\n * is at or behind the live edge.\n */\n class LiveTracker extends Component {\n /**\n * Creates an instance of this class.\n *\n * @param {Player} player\n * The `Player` that this class should be attached to.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {number} [options.trackingThreshold=20]\n * Number of seconds of live window (seekableEnd - seekableStart) that\n * media needs to have before the liveui will be shown.\n *\n * @param {number} [options.liveTolerance=15]\n * Number of seconds behind live that we have to be\n * before we will be considered non-live. Note that this will only\n * be used when playing at the live edge. This allows large seekable end\n * changes to not effect whether we are live or not.\n */\n constructor(player, options) {\n // LiveTracker does not need an element\n const options_ = merge(defaults$1, options, {\n createEl: false\n });\n super(player, options_);\n this.trackLiveHandler_ = () => this.trackLive_();\n this.handlePlay_ = e => this.handlePlay(e);\n this.handleFirstTimeupdate_ = e => this.handleFirstTimeupdate(e);\n this.handleSeeked_ = e => this.handleSeeked(e);\n this.seekToLiveEdge_ = e => this.seekToLiveEdge(e);\n this.reset_();\n this.on(this.player_, 'durationchange', e => this.handleDurationchange(e));\n // we should try to toggle tracking on canplay as native playback engines, like Safari\n // may not have the proper values for things like seekableEnd until then\n this.on(this.player_, 'canplay', () => this.toggleTracking());\n }\n\n /**\n * all the functionality for tracking when seek end changes\n * and for tracking how far past seek end we should be\n */\n trackLive_() {\n const seekable = this.player_.seekable();\n\n // skip undefined seekable\n if (!seekable || !seekable.length) {\n return;\n }\n const newTime = Number(window.performance.now().toFixed(4));\n const deltaTime = this.lastTime_ === -1 ? 0 : (newTime - this.lastTime_) / 1000;\n this.lastTime_ = newTime;\n this.pastSeekEnd_ = this.pastSeekEnd() + deltaTime;\n const liveCurrentTime = this.liveCurrentTime();\n const currentTime = this.player_.currentTime();\n\n // we are behind live if any are true\n // 1. the player is paused\n // 2. the user seeked to a location 2 seconds away from live\n // 3. the difference between live and current time is greater\n // liveTolerance which defaults to 15s\n let isBehind = this.player_.paused() || this.seekedBehindLive_ || Math.abs(liveCurrentTime - currentTime) > this.options_.liveTolerance;\n\n // we cannot be behind if\n // 1. until we have not seen a timeupdate yet\n // 2. liveCurrentTime is Infinity, which happens on Android and Native Safari\n if (!this.timeupdateSeen_ || liveCurrentTime === Infinity) {\n isBehind = false;\n }\n if (isBehind !== this.behindLiveEdge_) {\n this.behindLiveEdge_ = isBehind;\n this.trigger('liveedgechange');\n }\n }\n\n /**\n * handle a durationchange event on the player\n * and start/stop tracking accordingly.\n */\n handleDurationchange() {\n this.toggleTracking();\n }\n\n /**\n * start/stop tracking\n */\n toggleTracking() {\n if (this.player_.duration() === Infinity && this.liveWindow() >= this.options_.trackingThreshold) {\n if (this.player_.options_.liveui) {\n this.player_.addClass('vjs-liveui');\n }\n this.startTracking();\n } else {\n this.player_.removeClass('vjs-liveui');\n this.stopTracking();\n }\n }\n\n /**\n * start tracking live playback\n */\n startTracking() {\n if (this.isTracking()) {\n return;\n }\n\n // If we haven't seen a timeupdate, we need to check whether playback\n // began before this component started tracking. This can happen commonly\n // when using autoplay.\n if (!this.timeupdateSeen_) {\n this.timeupdateSeen_ = this.player_.hasStarted();\n }\n this.trackingInterval_ = this.setInterval(this.trackLiveHandler_, UPDATE_REFRESH_INTERVAL);\n this.trackLive_();\n this.on(this.player_, ['play', 'pause'], this.trackLiveHandler_);\n if (!this.timeupdateSeen_) {\n this.one(this.player_, 'play', this.handlePlay_);\n this.one(this.player_, 'timeupdate', this.handleFirstTimeupdate_);\n } else {\n this.on(this.player_, 'seeked', this.handleSeeked_);\n }\n }\n\n /**\n * handle the first timeupdate on the player if it wasn't already playing\n * when live tracker started tracking.\n */\n handleFirstTimeupdate() {\n this.timeupdateSeen_ = true;\n this.on(this.player_, 'seeked', this.handleSeeked_);\n }\n\n /**\n * Keep track of what time a seek starts, and listen for seeked\n * to find where a seek ends.\n */\n handleSeeked() {\n const timeDiff = Math.abs(this.liveCurrentTime() - this.player_.currentTime());\n this.seekedBehindLive_ = this.nextSeekedFromUser_ && timeDiff > 2;\n this.nextSeekedFromUser_ = false;\n this.trackLive_();\n }\n\n /**\n * handle the first play on the player, and make sure that we seek\n * right to the live edge.\n */\n handlePlay() {\n this.one(this.player_, 'timeupdate', this.seekToLiveEdge_);\n }\n\n /**\n * Stop tracking, and set all internal variables to\n * their initial value.\n */\n reset_() {\n this.lastTime_ = -1;\n this.pastSeekEnd_ = 0;\n this.lastSeekEnd_ = -1;\n this.behindLiveEdge_ = true;\n this.timeupdateSeen_ = false;\n this.seekedBehindLive_ = false;\n this.nextSeekedFromUser_ = false;\n this.clearInterval(this.trackingInterval_);\n this.trackingInterval_ = null;\n this.off(this.player_, ['play', 'pause'], this.trackLiveHandler_);\n this.off(this.player_, 'seeked', this.handleSeeked_);\n this.off(this.player_, 'play', this.handlePlay_);\n this.off(this.player_, 'timeupdate', this.handleFirstTimeupdate_);\n this.off(this.player_, 'timeupdate', this.seekToLiveEdge_);\n }\n\n /**\n * The next seeked event is from the user. Meaning that any seek\n * > 2s behind live will be considered behind live for real and\n * liveTolerance will be ignored.\n */\n nextSeekedFromUser() {\n this.nextSeekedFromUser_ = true;\n }\n\n /**\n * stop tracking live playback\n */\n stopTracking() {\n if (!this.isTracking()) {\n return;\n }\n this.reset_();\n this.trigger('liveedgechange');\n }\n\n /**\n * A helper to get the player seekable end\n * so that we don't have to null check everywhere\n *\n * @return {number}\n * The furthest seekable end or Infinity.\n */\n seekableEnd() {\n const seekable = this.player_.seekable();\n const seekableEnds = [];\n let i = seekable ? seekable.length : 0;\n while (i--) {\n seekableEnds.push(seekable.end(i));\n }\n\n // grab the furthest seekable end after sorting, or if there are none\n // default to Infinity\n return seekableEnds.length ? seekableEnds.sort()[seekableEnds.length - 1] : Infinity;\n }\n\n /**\n * A helper to get the player seekable start\n * so that we don't have to null check everywhere\n *\n * @return {number}\n * The earliest seekable start or 0.\n */\n seekableStart() {\n const seekable = this.player_.seekable();\n const seekableStarts = [];\n let i = seekable ? seekable.length : 0;\n while (i--) {\n seekableStarts.push(seekable.start(i));\n }\n\n // grab the first seekable start after sorting, or if there are none\n // default to 0\n return seekableStarts.length ? seekableStarts.sort()[0] : 0;\n }\n\n /**\n * Get the live time window aka\n * the amount of time between seekable start and\n * live current time.\n *\n * @return {number}\n * The amount of seconds that are seekable in\n * the live video.\n */\n liveWindow() {\n const liveCurrentTime = this.liveCurrentTime();\n\n // if liveCurrenTime is Infinity then we don't have a liveWindow at all\n if (liveCurrentTime === Infinity) {\n return 0;\n }\n return liveCurrentTime - this.seekableStart();\n }\n\n /**\n * Determines if the player is live, only checks if this component\n * is tracking live playback or not\n *\n * @return {boolean}\n * Whether liveTracker is tracking\n */\n isLive() {\n return this.isTracking();\n }\n\n /**\n * Determines if currentTime is at the live edge and won't fall behind\n * on each seekableendchange\n *\n * @return {boolean}\n * Whether playback is at the live edge\n */\n atLiveEdge() {\n return !this.behindLiveEdge();\n }\n\n /**\n * get what we expect the live current time to be\n *\n * @return {number}\n * The expected live current time\n */\n liveCurrentTime() {\n return this.pastSeekEnd() + this.seekableEnd();\n }\n\n /**\n * The number of seconds that have occurred after seekable end\n * changed. This will be reset to 0 once seekable end changes.\n *\n * @return {number}\n * Seconds past the current seekable end\n */\n pastSeekEnd() {\n const seekableEnd = this.seekableEnd();\n if (this.lastSeekEnd_ !== -1 && seekableEnd !== this.lastSeekEnd_) {\n this.pastSeekEnd_ = 0;\n }\n this.lastSeekEnd_ = seekableEnd;\n return this.pastSeekEnd_;\n }\n\n /**\n * If we are currently behind the live edge, aka currentTime will be\n * behind on a seekableendchange\n *\n * @return {boolean}\n * If we are behind the live edge\n */\n behindLiveEdge() {\n return this.behindLiveEdge_;\n }\n\n /**\n * Whether live tracker is currently tracking or not.\n */\n isTracking() {\n return typeof this.trackingInterval_ === 'number';\n }\n\n /**\n * Seek to the live edge if we are behind the live edge\n */\n seekToLiveEdge() {\n this.seekedBehindLive_ = false;\n if (this.atLiveEdge()) {\n return;\n }\n this.nextSeekedFromUser_ = false;\n this.player_.currentTime(this.liveCurrentTime());\n }\n\n /**\n * Dispose of liveTracker\n */\n dispose() {\n this.stopTracking();\n super.dispose();\n }\n }\n Component.registerComponent('LiveTracker', LiveTracker);\n\n /**\n * Displays an element over the player which contains an optional title and\n * description for the current content.\n *\n * Much of the code for this component originated in the now obsolete\n * videojs-dock plugin: https://github.com/brightcove/videojs-dock/\n *\n * @extends Component\n */\n class TitleBar extends Component {\n constructor(player, options) {\n super(player, options);\n this.on('statechanged', e => this.updateDom_());\n this.updateDom_();\n }\n\n /**\n * Create the `TitleBar`'s DOM element\n *\n * @return {Element}\n * The element that was created.\n */\n createEl() {\n this.els = {\n title: createEl('div', {\n className: 'vjs-title-bar-title',\n id: `vjs-title-bar-title-${newGUID()}`\n }),\n description: createEl('div', {\n className: 'vjs-title-bar-description',\n id: `vjs-title-bar-description-${newGUID()}`\n })\n };\n return createEl('div', {\n className: 'vjs-title-bar'\n }, {}, values(this.els));\n }\n\n /**\n * Updates the DOM based on the component's state object.\n */\n updateDom_() {\n const tech = this.player_.tech_;\n const techEl = tech && tech.el_;\n const techAriaAttrs = {\n title: 'aria-labelledby',\n description: 'aria-describedby'\n };\n ['title', 'description'].forEach(k => {\n const value = this.state[k];\n const el = this.els[k];\n const techAriaAttr = techAriaAttrs[k];\n emptyEl(el);\n if (value) {\n textContent(el, value);\n }\n\n // If there is a tech element available, update its ARIA attributes\n // according to whether a title and/or description have been provided.\n if (techEl) {\n techEl.removeAttribute(techAriaAttr);\n if (value) {\n techEl.setAttribute(techAriaAttr, el.id);\n }\n }\n });\n if (this.state.title || this.state.description) {\n this.show();\n } else {\n this.hide();\n }\n }\n\n /**\n * Update the contents of the title bar component with new title and\n * description text.\n *\n * If both title and description are missing, the title bar will be hidden.\n *\n * If either title or description are present, the title bar will be visible.\n *\n * NOTE: Any previously set value will be preserved. To unset a previously\n * set value, you must pass an empty string or null.\n *\n * For example:\n *\n * ```\n * update({title: 'foo', description: 'bar'}) // title: 'foo', description: 'bar'\n * update({description: 'bar2'}) // title: 'foo', description: 'bar2'\n * update({title: ''}) // title: '', description: 'bar2'\n * update({title: 'foo', description: null}) // title: 'foo', description: null\n * ```\n *\n * @param {Object} [options={}]\n * An options object. When empty, the title bar will be hidden.\n *\n * @param {string} [options.title]\n * A title to display in the title bar.\n *\n * @param {string} [options.description]\n * A description to display in the title bar.\n */\n update(options) {\n this.setState(options);\n }\n\n /**\n * Dispose the component.\n */\n dispose() {\n const tech = this.player_.tech_;\n const techEl = tech && tech.el_;\n if (techEl) {\n techEl.removeAttribute('aria-labelledby');\n techEl.removeAttribute('aria-describedby');\n }\n super.dispose();\n this.els = null;\n }\n }\n Component.registerComponent('TitleBar', TitleBar);\n\n /** @import Player from './player' */\n\n /**\n * @typedef {object} TransientButtonOptions\n * @property {string} [controlText] Control text, usually visible for these buttons\n * @property {number} [initialDisplay=4000] Time in ms that button should initially remain visible\n * @property {Array<'top'|'neartop'|'bottom'|'left'|'right'>} [position] Array of position strings to add basic styles for positioning\n * @property {string} [className] Class(es) to add\n * @property {boolean} [takeFocus=false] Whether element sohuld take focus when shown\n * @property {Function} [clickHandler] Function called on button activation\n */\n\n /** @type {TransientButtonOptions} */\n const defaults = {\n initialDisplay: 4000,\n position: [],\n takeFocus: false\n };\n\n /**\n * A floating transient button.\n * It's recommended to insert these buttons _before_ the control bar with the this argument to `addChild`\n * for a logical tab order.\n *\n * @example\n * ```\n * player.addChild(\n * 'TransientButton',\n * options,\n * player.children().indexOf(player.getChild(\"ControlBar\"))\n * )\n * ```\n *\n * @extends Button\n */\n class TransientButton extends Button {\n /**\n * TransientButton constructor\n *\n * @param {Player} player The button's player\n * @param {TransientButtonOptions} options Options for the transient button\n */\n constructor(player, options) {\n options = merge(defaults, options);\n super(player, options);\n this.controlText(options.controlText);\n this.hide();\n\n // When shown, the float button will be visible even if the user is inactive.\n // Clear this if there is any interaction.\n this.on(this.player_, ['useractive', 'userinactive'], e => {\n this.removeClass('force-display');\n });\n }\n\n /**\n * Return CSS class including position classes\n *\n * @return {string} CSS class list\n */\n buildCSSClass() {\n return `vjs-transient-button focus-visible ${this.options_.position.map(c => `vjs-${c}`).join(' ')}`;\n }\n\n /**\n * Create the button element\n *\n * @return {HTMLButtonElement} The button element\n */\n createEl() {\n /** @type HTMLButtonElement */\n const el = createEl('button', {}, {\n type: 'button',\n class: this.buildCSSClass()\n }, createEl('span'));\n this.controlTextEl_ = el.querySelector('span');\n return el;\n }\n\n /**\n * Show the button. The button will remain visible for the `initialDisplay` time, default 4s,\n * and when there is user activity.\n */\n show() {\n super.show();\n this.addClass('force-display');\n if (this.options_.takeFocus) {\n this.el().focus({\n preventScroll: true\n });\n }\n this.forceDisplayTimeout = this.player_.setTimeout(() => {\n this.removeClass('force-display');\n }, this.options_.initialDisplay);\n }\n\n /**\n * Hide the display, even if during the `initialDisplay` time.\n */\n hide() {\n this.removeClass('force-display');\n super.hide();\n }\n\n /**\n * Dispose the component\n */\n dispose() {\n this.player_.clearTimeout(this.forceDisplayTimeout);\n super.dispose();\n }\n }\n Component.registerComponent('TransientButton', TransientButton);\n\n /** @import Html5 from './html5' */\n\n /**\n * This function is used to fire a sourceset when there is something\n * similar to `mediaEl.load()` being called. It will try to find the source via\n * the `src` attribute and then the `<source>` elements. It will then fire `sourceset`\n * with the source that was found or empty string if we cannot know. If it cannot\n * find a source then `sourceset` will not be fired.\n *\n * @param {Html5} tech\n * The tech object that sourceset was setup on\n *\n * @return {boolean}\n * returns false if the sourceset was not fired and true otherwise.\n */\n const sourcesetLoad = tech => {\n const el = tech.el();\n\n // if `el.src` is set, that source will be loaded.\n if (el.hasAttribute('src')) {\n tech.triggerSourceset(el.src);\n return true;\n }\n\n /**\n * Since there isn't a src property on the media element, source elements will be used for\n * implementing the source selection algorithm. This happens asynchronously and\n * for most cases were there is more than one source we cannot tell what source will\n * be loaded, without re-implementing the source selection algorithm. At this time we are not\n * going to do that. There are three special cases that we do handle here though:\n *\n * 1. If there are no sources, do not fire `sourceset`.\n * 2. If there is only one `<source>` with a `src` property/attribute that is our `src`\n * 3. If there is more than one `<source>` but all of them have the same `src` url.\n * That will be our src.\n */\n const sources = tech.$$('source');\n const srcUrls = [];\n let src = '';\n\n // if there are no sources, do not fire sourceset\n if (!sources.length) {\n return false;\n }\n\n // only count valid/non-duplicate source elements\n for (let i = 0; i < sources.length; i++) {\n const url = sources[i].src;\n if (url && srcUrls.indexOf(url) === -1) {\n srcUrls.push(url);\n }\n }\n\n // there were no valid sources\n if (!srcUrls.length) {\n return false;\n }\n\n // there is only one valid source element url\n // use that\n if (srcUrls.length === 1) {\n src = srcUrls[0];\n }\n tech.triggerSourceset(src);\n return true;\n };\n\n /**\n * our implementation of an `innerHTML` descriptor for browsers\n * that do not have one.\n */\n const innerHTMLDescriptorPolyfill = Object.defineProperty({}, 'innerHTML', {\n get() {\n return this.cloneNode(true).innerHTML;\n },\n set(v) {\n // make a dummy node to use innerHTML on\n const dummy = document.createElement(this.nodeName.toLowerCase());\n\n // set innerHTML to the value provided\n dummy.innerHTML = v;\n\n // make a document fragment to hold the nodes from dummy\n const docFrag = document.createDocumentFragment();\n\n // copy all of the nodes created by the innerHTML on dummy\n // to the document fragment\n while (dummy.childNodes.length) {\n docFrag.appendChild(dummy.childNodes[0]);\n }\n\n // remove content\n this.innerText = '';\n\n // now we add all of that html in one by appending the\n // document fragment. This is how innerHTML does it.\n window.Element.prototype.appendChild.call(this, docFrag);\n\n // then return the result that innerHTML's setter would\n return this.innerHTML;\n }\n });\n\n /**\n * Get a property descriptor given a list of priorities and the\n * property to get.\n */\n const getDescriptor = (priority, prop) => {\n let descriptor = {};\n for (let i = 0; i < priority.length; i++) {\n descriptor = Object.getOwnPropertyDescriptor(priority[i], prop);\n if (descriptor && descriptor.set && descriptor.get) {\n break;\n }\n }\n descriptor.enumerable = true;\n descriptor.configurable = true;\n return descriptor;\n };\n const getInnerHTMLDescriptor = tech => getDescriptor([tech.el(), window.HTMLMediaElement.prototype, window.Element.prototype, innerHTMLDescriptorPolyfill], 'innerHTML');\n\n /**\n * Patches browser internal functions so that we can tell synchronously\n * if a `<source>` was appended to the media element. For some reason this\n * causes a `sourceset` if the the media element is ready and has no source.\n * This happens when:\n * - The page has just loaded and the media element does not have a source.\n * - The media element was emptied of all sources, then `load()` was called.\n *\n * It does this by patching the following functions/properties when they are supported:\n *\n * - `append()` - can be used to add a `<source>` element to the media element\n * - `appendChild()` - can be used to add a `<source>` element to the media element\n * - `insertAdjacentHTML()` - can be used to add a `<source>` element to the media element\n * - `innerHTML` - can be used to add a `<source>` element to the media element\n *\n * @param {Html5} tech\n * The tech object that sourceset is being setup on.\n */\n const firstSourceWatch = function (tech) {\n const el = tech.el();\n\n // make sure firstSourceWatch isn't setup twice.\n if (el.resetSourceWatch_) {\n return;\n }\n const old = {};\n const innerDescriptor = getInnerHTMLDescriptor(tech);\n const appendWrapper = appendFn => (...args) => {\n const retval = appendFn.apply(el, args);\n sourcesetLoad(tech);\n return retval;\n };\n ['append', 'appendChild', 'insertAdjacentHTML'].forEach(k => {\n if (!el[k]) {\n return;\n }\n\n // store the old function\n old[k] = el[k];\n\n // call the old function with a sourceset if a source\n // was loaded\n el[k] = appendWrapper(old[k]);\n });\n Object.defineProperty(el, 'innerHTML', merge(innerDescriptor, {\n set: appendWrapper(innerDescriptor.set)\n }));\n el.resetSourceWatch_ = () => {\n el.resetSourceWatch_ = null;\n Object.keys(old).forEach(k => {\n el[k] = old[k];\n });\n Object.defineProperty(el, 'innerHTML', innerDescriptor);\n };\n\n // on the first sourceset, we need to revert our changes\n tech.one('sourceset', el.resetSourceWatch_);\n };\n\n /**\n * our implementation of a `src` descriptor for browsers\n * that do not have one\n */\n const srcDescriptorPolyfill = Object.defineProperty({}, 'src', {\n get() {\n if (this.hasAttribute('src')) {\n return getAbsoluteURL(window.Element.prototype.getAttribute.call(this, 'src'));\n }\n return '';\n },\n set(v) {\n window.Element.prototype.setAttribute.call(this, 'src', v);\n return v;\n }\n });\n const getSrcDescriptor = tech => getDescriptor([tech.el(), window.HTMLMediaElement.prototype, srcDescriptorPolyfill], 'src');\n\n /**\n * setup `sourceset` handling on the `Html5` tech. This function\n * patches the following element properties/functions:\n *\n * - `src` - to determine when `src` is set\n * - `setAttribute()` - to determine when `src` is set\n * - `load()` - this re-triggers the source selection algorithm, and can\n * cause a sourceset.\n *\n * If there is no source when we are adding `sourceset` support or during a `load()`\n * we also patch the functions listed in `firstSourceWatch`.\n *\n * @param {Html5} tech\n * The tech to patch\n */\n const setupSourceset = function (tech) {\n if (!tech.featuresSourceset) {\n return;\n }\n const el = tech.el();\n\n // make sure sourceset isn't setup twice.\n if (el.resetSourceset_) {\n return;\n }\n const srcDescriptor = getSrcDescriptor(tech);\n const oldSetAttribute = el.setAttribute;\n const oldLoad = el.load;\n Object.defineProperty(el, 'src', merge(srcDescriptor, {\n set: v => {\n const retval = srcDescriptor.set.call(el, v);\n\n // we use the getter here to get the actual value set on src\n tech.triggerSourceset(el.src);\n return retval;\n }\n }));\n el.setAttribute = (n, v) => {\n const retval = oldSetAttribute.call(el, n, v);\n if (/src/i.test(n)) {\n tech.triggerSourceset(el.src);\n }\n return retval;\n };\n el.load = () => {\n const retval = oldLoad.call(el);\n\n // if load was called, but there was no source to fire\n // sourceset on. We have to watch for a source append\n // as that can trigger a `sourceset` when the media element\n // has no source\n if (!sourcesetLoad(tech)) {\n tech.triggerSourceset('');\n firstSourceWatch(tech);\n }\n return retval;\n };\n if (el.currentSrc) {\n tech.triggerSourceset(el.currentSrc);\n } else if (!sourcesetLoad(tech)) {\n firstSourceWatch(tech);\n }\n el.resetSourceset_ = () => {\n el.resetSourceset_ = null;\n el.load = oldLoad;\n el.setAttribute = oldSetAttribute;\n Object.defineProperty(el, 'src', srcDescriptor);\n if (el.resetSourceWatch_) {\n el.resetSourceWatch_();\n }\n };\n };\n\n /**\n * @file html5.js\n */\n\n /**\n * HTML5 Media Controller - Wrapper for HTML5 Media API\n *\n * @mixes Tech~SourceHandlerAdditions\n * @extends Tech\n */\n class Html5 extends Tech {\n /**\n * Create an instance of this Tech.\n *\n * @param {Object} [options]\n * The key/value store of player options.\n *\n * @param {Function} [ready]\n * Callback function to call when the `HTML5` Tech is ready.\n */\n constructor(options, ready) {\n super(options, ready);\n const source = options.source;\n let crossoriginTracks = false;\n this.featuresVideoFrameCallback = this.featuresVideoFrameCallback && this.el_.tagName === 'VIDEO';\n\n // Set the source if one is provided\n // 1) Check if the source is new (if not, we want to keep the original so playback isn't interrupted)\n // 2) Check to see if the network state of the tag was failed at init, and if so, reset the source\n // anyway so the error gets fired.\n if (source && (this.el_.currentSrc !== source.src || options.tag && options.tag.initNetworkState_ === 3)) {\n this.setSource(source);\n } else {\n this.handleLateInit_(this.el_);\n }\n\n // setup sourceset after late sourceset/init\n if (options.enableSourceset) {\n this.setupSourcesetHandling_();\n }\n this.isScrubbing_ = false;\n if (this.el_.hasChildNodes()) {\n const nodes = this.el_.childNodes;\n let nodesLength = nodes.length;\n const removeNodes = [];\n while (nodesLength--) {\n const node = nodes[nodesLength];\n const nodeName = node.nodeName.toLowerCase();\n if (nodeName === 'track') {\n if (!this.featuresNativeTextTracks) {\n // Empty video tag tracks so the built-in player doesn't use them also.\n // This may not be fast enough to stop HTML5 browsers from reading the tags\n // so we'll need to turn off any default tracks if we're manually doing\n // captions and subtitles. videoElement.textTracks\n removeNodes.push(node);\n } else {\n // store HTMLTrackElement and TextTrack to remote list\n this.remoteTextTrackEls().addTrackElement_(node);\n this.remoteTextTracks().addTrack(node.track);\n this.textTracks().addTrack(node.track);\n if (!crossoriginTracks && !this.el_.hasAttribute('crossorigin') && isCrossOrigin(node.src)) {\n crossoriginTracks = true;\n }\n }\n }\n }\n for (let i = 0; i < removeNodes.length; i++) {\n this.el_.removeChild(removeNodes[i]);\n }\n }\n this.proxyNativeTracks_();\n if (this.featuresNativeTextTracks && crossoriginTracks) {\n log.warn('Text Tracks are being loaded from another origin but the crossorigin attribute isn\\'t used.\\n' + 'This may prevent text tracks from loading.');\n }\n\n // prevent iOS Safari from disabling metadata text tracks during native playback\n this.restoreMetadataTracksInIOSNativePlayer_();\n\n // Determine if native controls should be used\n // Our goal should be to get the custom controls on mobile solid everywhere\n // so we can remove this all together. Right now this will block custom\n // controls on touch enabled laptops like the Chrome Pixel\n if ((TOUCH_ENABLED || IS_IPHONE) && options.nativeControlsForTouch === true) {\n this.setControls(true);\n }\n\n // on iOS, we want to proxy `webkitbeginfullscreen` and `webkitendfullscreen`\n // into a `fullscreenchange` event\n this.proxyWebkitFullscreen_();\n this.triggerReady();\n }\n\n /**\n * Dispose of `HTML5` media element and remove all tracks.\n */\n dispose() {\n if (this.el_ && this.el_.resetSourceset_) {\n this.el_.resetSourceset_();\n }\n Html5.disposeMediaElement(this.el_);\n this.options_ = null;\n\n // tech will handle clearing of the emulated track list\n super.dispose();\n }\n\n /**\n * Modify the media element so that we can detect when\n * the source is changed. Fires `sourceset` just after the source has changed\n */\n setupSourcesetHandling_() {\n setupSourceset(this);\n }\n\n /**\n * When a captions track is enabled in the iOS Safari native player, all other\n * tracks are disabled (including metadata tracks), which nulls all of their\n * associated cue points. This will restore metadata tracks to their pre-fullscreen\n * state in those cases so that cue points are not needlessly lost.\n *\n * @private\n */\n restoreMetadataTracksInIOSNativePlayer_() {\n const textTracks = this.textTracks();\n let metadataTracksPreFullscreenState;\n\n // captures a snapshot of every metadata track's current state\n const takeMetadataTrackSnapshot = () => {\n metadataTracksPreFullscreenState = [];\n for (let i = 0; i < textTracks.length; i++) {\n const track = textTracks[i];\n if (track.kind === 'metadata') {\n metadataTracksPreFullscreenState.push({\n track,\n storedMode: track.mode\n });\n }\n }\n };\n\n // snapshot each metadata track's initial state, and update the snapshot\n // each time there is a track 'change' event\n takeMetadataTrackSnapshot();\n textTracks.addEventListener('change', takeMetadataTrackSnapshot);\n this.on('dispose', () => textTracks.removeEventListener('change', takeMetadataTrackSnapshot));\n const restoreTrackMode = () => {\n for (let i = 0; i < metadataTracksPreFullscreenState.length; i++) {\n const storedTrack = metadataTracksPreFullscreenState[i];\n if (storedTrack.track.mode === 'disabled' && storedTrack.track.mode !== storedTrack.storedMode) {\n storedTrack.track.mode = storedTrack.storedMode;\n }\n }\n // we only want this handler to be executed on the first 'change' event\n textTracks.removeEventListener('change', restoreTrackMode);\n };\n\n // when we enter fullscreen playback, stop updating the snapshot and\n // restore all track modes to their pre-fullscreen state\n this.on('webkitbeginfullscreen', () => {\n textTracks.removeEventListener('change', takeMetadataTrackSnapshot);\n\n // remove the listener before adding it just in case it wasn't previously removed\n textTracks.removeEventListener('change', restoreTrackMode);\n textTracks.addEventListener('change', restoreTrackMode);\n });\n\n // start updating the snapshot again after leaving fullscreen\n this.on('webkitendfullscreen', () => {\n // remove the listener before adding it just in case it wasn't previously removed\n textTracks.removeEventListener('change', takeMetadataTrackSnapshot);\n textTracks.addEventListener('change', takeMetadataTrackSnapshot);\n\n // remove the restoreTrackMode handler in case it wasn't triggered during fullscreen playback\n textTracks.removeEventListener('change', restoreTrackMode);\n });\n }\n\n /**\n * Attempt to force override of tracks for the given type\n *\n * @param {string} type - Track type to override, possible values include 'Audio',\n * 'Video', and 'Text'.\n * @param {boolean} override - If set to true native audio/video will be overridden,\n * otherwise native audio/video will potentially be used.\n * @private\n */\n overrideNative_(type, override) {\n // If there is no behavioral change don't add/remove listeners\n if (override !== this[`featuresNative${type}Tracks`]) {\n return;\n }\n const lowerCaseType = type.toLowerCase();\n if (this[`${lowerCaseType}TracksListeners_`]) {\n Object.keys(this[`${lowerCaseType}TracksListeners_`]).forEach(eventName => {\n const elTracks = this.el()[`${lowerCaseType}Tracks`];\n elTracks.removeEventListener(eventName, this[`${lowerCaseType}TracksListeners_`][eventName]);\n });\n }\n this[`featuresNative${type}Tracks`] = !override;\n this[`${lowerCaseType}TracksListeners_`] = null;\n this.proxyNativeTracksForType_(lowerCaseType);\n }\n\n /**\n * Attempt to force override of native audio tracks.\n *\n * @param {boolean} override - If set to true native audio will be overridden,\n * otherwise native audio will potentially be used.\n */\n overrideNativeAudioTracks(override) {\n this.overrideNative_('Audio', override);\n }\n\n /**\n * Attempt to force override of native video tracks.\n *\n * @param {boolean} override - If set to true native video will be overridden,\n * otherwise native video will potentially be used.\n */\n overrideNativeVideoTracks(override) {\n this.overrideNative_('Video', override);\n }\n\n /**\n * Proxy native track list events for the given type to our track\n * lists if the browser we are playing in supports that type of track list.\n *\n * @param {string} name - Track type; values include 'audio', 'video', and 'text'\n * @private\n */\n proxyNativeTracksForType_(name) {\n const props = NORMAL[name];\n const elTracks = this.el()[props.getterName];\n const techTracks = this[props.getterName]();\n if (!this[`featuresNative${props.capitalName}Tracks`] || !elTracks || !elTracks.addEventListener) {\n return;\n }\n const listeners = {\n change: e => {\n const event = {\n type: 'change',\n target: techTracks,\n currentTarget: techTracks,\n srcElement: techTracks\n };\n techTracks.trigger(event);\n\n // if we are a text track change event, we should also notify the\n // remote text track list. This can potentially cause a false positive\n // if we were to get a change event on a non-remote track and\n // we triggered the event on the remote text track list which doesn't\n // contain that track. However, best practices mean looping through the\n // list of tracks and searching for the appropriate mode value, so,\n // this shouldn't pose an issue\n if (name === 'text') {\n this[REMOTE.remoteText.getterName]().trigger(event);\n }\n },\n addtrack(e) {\n techTracks.addTrack(e.track);\n },\n removetrack(e) {\n techTracks.removeTrack(e.track);\n }\n };\n const removeOldTracks = function () {\n const removeTracks = [];\n for (let i = 0; i < techTracks.length; i++) {\n let found = false;\n for (let j = 0; j < elTracks.length; j++) {\n if (elTracks[j] === techTracks[i]) {\n found = true;\n break;\n }\n }\n if (!found) {\n removeTracks.push(techTracks[i]);\n }\n }\n while (removeTracks.length) {\n techTracks.removeTrack(removeTracks.shift());\n }\n };\n this[props.getterName + 'Listeners_'] = listeners;\n Object.keys(listeners).forEach(eventName => {\n const listener = listeners[eventName];\n elTracks.addEventListener(eventName, listener);\n this.on('dispose', e => elTracks.removeEventListener(eventName, listener));\n });\n\n // Remove (native) tracks that are not used anymore\n this.on('loadstart', removeOldTracks);\n this.on('dispose', e => this.off('loadstart', removeOldTracks));\n }\n\n /**\n * Proxy all native track list events to our track lists if the browser we are playing\n * in supports that type of track list.\n *\n * @private\n */\n proxyNativeTracks_() {\n NORMAL.names.forEach(name => {\n this.proxyNativeTracksForType_(name);\n });\n }\n\n /**\n * Create the `Html5` Tech's DOM element.\n *\n * @return {Element}\n * The element that gets created.\n */\n createEl() {\n let el = this.options_.tag;\n\n // Check if this browser supports moving the element into the box.\n // On the iPhone video will break if you move the element,\n // So we have to create a brand new element.\n // If we ingested the player div, we do not need to move the media element.\n if (!el || !(this.options_.playerElIngest || this.movingMediaElementInDOM)) {\n // If the original tag is still there, clone and remove it.\n if (el) {\n const clone = el.cloneNode(true);\n if (el.parentNode) {\n el.parentNode.insertBefore(clone, el);\n }\n Html5.disposeMediaElement(el);\n el = clone;\n } else {\n el = document.createElement('video');\n\n // determine if native controls should be used\n const tagAttributes = this.options_.tag && getAttributes(this.options_.tag);\n const attributes = merge({}, tagAttributes);\n if (!TOUCH_ENABLED || this.options_.nativeControlsForTouch !== true) {\n delete attributes.controls;\n }\n setAttributes(el, Object.assign(attributes, {\n id: this.options_.techId,\n class: 'vjs-tech'\n }));\n }\n el.playerId = this.options_.playerId;\n }\n if (typeof this.options_.preload !== 'undefined') {\n setAttribute(el, 'preload', this.options_.preload);\n }\n if (this.options_.disablePictureInPicture !== undefined) {\n el.disablePictureInPicture = this.options_.disablePictureInPicture;\n }\n\n // Update specific tag settings, in case they were overridden\n // `autoplay` has to be *last* so that `muted` and `playsinline` are present\n // when iOS/Safari or other browsers attempt to autoplay.\n const settingsAttrs = ['loop', 'muted', 'playsinline', 'autoplay'];\n for (let i = 0; i < settingsAttrs.length; i++) {\n const attr = settingsAttrs[i];\n const value = this.options_[attr];\n if (typeof value !== 'undefined') {\n if (value) {\n setAttribute(el, attr, attr);\n } else {\n removeAttribute(el, attr);\n }\n el[attr] = value;\n }\n }\n return el;\n }\n\n /**\n * This will be triggered if the loadstart event has already fired, before videojs was\n * ready. Two known examples of when this can happen are:\n * 1. If we're loading the playback object after it has started loading\n * 2. The media is already playing the (often with autoplay on) then\n *\n * This function will fire another loadstart so that videojs can catchup.\n *\n * @fires Tech#loadstart\n *\n * @return {undefined}\n * returns nothing.\n */\n handleLateInit_(el) {\n if (el.networkState === 0 || el.networkState === 3) {\n // The video element hasn't started loading the source yet\n // or didn't find a source\n return;\n }\n if (el.readyState === 0) {\n // NetworkState is set synchronously BUT loadstart is fired at the\n // end of the current stack, usually before setInterval(fn, 0).\n // So at this point we know loadstart may have already fired or is\n // about to fire, and either way the player hasn't seen it yet.\n // We don't want to fire loadstart prematurely here and cause a\n // double loadstart so we'll wait and see if it happens between now\n // and the next loop, and fire it if not.\n // HOWEVER, we also want to make sure it fires before loadedmetadata\n // which could also happen between now and the next loop, so we'll\n // watch for that also.\n let loadstartFired = false;\n const setLoadstartFired = function () {\n loadstartFired = true;\n };\n this.on('loadstart', setLoadstartFired);\n const triggerLoadstart = function () {\n // We did miss the original loadstart. Make sure the player\n // sees loadstart before loadedmetadata\n if (!loadstartFired) {\n this.trigger('loadstart');\n }\n };\n this.on('loadedmetadata', triggerLoadstart);\n this.ready(function () {\n this.off('loadstart', setLoadstartFired);\n this.off('loadedmetadata', triggerLoadstart);\n if (!loadstartFired) {\n // We did miss the original native loadstart. Fire it now.\n this.trigger('loadstart');\n }\n });\n return;\n }\n\n // From here on we know that loadstart already fired and we missed it.\n // The other readyState events aren't as much of a problem if we double\n // them, so not going to go to as much trouble as loadstart to prevent\n // that unless we find reason to.\n const eventsToTrigger = ['loadstart'];\n\n // loadedmetadata: newly equal to HAVE_METADATA (1) or greater\n eventsToTrigger.push('loadedmetadata');\n\n // loadeddata: newly increased to HAVE_CURRENT_DATA (2) or greater\n if (el.readyState >= 2) {\n eventsToTrigger.push('loadeddata');\n }\n\n // canplay: newly increased to HAVE_FUTURE_DATA (3) or greater\n if (el.readyState >= 3) {\n eventsToTrigger.push('canplay');\n }\n\n // canplaythrough: newly equal to HAVE_ENOUGH_DATA (4)\n if (el.readyState >= 4) {\n eventsToTrigger.push('canplaythrough');\n }\n\n // We still need to give the player time to add event listeners\n this.ready(function () {\n eventsToTrigger.forEach(function (type) {\n this.trigger(type);\n }, this);\n });\n }\n\n /**\n * Set whether we are scrubbing or not.\n * This is used to decide whether we should use `fastSeek` or not.\n * `fastSeek` is used to provide trick play on Safari browsers.\n *\n * @param {boolean} isScrubbing\n * - true for we are currently scrubbing\n * - false for we are no longer scrubbing\n */\n setScrubbing(isScrubbing) {\n this.isScrubbing_ = isScrubbing;\n }\n\n /**\n * Get whether we are scrubbing or not.\n *\n * @return {boolean} isScrubbing\n * - true for we are currently scrubbing\n * - false for we are no longer scrubbing\n */\n scrubbing() {\n return this.isScrubbing_;\n }\n\n /**\n * Set current time for the `HTML5` tech.\n *\n * @param {number} seconds\n * Set the current time of the media to this.\n */\n setCurrentTime(seconds) {\n try {\n if (this.isScrubbing_ && this.el_.fastSeek && IS_ANY_SAFARI) {\n this.el_.fastSeek(seconds);\n } else {\n this.el_.currentTime = seconds;\n }\n } catch (e) {\n log(e, 'Video is not ready. (Video.js)');\n // this.warning(VideoJS.warnings.videoNotReady);\n }\n }\n\n /**\n * Get the current duration of the HTML5 media element.\n *\n * @return {number}\n * The duration of the media or 0 if there is no duration.\n */\n duration() {\n // Android Chrome will report duration as Infinity for VOD HLS until after\n // playback has started, which triggers the live display erroneously.\n // Return NaN if playback has not started and trigger a durationupdate once\n // the duration can be reliably known.\n if (this.el_.duration === Infinity && IS_ANDROID && IS_CHROME && this.el_.currentTime === 0) {\n // Wait for the first `timeupdate` with currentTime > 0 - there may be\n // several with 0\n const checkProgress = () => {\n if (this.el_.currentTime > 0) {\n // Trigger durationchange for genuinely live video\n if (this.el_.duration === Infinity) {\n this.trigger('durationchange');\n }\n this.off('timeupdate', checkProgress);\n }\n };\n this.on('timeupdate', checkProgress);\n return NaN;\n }\n return this.el_.duration || NaN;\n }\n\n /**\n * Get the current width of the HTML5 media element.\n *\n * @return {number}\n * The width of the HTML5 media element.\n */\n width() {\n return this.el_.offsetWidth;\n }\n\n /**\n * Get the current height of the HTML5 media element.\n *\n * @return {number}\n * The height of the HTML5 media element.\n */\n height() {\n return this.el_.offsetHeight;\n }\n\n /**\n * Proxy iOS `webkitbeginfullscreen` and `webkitendfullscreen` into\n * `fullscreenchange` event.\n *\n * @private\n * @fires fullscreenchange\n * @listens webkitendfullscreen\n * @listens webkitbeginfullscreen\n * @listens webkitbeginfullscreen\n */\n proxyWebkitFullscreen_() {\n if (!('webkitDisplayingFullscreen' in this.el_)) {\n return;\n }\n const endFn = function () {\n this.trigger('fullscreenchange', {\n isFullscreen: false\n });\n // Safari will sometimes set controls on the videoelement when existing fullscreen.\n if (this.el_.controls && !this.options_.nativeControlsForTouch && this.controls()) {\n this.el_.controls = false;\n }\n };\n const beginFn = function () {\n if ('webkitPresentationMode' in this.el_ && this.el_.webkitPresentationMode !== 'picture-in-picture') {\n this.one('webkitendfullscreen', endFn);\n this.trigger('fullscreenchange', {\n isFullscreen: true,\n // set a flag in case another tech triggers fullscreenchange\n nativeIOSFullscreen: true\n });\n }\n };\n this.on('webkitbeginfullscreen', beginFn);\n this.on('dispose', () => {\n this.off('webkitbeginfullscreen', beginFn);\n this.off('webkitendfullscreen', endFn);\n });\n }\n\n /**\n * Check if fullscreen is supported on the video el.\n *\n * @return {boolean}\n * - True if fullscreen is supported.\n * - False if fullscreen is not supported.\n */\n supportsFullScreen() {\n return typeof this.el_.webkitEnterFullScreen === 'function';\n }\n\n /**\n * Request that the `HTML5` Tech enter fullscreen.\n */\n enterFullScreen() {\n const video = this.el_;\n if (video.paused && video.networkState <= video.HAVE_METADATA) {\n // attempt to prime the video element for programmatic access\n // this isn't necessary on the desktop but shouldn't hurt\n silencePromise(this.el_.play());\n\n // playing and pausing synchronously during the transition to fullscreen\n // can get iOS ~6.1 devices into a play/pause loop\n this.setTimeout(function () {\n video.pause();\n try {\n video.webkitEnterFullScreen();\n } catch (e) {\n this.trigger('fullscreenerror', e);\n }\n }, 0);\n } else {\n try {\n video.webkitEnterFullScreen();\n } catch (e) {\n this.trigger('fullscreenerror', e);\n }\n }\n }\n\n /**\n * Request that the `HTML5` Tech exit fullscreen.\n */\n exitFullScreen() {\n if (!this.el_.webkitDisplayingFullscreen) {\n this.trigger('fullscreenerror', new Error('The video is not fullscreen'));\n return;\n }\n this.el_.webkitExitFullScreen();\n }\n\n /**\n * Create a floating video window always on top of other windows so that users may\n * continue consuming media while they interact with other content sites, or\n * applications on their device.\n *\n * @see [Spec]{@link https://wicg.github.io/picture-in-picture}\n *\n * @return {Promise}\n * A promise with a Picture-in-Picture window.\n */\n requestPictureInPicture() {\n return this.el_.requestPictureInPicture();\n }\n\n /**\n * Native requestVideoFrameCallback if supported by browser/tech, or fallback\n * Don't use rVCF on Safari when DRM is playing, as it doesn't fire\n * Needs to be checked later than the constructor\n * This will be a false positive for clear sources loaded after a Fairplay source\n *\n * @param {function} cb function to call\n * @return {number} id of request\n */\n requestVideoFrameCallback(cb) {\n if (this.featuresVideoFrameCallback && !this.el_.webkitKeys) {\n return this.el_.requestVideoFrameCallback(cb);\n }\n return super.requestVideoFrameCallback(cb);\n }\n\n /**\n * Native or fallback requestVideoFrameCallback\n *\n * @param {number} id request id to cancel\n */\n cancelVideoFrameCallback(id) {\n if (this.featuresVideoFrameCallback && !this.el_.webkitKeys) {\n this.el_.cancelVideoFrameCallback(id);\n } else {\n super.cancelVideoFrameCallback(id);\n }\n }\n\n /**\n * A getter/setter for the `Html5` Tech's source object.\n * > Note: Please use {@link Html5#setSource}\n *\n * @param {Tech~SourceObject} [src]\n * The source object you want to set on the `HTML5` techs element.\n *\n * @return {Tech~SourceObject|undefined}\n * - The current source object when a source is not passed in.\n * - undefined when setting\n *\n * @deprecated Since version 5.\n */\n src(src) {\n if (src === undefined) {\n return this.el_.src;\n }\n\n // Setting src through `src` instead of `setSrc` will be deprecated\n this.setSrc(src);\n }\n\n /**\n * Add a <source> element to the <video> element.\n *\n * @param {string} srcUrl\n * The URL of the video source.\n *\n * @param {string} [mimeType]\n * The MIME type of the video source. Optional but recommended.\n *\n * @return {boolean}\n * Returns true if the source element was successfully added, false otherwise.\n */\n addSourceElement(srcUrl, mimeType) {\n if (!srcUrl) {\n log.error('Invalid source URL.');\n return false;\n }\n const sourceAttributes = {\n src: srcUrl\n };\n if (mimeType) {\n sourceAttributes.type = mimeType;\n }\n const sourceElement = createEl('source', {}, sourceAttributes);\n this.el_.appendChild(sourceElement);\n return true;\n }\n\n /**\n * Remove a <source> element from the <video> element by its URL.\n *\n * @param {string} srcUrl\n * The URL of the source to remove.\n *\n * @return {boolean}\n * Returns true if the source element was successfully removed, false otherwise.\n */\n removeSourceElement(srcUrl) {\n if (!srcUrl) {\n log.error('Source URL is required to remove the source element.');\n return false;\n }\n const sourceElements = this.el_.querySelectorAll('source');\n for (const sourceElement of sourceElements) {\n if (sourceElement.src === srcUrl) {\n this.el_.removeChild(sourceElement);\n return true;\n }\n }\n log.warn(`No matching source element found with src: ${srcUrl}`);\n return false;\n }\n\n /**\n * Reset the tech by removing all sources and then calling\n * {@link Html5.resetMediaElement}.\n */\n reset() {\n Html5.resetMediaElement(this.el_);\n }\n\n /**\n * Get the current source on the `HTML5` Tech. Falls back to returning the source from\n * the HTML5 media element.\n *\n * @return {Tech~SourceObject}\n * The current source object from the HTML5 tech. With a fallback to the\n * elements source.\n */\n currentSrc() {\n if (this.currentSource_) {\n return this.currentSource_.src;\n }\n return this.el_.currentSrc;\n }\n\n /**\n * Set controls attribute for the HTML5 media Element.\n *\n * @param {string} val\n * Value to set the controls attribute to\n */\n setControls(val) {\n this.el_.controls = !!val;\n }\n\n /**\n * Create and returns a remote {@link TextTrack} object.\n *\n * @param {string} kind\n * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)\n *\n * @param {string} [label]\n * Label to identify the text track\n *\n * @param {string} [language]\n * Two letter language abbreviation\n *\n * @return {TextTrack}\n * The TextTrack that gets created.\n */\n addTextTrack(kind, label, language) {\n if (!this.featuresNativeTextTracks) {\n return super.addTextTrack(kind, label, language);\n }\n return this.el_.addTextTrack(kind, label, language);\n }\n\n /**\n * Creates either native TextTrack or an emulated TextTrack depending\n * on the value of `featuresNativeTextTracks`\n *\n * @param {Object} options\n * The object should contain the options to initialize the TextTrack with.\n *\n * @param {string} [options.kind]\n * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata).\n *\n * @param {string} [options.label]\n * Label to identify the text track\n *\n * @param {string} [options.language]\n * Two letter language abbreviation.\n *\n * @param {boolean} [options.default]\n * Default this track to on.\n *\n * @param {string} [options.id]\n * The internal id to assign this track.\n *\n * @param {string} [options.src]\n * A source url for the track.\n *\n * @return {HTMLTrackElement}\n * The track element that gets created.\n */\n createRemoteTextTrack(options) {\n if (!this.featuresNativeTextTracks) {\n return super.createRemoteTextTrack(options);\n }\n const htmlTrackElement = document.createElement('track');\n if (options.kind) {\n htmlTrackElement.kind = options.kind;\n }\n if (options.label) {\n htmlTrackElement.label = options.label;\n }\n if (options.language || options.srclang) {\n htmlTrackElement.srclang = options.language || options.srclang;\n }\n if (options.default) {\n htmlTrackElement.default = options.default;\n }\n if (options.id) {\n htmlTrackElement.id = options.id;\n }\n if (options.src) {\n htmlTrackElement.src = options.src;\n }\n return htmlTrackElement;\n }\n\n /**\n * Creates a remote text track object and returns an html track element.\n *\n * @param {Object} options The object should contain values for\n * kind, language, label, and src (location of the WebVTT file)\n * @param {boolean} [manualCleanup=false] if set to true, the TextTrack\n * will not be removed from the TextTrackList and HtmlTrackElementList\n * after a source change\n * @return {HTMLTrackElement} An Html Track Element.\n * This can be an emulated {@link HTMLTrackElement} or a native one.\n *\n */\n addRemoteTextTrack(options, manualCleanup) {\n const htmlTrackElement = super.addRemoteTextTrack(options, manualCleanup);\n if (this.featuresNativeTextTracks) {\n this.el().appendChild(htmlTrackElement);\n }\n return htmlTrackElement;\n }\n\n /**\n * Remove remote `TextTrack` from `TextTrackList` object\n *\n * @param {TextTrack} track\n * `TextTrack` object to remove\n */\n removeRemoteTextTrack(track) {\n super.removeRemoteTextTrack(track);\n if (this.featuresNativeTextTracks) {\n const tracks = this.$$('track');\n let i = tracks.length;\n while (i--) {\n if (track === tracks[i] || track === tracks[i].track) {\n this.el().removeChild(tracks[i]);\n }\n }\n }\n }\n\n /**\n * Gets available media playback quality metrics as specified by the W3C's Media\n * Playback Quality API.\n *\n * @see [Spec]{@link https://wicg.github.io/media-playback-quality}\n *\n * @return {Object}\n * An object with supported media playback quality metrics\n */\n getVideoPlaybackQuality() {\n if (typeof this.el().getVideoPlaybackQuality === 'function') {\n return this.el().getVideoPlaybackQuality();\n }\n const videoPlaybackQuality = {};\n if (typeof this.el().webkitDroppedFrameCount !== 'undefined' && typeof this.el().webkitDecodedFrameCount !== 'undefined') {\n videoPlaybackQuality.droppedVideoFrames = this.el().webkitDroppedFrameCount;\n videoPlaybackQuality.totalVideoFrames = this.el().webkitDecodedFrameCount;\n }\n if (window.performance) {\n videoPlaybackQuality.creationTime = window.performance.now();\n }\n return videoPlaybackQuality;\n }\n }\n\n /* HTML5 Support Testing ---------------------------------------------------- */\n\n /**\n * Element for testing browser HTML5 media capabilities\n *\n * @type {Element}\n * @constant\n * @private\n */\n defineLazyProperty(Html5, 'TEST_VID', function () {\n if (!isReal()) {\n return;\n }\n const video = document.createElement('video');\n const track = document.createElement('track');\n track.kind = 'captions';\n track.srclang = 'en';\n track.label = 'English';\n video.appendChild(track);\n return video;\n });\n\n /**\n * Check if HTML5 media is supported by this browser/device.\n *\n * @return {boolean}\n * - True if HTML5 media is supported.\n * - False if HTML5 media is not supported.\n */\n Html5.isSupported = function () {\n // IE with no Media Player is a LIAR! (#984)\n try {\n Html5.TEST_VID.volume = 0.5;\n } catch (e) {\n return false;\n }\n return !!(Html5.TEST_VID && Html5.TEST_VID.canPlayType);\n };\n\n /**\n * Check if the tech can support the given type\n *\n * @param {string} type\n * The mimetype to check\n * @return {string} 'probably', 'maybe', or '' (empty string)\n */\n Html5.canPlayType = function (type) {\n return Html5.TEST_VID.canPlayType(type);\n };\n\n /**\n * Check if the tech can support the given source\n *\n * @param {Object} srcObj\n * The source object\n * @param {Object} options\n * The options passed to the tech\n * @return {string} 'probably', 'maybe', or '' (empty string)\n */\n Html5.canPlaySource = function (srcObj, options) {\n return Html5.canPlayType(srcObj.type);\n };\n\n /**\n * Check if the volume can be changed in this browser/device.\n * Volume cannot be changed in a lot of mobile devices.\n * Specifically, it can't be changed from 1 on iOS.\n *\n * @return {boolean}\n * - True if volume can be controlled\n * - False otherwise\n */\n Html5.canControlVolume = function () {\n // IE will error if Windows Media Player not installed #3315\n try {\n const volume = Html5.TEST_VID.volume;\n Html5.TEST_VID.volume = volume / 2 + 0.1;\n const canControl = volume !== Html5.TEST_VID.volume;\n\n // With the introduction of iOS 15, there are cases where the volume is read as\n // changed but reverts back to its original state at the start of the next tick.\n // To determine whether volume can be controlled on iOS,\n // a timeout is set and the volume is checked asynchronously.\n // Since `features` doesn't currently work asynchronously, the value is manually set.\n if (canControl && IS_IOS) {\n window.setTimeout(() => {\n if (Html5 && Html5.prototype) {\n Html5.prototype.featuresVolumeControl = volume !== Html5.TEST_VID.volume;\n }\n });\n\n // default iOS to false, which will be updated in the timeout above.\n return false;\n }\n return canControl;\n } catch (e) {\n return false;\n }\n };\n\n /**\n * Check if the volume can be muted in this browser/device.\n * Some devices, e.g. iOS, don't allow changing volume\n * but permits muting/unmuting.\n *\n * @return {boolean}\n * - True if volume can be muted\n * - False otherwise\n */\n Html5.canMuteVolume = function () {\n try {\n const muted = Html5.TEST_VID.muted;\n\n // in some versions of iOS muted property doesn't always\n // work, so we want to set both property and attribute\n Html5.TEST_VID.muted = !muted;\n if (Html5.TEST_VID.muted) {\n setAttribute(Html5.TEST_VID, 'muted', 'muted');\n } else {\n removeAttribute(Html5.TEST_VID, 'muted', 'muted');\n }\n return muted !== Html5.TEST_VID.muted;\n } catch (e) {\n return false;\n }\n };\n\n /**\n * Check if the playback rate can be changed in this browser/device.\n *\n * @return {boolean}\n * - True if playback rate can be controlled\n * - False otherwise\n */\n Html5.canControlPlaybackRate = function () {\n // Playback rate API is implemented in Android Chrome, but doesn't do anything\n // https://github.com/videojs/video.js/issues/3180\n if (IS_ANDROID && IS_CHROME && CHROME_VERSION < 58) {\n return false;\n }\n // IE will error if Windows Media Player not installed #3315\n try {\n const playbackRate = Html5.TEST_VID.playbackRate;\n Html5.TEST_VID.playbackRate = playbackRate / 2 + 0.1;\n return playbackRate !== Html5.TEST_VID.playbackRate;\n } catch (e) {\n return false;\n }\n };\n\n /**\n * Check if we can override a video/audio elements attributes, with\n * Object.defineProperty.\n *\n * @return {boolean}\n * - True if builtin attributes can be overridden\n * - False otherwise\n */\n Html5.canOverrideAttributes = function () {\n // if we cannot overwrite the src/innerHTML property, there is no support\n // iOS 7 safari for instance cannot do this.\n try {\n const noop = () => {};\n Object.defineProperty(document.createElement('video'), 'src', {\n get: noop,\n set: noop\n });\n Object.defineProperty(document.createElement('audio'), 'src', {\n get: noop,\n set: noop\n });\n Object.defineProperty(document.createElement('video'), 'innerHTML', {\n get: noop,\n set: noop\n });\n Object.defineProperty(document.createElement('audio'), 'innerHTML', {\n get: noop,\n set: noop\n });\n } catch (e) {\n return false;\n }\n return true;\n };\n\n /**\n * Check to see if native `TextTrack`s are supported by this browser/device.\n *\n * @return {boolean}\n * - True if native `TextTrack`s are supported.\n * - False otherwise\n */\n Html5.supportsNativeTextTracks = function () {\n return IS_ANY_SAFARI || IS_IOS && IS_CHROME;\n };\n\n /**\n * Check to see if native `VideoTrack`s are supported by this browser/device\n *\n * @return {boolean}\n * - True if native `VideoTrack`s are supported.\n * - False otherwise\n */\n Html5.supportsNativeVideoTracks = function () {\n return !!(Html5.TEST_VID && Html5.TEST_VID.videoTracks);\n };\n\n /**\n * Check to see if native `AudioTrack`s are supported by this browser/device\n *\n * @return {boolean}\n * - True if native `AudioTrack`s are supported.\n * - False otherwise\n */\n Html5.supportsNativeAudioTracks = function () {\n return !!(Html5.TEST_VID && Html5.TEST_VID.audioTracks);\n };\n\n /**\n * An array of events available on the Html5 tech.\n *\n * @private\n * @type {Array}\n */\n Html5.Events = ['loadstart', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'waiting', 'seeking', 'seeked', 'ended', 'durationchange', 'timeupdate', 'progress', 'play', 'pause', 'ratechange', 'resize', 'volumechange'];\n\n /**\n * Boolean indicating whether the `Tech` supports volume control.\n *\n * @type {boolean}\n * @default {@link Html5.canControlVolume}\n */\n /**\n * Boolean indicating whether the `Tech` supports muting volume.\n *\n * @type {boolean}\n * @default {@link Html5.canMuteVolume}\n */\n\n /**\n * Boolean indicating whether the `Tech` supports changing the speed at which the media\n * plays. Examples:\n * - Set player to play 2x (twice) as fast\n * - Set player to play 0.5x (half) as fast\n *\n * @type {boolean}\n * @default {@link Html5.canControlPlaybackRate}\n */\n\n /**\n * Boolean indicating whether the `Tech` supports the `sourceset` event.\n *\n * @type {boolean}\n * @default\n */\n /**\n * Boolean indicating whether the `HTML5` tech currently supports native `TextTrack`s.\n *\n * @type {boolean}\n * @default {@link Html5.supportsNativeTextTracks}\n */\n /**\n * Boolean indicating whether the `HTML5` tech currently supports native `VideoTrack`s.\n *\n * @type {boolean}\n * @default {@link Html5.supportsNativeVideoTracks}\n */\n /**\n * Boolean indicating whether the `HTML5` tech currently supports native `AudioTrack`s.\n *\n * @type {boolean}\n * @default {@link Html5.supportsNativeAudioTracks}\n */\n [['featuresMuteControl', 'canMuteVolume'], ['featuresPlaybackRate', 'canControlPlaybackRate'], ['featuresSourceset', 'canOverrideAttributes'], ['featuresNativeTextTracks', 'supportsNativeTextTracks'], ['featuresNativeVideoTracks', 'supportsNativeVideoTracks'], ['featuresNativeAudioTracks', 'supportsNativeAudioTracks']].forEach(function ([key, fn]) {\n defineLazyProperty(Html5.prototype, key, () => Html5[fn](), true);\n });\n Html5.prototype.featuresVolumeControl = Html5.canControlVolume();\n\n /**\n * Boolean indicating whether the `HTML5` tech currently supports the media element\n * moving in the DOM. iOS breaks if you move the media element, so this is set this to\n * false there. Everywhere else this should be true.\n *\n * @type {boolean}\n * @default\n */\n Html5.prototype.movingMediaElementInDOM = !IS_IOS;\n\n // TODO: Previous comment: No longer appears to be used. Can probably be removed.\n // Is this true?\n /**\n * Boolean indicating whether the `HTML5` tech currently supports automatic media resize\n * when going into fullscreen.\n *\n * @type {boolean}\n * @default\n */\n Html5.prototype.featuresFullscreenResize = true;\n\n /**\n * Boolean indicating whether the `HTML5` tech currently supports the progress event.\n * If this is false, manual `progress` events will be triggered instead.\n *\n * @type {boolean}\n * @default\n */\n Html5.prototype.featuresProgressEvents = true;\n\n /**\n * Boolean indicating whether the `HTML5` tech currently supports the timeupdate event.\n * If this is false, manual `timeupdate` events will be triggered instead.\n *\n * @default\n */\n Html5.prototype.featuresTimeupdateEvents = true;\n\n /**\n * Whether the HTML5 el supports `requestVideoFrameCallback`\n *\n * @type {boolean}\n */\n Html5.prototype.featuresVideoFrameCallback = !!(Html5.TEST_VID && Html5.TEST_VID.requestVideoFrameCallback);\n Html5.disposeMediaElement = function (el) {\n if (!el) {\n return;\n }\n if (el.parentNode) {\n el.parentNode.removeChild(el);\n }\n\n // remove any child track or source nodes to prevent their loading\n while (el.hasChildNodes()) {\n el.removeChild(el.firstChild);\n }\n\n // remove any src reference. not setting `src=''` because that causes a warning\n // in firefox\n el.removeAttribute('src');\n\n // force the media element to update its loading state by calling load()\n // however IE on Windows 7N has a bug that throws an error so need a try/catch (#793)\n if (typeof el.load === 'function') {\n // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473)\n (function () {\n try {\n el.load();\n } catch (e) {\n // not supported\n }\n })();\n }\n };\n Html5.resetMediaElement = function (el) {\n if (!el) {\n return;\n }\n const sources = el.querySelectorAll('source');\n let i = sources.length;\n while (i--) {\n el.removeChild(sources[i]);\n }\n\n // remove any src reference.\n // not setting `src=''` because that throws an error\n el.removeAttribute('src');\n if (typeof el.load === 'function') {\n // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473)\n (function () {\n try {\n el.load();\n } catch (e) {\n // satisfy linter\n }\n })();\n }\n };\n\n /* Native HTML5 element property wrapping ----------------------------------- */\n // Wrap native boolean attributes with getters that check both property and attribute\n // The list is as followed:\n // muted, defaultMuted, autoplay, controls, loop, playsinline\n [\n /**\n * Get the value of `muted` from the media element. `muted` indicates\n * that the volume for the media should be set to silent. This does not actually change\n * the `volume` attribute.\n *\n * @method Html5#muted\n * @return {boolean}\n * - True if the value of `volume` should be ignored and the audio set to silent.\n * - False if the value of `volume` should be used.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted}\n */\n 'muted',\n /**\n * Get the value of `defaultMuted` from the media element. `defaultMuted` indicates\n * whether the media should start muted or not. Only changes the default state of the\n * media. `muted` and `defaultMuted` can have different values. {@link Html5#muted} indicates the\n * current state.\n *\n * @method Html5#defaultMuted\n * @return {boolean}\n * - The value of `defaultMuted` from the media element.\n * - True indicates that the media should start muted.\n * - False indicates that the media should not start muted\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted}\n */\n 'defaultMuted',\n /**\n * Get the value of `autoplay` from the media element. `autoplay` indicates\n * that the media should start to play as soon as the page is ready.\n *\n * @method Html5#autoplay\n * @return {boolean}\n * - The value of `autoplay` from the media element.\n * - True indicates that the media should start as soon as the page loads.\n * - False indicates that the media should not start as soon as the page loads.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay}\n */\n 'autoplay',\n /**\n * Get the value of `controls` from the media element. `controls` indicates\n * whether the native media controls should be shown or hidden.\n *\n * @method Html5#controls\n * @return {boolean}\n * - The value of `controls` from the media element.\n * - True indicates that native controls should be showing.\n * - False indicates that native controls should be hidden.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-controls}\n */\n 'controls',\n /**\n * Get the value of `loop` from the media element. `loop` indicates\n * that the media should return to the start of the media and continue playing once\n * it reaches the end.\n *\n * @method Html5#loop\n * @return {boolean}\n * - The value of `loop` from the media element.\n * - True indicates that playback should seek back to start once\n * the end of a media is reached.\n * - False indicates that playback should not loop back to the start when the\n * end of the media is reached.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop}\n */\n 'loop',\n /**\n * Get the value of `playsinline` from the media element. `playsinline` indicates\n * to the browser that non-fullscreen playback is preferred when fullscreen\n * playback is the native default, such as in iOS Safari.\n *\n * @method Html5#playsinline\n * @return {boolean}\n * - The value of `playsinline` from the media element.\n * - True indicates that the media should play inline.\n * - False indicates that the media should not play inline.\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}\n */\n 'playsinline'].forEach(function (prop) {\n Html5.prototype[prop] = function () {\n return this.el_[prop] || this.el_.hasAttribute(prop);\n };\n });\n\n // Wrap native boolean attributes with setters that set both property and attribute\n // The list is as followed:\n // setMuted, setDefaultMuted, setAutoplay, setLoop, setPlaysinline\n // setControls is special-cased above\n [\n /**\n * Set the value of `muted` on the media element. `muted` indicates that the current\n * audio level should be silent.\n *\n * @method Html5#setMuted\n * @param {boolean} muted\n * - True if the audio should be set to silent\n * - False otherwise\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted}\n */\n 'muted',\n /**\n * Set the value of `defaultMuted` on the media element. `defaultMuted` indicates that the current\n * audio level should be silent, but will only effect the muted level on initial playback..\n *\n * @method Html5.prototype.setDefaultMuted\n * @param {boolean} defaultMuted\n * - True if the audio should be set to silent\n * - False otherwise\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted}\n */\n 'defaultMuted',\n /**\n * Set the value of `autoplay` on the media element. `autoplay` indicates\n * that the media should start to play as soon as the page is ready.\n *\n * @method Html5#setAutoplay\n * @param {boolean} autoplay\n * - True indicates that the media should start as soon as the page loads.\n * - False indicates that the media should not start as soon as the page loads.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay}\n */\n 'autoplay',\n /**\n * Set the value of `loop` on the media element. `loop` indicates\n * that the media should return to the start of the media and continue playing once\n * it reaches the end.\n *\n * @method Html5#setLoop\n * @param {boolean} loop\n * - True indicates that playback should seek back to start once\n * the end of a media is reached.\n * - False indicates that playback should not loop back to the start when the\n * end of the media is reached.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop}\n */\n 'loop',\n /**\n * Set the value of `playsinline` from the media element. `playsinline` indicates\n * to the browser that non-fullscreen playback is preferred when fullscreen\n * playback is the native default, such as in iOS Safari.\n *\n * @method Html5#setPlaysinline\n * @param {boolean} playsinline\n * - True indicates that the media should play inline.\n * - False indicates that the media should not play inline.\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}\n */\n 'playsinline'].forEach(function (prop) {\n Html5.prototype['set' + toTitleCase(prop)] = function (v) {\n this.el_[prop] = v;\n if (v) {\n this.el_.setAttribute(prop, prop);\n } else {\n this.el_.removeAttribute(prop);\n }\n };\n });\n\n // Wrap native properties with a getter\n // The list is as followed\n // paused, currentTime, buffered, volume, poster, preload, error, seeking\n // seekable, ended, playbackRate, defaultPlaybackRate, disablePictureInPicture\n // played, networkState, readyState, videoWidth, videoHeight, crossOrigin\n [\n /**\n * Get the value of `paused` from the media element. `paused` indicates whether the media element\n * is currently paused or not.\n *\n * @method Html5#paused\n * @return {boolean}\n * The value of `paused` from the media element.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-paused}\n */\n 'paused',\n /**\n * Get the value of `currentTime` from the media element. `currentTime` indicates\n * the current second that the media is at in playback.\n *\n * @method Html5#currentTime\n * @return {number}\n * The value of `currentTime` from the media element.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-currenttime}\n */\n 'currentTime',\n /**\n * Get the value of `buffered` from the media element. `buffered` is a `TimeRange`\n * object that represents the parts of the media that are already downloaded and\n * available for playback.\n *\n * @method Html5#buffered\n * @return {TimeRange}\n * The value of `buffered` from the media element.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-buffered}\n */\n 'buffered',\n /**\n * Get the value of `volume` from the media element. `volume` indicates\n * the current playback volume of audio for a media. `volume` will be a value from 0\n * (silent) to 1 (loudest and default).\n *\n * @method Html5#volume\n * @return {number}\n * The value of `volume` from the media element. Value will be between 0-1.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume}\n */\n 'volume',\n /**\n * Get the value of `poster` from the media element. `poster` indicates\n * that the url of an image file that can/will be shown when no media data is available.\n *\n * @method Html5#poster\n * @return {string}\n * The value of `poster` from the media element. Value will be a url to an\n * image.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-video-poster}\n */\n 'poster',\n /**\n * Get the value of `preload` from the media element. `preload` indicates\n * what should download before the media is interacted with. It can have the following\n * values:\n * - none: nothing should be downloaded\n * - metadata: poster and the first few frames of the media may be downloaded to get\n * media dimensions and other metadata\n * - auto: allow the media and metadata for the media to be downloaded before\n * interaction\n *\n * @method Html5#preload\n * @return {string}\n * The value of `preload` from the media element. Will be 'none', 'metadata',\n * or 'auto'.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload}\n */\n 'preload',\n /**\n * Get the value of the `error` from the media element. `error` indicates any\n * MediaError that may have occurred during playback. If error returns null there is no\n * current error.\n *\n * @method Html5#error\n * @return {MediaError|null}\n * The value of `error` from the media element. Will be `MediaError` if there\n * is a current error and null otherwise.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-error}\n */\n 'error',\n /**\n * Get the value of `seeking` from the media element. `seeking` indicates whether the\n * media is currently seeking to a new position or not.\n *\n * @method Html5#seeking\n * @return {boolean}\n * - The value of `seeking` from the media element.\n * - True indicates that the media is currently seeking to a new position.\n * - False indicates that the media is not seeking to a new position at this time.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seeking}\n */\n 'seeking',\n /**\n * Get the value of `seekable` from the media element. `seekable` returns a\n * `TimeRange` object indicating ranges of time that can currently be `seeked` to.\n *\n * @method Html5#seekable\n * @return {TimeRange}\n * The value of `seekable` from the media element. A `TimeRange` object\n * indicating the current ranges of time that can be seeked to.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seekable}\n */\n 'seekable',\n /**\n * Get the value of `ended` from the media element. `ended` indicates whether\n * the media has reached the end or not.\n *\n * @method Html5#ended\n * @return {boolean}\n * - The value of `ended` from the media element.\n * - True indicates that the media has ended.\n * - False indicates that the media has not ended.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended}\n */\n 'ended',\n /**\n * Get the value of `playbackRate` from the media element. `playbackRate` indicates\n * the rate at which the media is currently playing back. Examples:\n * - if playbackRate is set to 2, media will play twice as fast.\n * - if playbackRate is set to 0.5, media will play half as fast.\n *\n * @method Html5#playbackRate\n * @return {number}\n * The value of `playbackRate` from the media element. A number indicating\n * the current playback speed of the media, where 1 is normal speed.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}\n */\n 'playbackRate',\n /**\n * Get the value of `defaultPlaybackRate` from the media element. `defaultPlaybackRate` indicates\n * the rate at which the media is currently playing back. This value will not indicate the current\n * `playbackRate` after playback has started, use {@link Html5#playbackRate} for that.\n *\n * Examples:\n * - if defaultPlaybackRate is set to 2, media will play twice as fast.\n * - if defaultPlaybackRate is set to 0.5, media will play half as fast.\n *\n * @method Html5.prototype.defaultPlaybackRate\n * @return {number}\n * The value of `defaultPlaybackRate` from the media element. A number indicating\n * the current playback speed of the media, where 1 is normal speed.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}\n */\n 'defaultPlaybackRate',\n /**\n * Get the value of 'disablePictureInPicture' from the video element.\n *\n * @method Html5#disablePictureInPicture\n * @return {boolean} value\n * - The value of `disablePictureInPicture` from the video element.\n * - True indicates that the video can't be played in Picture-In-Picture mode\n * - False indicates that the video can be played in Picture-In-Picture mode\n *\n * @see [Spec]{@link https://w3c.github.io/picture-in-picture/#disable-pip}\n */\n 'disablePictureInPicture',\n /**\n * Get the value of `played` from the media element. `played` returns a `TimeRange`\n * object representing points in the media timeline that have been played.\n *\n * @method Html5#played\n * @return {TimeRange}\n * The value of `played` from the media element. A `TimeRange` object indicating\n * the ranges of time that have been played.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-played}\n */\n 'played',\n /**\n * Get the value of `networkState` from the media element. `networkState` indicates\n * the current network state. It returns an enumeration from the following list:\n * - 0: NETWORK_EMPTY\n * - 1: NETWORK_IDLE\n * - 2: NETWORK_LOADING\n * - 3: NETWORK_NO_SOURCE\n *\n * @method Html5#networkState\n * @return {number}\n * The value of `networkState` from the media element. This will be a number\n * from the list in the description.\n *\n * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-networkstate}\n */\n 'networkState',\n /**\n * Get the value of `readyState` from the media element. `readyState` indicates\n * the current state of the media element. It returns an enumeration from the\n * following list:\n * - 0: HAVE_NOTHING\n * - 1: HAVE_METADATA\n * - 2: HAVE_CURRENT_DATA\n * - 3: HAVE_FUTURE_DATA\n * - 4: HAVE_ENOUGH_DATA\n *\n * @method Html5#readyState\n * @return {number}\n * The value of `readyState` from the media element. This will be a number\n * from the list in the description.\n *\n * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#ready-states}\n */\n 'readyState',\n /**\n * Get the value of `videoWidth` from the video element. `videoWidth` indicates\n * the current width of the video in css pixels.\n *\n * @method Html5#videoWidth\n * @return {number}\n * The value of `videoWidth` from the video element. This will be a number\n * in css pixels.\n *\n * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth}\n */\n 'videoWidth',\n /**\n * Get the value of `videoHeight` from the video element. `videoHeight` indicates\n * the current height of the video in css pixels.\n *\n * @method Html5#videoHeight\n * @return {number}\n * The value of `videoHeight` from the video element. This will be a number\n * in css pixels.\n *\n * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth}\n */\n 'videoHeight',\n /**\n * Get the value of `crossOrigin` from the media element. `crossOrigin` indicates\n * to the browser that should sent the cookies along with the requests for the\n * different assets/playlists\n *\n * @method Html5#crossOrigin\n * @return {string}\n * - anonymous indicates that the media should not sent cookies.\n * - use-credentials indicates that the media should sent cookies along the requests.\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/#attr-media-crossorigin}\n */\n 'crossOrigin'].forEach(function (prop) {\n Html5.prototype[prop] = function () {\n return this.el_[prop];\n };\n });\n\n // Wrap native properties with a setter in this format:\n // set + toTitleCase(name)\n // The list is as follows:\n // setVolume, setSrc, setPoster, setPreload, setPlaybackRate, setDefaultPlaybackRate,\n // setDisablePictureInPicture, setCrossOrigin\n [\n /**\n * Set the value of `volume` on the media element. `volume` indicates the current\n * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and\n * so on.\n *\n * @method Html5#setVolume\n * @param {number} percentAsDecimal\n * The volume percent as a decimal. Valid range is from 0-1.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume}\n */\n 'volume',\n /**\n * Set the value of `src` on the media element. `src` indicates the current\n * {@link Tech~SourceObject} for the media.\n *\n * @method Html5#setSrc\n * @param {Tech~SourceObject} src\n * The source object to set as the current source.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-src}\n */\n 'src',\n /**\n * Set the value of `poster` on the media element. `poster` is the url to\n * an image file that can/will be shown when no media data is available.\n *\n * @method Html5#setPoster\n * @param {string} poster\n * The url to an image that should be used as the `poster` for the media\n * element.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-poster}\n */\n 'poster',\n /**\n * Set the value of `preload` on the media element. `preload` indicates\n * what should download before the media is interacted with. It can have the following\n * values:\n * - none: nothing should be downloaded\n * - metadata: poster and the first few frames of the media may be downloaded to get\n * media dimensions and other metadata\n * - auto: allow the media and metadata for the media to be downloaded before\n * interaction\n *\n * @method Html5#setPreload\n * @param {string} preload\n * The value of `preload` to set on the media element. Must be 'none', 'metadata',\n * or 'auto'.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload}\n */\n 'preload',\n /**\n * Set the value of `playbackRate` on the media element. `playbackRate` indicates\n * the rate at which the media should play back. Examples:\n * - if playbackRate is set to 2, media will play twice as fast.\n * - if playbackRate is set to 0.5, media will play half as fast.\n *\n * @method Html5#setPlaybackRate\n * @return {number}\n * The value of `playbackRate` from the media element. A number indicating\n * the current playback speed of the media, where 1 is normal speed.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}\n */\n 'playbackRate',\n /**\n * Set the value of `defaultPlaybackRate` on the media element. `defaultPlaybackRate` indicates\n * the rate at which the media should play back upon initial startup. Changing this value\n * after a video has started will do nothing. Instead you should used {@link Html5#setPlaybackRate}.\n *\n * Example Values:\n * - if playbackRate is set to 2, media will play twice as fast.\n * - if playbackRate is set to 0.5, media will play half as fast.\n *\n * @method Html5.prototype.setDefaultPlaybackRate\n * @return {number}\n * The value of `defaultPlaybackRate` from the media element. A number indicating\n * the current playback speed of the media, where 1 is normal speed.\n *\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultplaybackrate}\n */\n 'defaultPlaybackRate',\n /**\n * Prevents the browser from suggesting a Picture-in-Picture context menu\n * or to request Picture-in-Picture automatically in some cases.\n *\n * @method Html5#setDisablePictureInPicture\n * @param {boolean} value\n * The true value will disable Picture-in-Picture mode.\n *\n * @see [Spec]{@link https://w3c.github.io/picture-in-picture/#disable-pip}\n */\n 'disablePictureInPicture',\n /**\n * Set the value of `crossOrigin` from the media element. `crossOrigin` indicates\n * to the browser that should sent the cookies along with the requests for the\n * different assets/playlists\n *\n * @method Html5#setCrossOrigin\n * @param {string} crossOrigin\n * - anonymous indicates that the media should not sent cookies.\n * - use-credentials indicates that the media should sent cookies along the requests.\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/#attr-media-crossorigin}\n */\n 'crossOrigin'].forEach(function (prop) {\n Html5.prototype['set' + toTitleCase(prop)] = function (v) {\n this.el_[prop] = v;\n };\n });\n\n // wrap native functions with a function\n // The list is as follows:\n // pause, load, play\n [\n /**\n * A wrapper around the media elements `pause` function. This will call the `HTML5`\n * media elements `pause` function.\n *\n * @method Html5#pause\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-pause}\n */\n 'pause',\n /**\n * A wrapper around the media elements `load` function. This will call the `HTML5`s\n * media element `load` function.\n *\n * @method Html5#load\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-load}\n */\n 'load',\n /**\n * A wrapper around the media elements `play` function. This will call the `HTML5`s\n * media element `play` function.\n *\n * @method Html5#play\n * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-play}\n */\n 'play'].forEach(function (prop) {\n Html5.prototype[prop] = function () {\n return this.el_[prop]();\n };\n });\n Tech.withSourceHandlers(Html5);\n\n /**\n * Native source handler for Html5, simply passes the source to the media element.\n *\n * @property {Tech~SourceObject} source\n * The source object\n *\n * @property {Html5} tech\n * The instance of the HTML5 tech.\n */\n Html5.nativeSourceHandler = {};\n\n /**\n * Check if the media element can play the given mime type.\n *\n * @param {string} type\n * The mimetype to check\n *\n * @return {string}\n * 'probably', 'maybe', or '' (empty string)\n */\n Html5.nativeSourceHandler.canPlayType = function (type) {\n // IE without MediaPlayer throws an error (#519)\n try {\n return Html5.TEST_VID.canPlayType(type);\n } catch (e) {\n return '';\n }\n };\n\n /**\n * Check if the media element can handle a source natively.\n *\n * @param {Tech~SourceObject} source\n * The source object\n *\n * @param {Object} [options]\n * Options to be passed to the tech.\n *\n * @return {string}\n * 'probably', 'maybe', or '' (empty string).\n */\n Html5.nativeSourceHandler.canHandleSource = function (source, options) {\n // If a type was provided we should rely on that\n if (source.type) {\n return Html5.nativeSourceHandler.canPlayType(source.type);\n\n // If no type, fall back to checking 'video/[EXTENSION]'\n } else if (source.src) {\n const ext = getFileExtension(source.src);\n return Html5.nativeSourceHandler.canPlayType(`video/${ext}`);\n }\n return '';\n };\n\n /**\n * Pass the source to the native media element.\n *\n * @param {Tech~SourceObject} source\n * The source object\n *\n * @param {Html5} tech\n * The instance of the Html5 tech\n *\n * @param {Object} [options]\n * The options to pass to the source\n */\n Html5.nativeSourceHandler.handleSource = function (source, tech, options) {\n tech.setSrc(source.src);\n };\n\n /**\n * A noop for the native dispose function, as cleanup is not needed.\n */\n Html5.nativeSourceHandler.dispose = function () {};\n\n // Register the native source handler\n Html5.registerSourceHandler(Html5.nativeSourceHandler);\n Tech.registerTech('Html5', Html5);\n\n /**\n * @file player.js\n */\n\n /** @import AudioTrackList from './tracks/audio-track-list' */\n /** @import HtmlTrackElement from './tracks/html-track-element' */\n /** @import HtmlTrackElementList from './tracks/html-track-element-list' */\n /** @import TextTrackList from './tracks/text-track-list' */\n /** @import { TimeRange } from './utils/time' */\n /** @import VideoTrackList from './tracks/video-track-list' */\n\n /**\n * @callback PlayerReadyCallback\n * @this {Player}\n * @returns {void}\n */\n\n // The following tech events are simply re-triggered\n // on the player when they happen\n const TECH_EVENTS_RETRIGGER = [\n /**\n * Fired while the user agent is downloading media data.\n *\n * @event Player#progress\n * @type {Event}\n */\n /**\n * Retrigger the `progress` event that was triggered by the {@link Tech}.\n *\n * @private\n * @method Player#handleTechProgress_\n * @fires Player#progress\n * @listens Tech#progress\n */\n 'progress',\n /**\n * Fires when the loading of an audio/video is aborted.\n *\n * @event Player#abort\n * @type {Event}\n */\n /**\n * Retrigger the `abort` event that was triggered by the {@link Tech}.\n *\n * @private\n * @method Player#handleTechAbort_\n * @fires Player#abort\n * @listens Tech#abort\n */\n 'abort',\n /**\n * Fires when the browser is intentionally not getting media data.\n *\n * @event Player#suspend\n * @type {Event}\n */\n /**\n * Retrigger the `suspend` event that was triggered by the {@link Tech}.\n *\n * @private\n * @method Player#handleTechSuspend_\n * @fires Player#suspend\n * @listens Tech#suspend\n */\n 'suspend',\n /**\n * Fires when the current playlist is empty.\n *\n * @event Player#emptied\n * @type {Event}\n */\n /**\n * Retrigger the `emptied` event that was triggered by the {@link Tech}.\n *\n * @private\n * @method Player#handleTechEmptied_\n * @fires Player#emptied\n * @listens Tech#emptied\n */\n 'emptied',\n /**\n * Fires when the browser is trying to get media data, but data is not available.\n *\n * @event Player#stalled\n * @type {Event}\n */\n /**\n * Retrigger the `stalled` event that was triggered by the {@link Tech}.\n *\n * @private\n * @method Player#handleTechStalled_\n * @fires Player#stalled\n * @listens Tech#stalled\n */\n 'stalled',\n /**\n * Fires when the browser has loaded meta data for the audio/video.\n *\n * @event Player#loadedmetadata\n * @type {Event}\n */\n /**\n * Retrigger the `loadedmetadata` event that was triggered by the {@link Tech}.\n *\n * @private\n * @method Player#handleTechLoadedmetadata_\n * @fires Player#loadedmetadata\n * @listens Tech#loadedmetadata\n */\n 'loadedmetadata',\n /**\n * Fires when the browser has loaded the current frame of the audio/video.\n *\n * @event Player#loadeddata\n * @type {event}\n */\n /**\n * Retrigger the `loadeddata` event that was triggered by the {@link Tech}.\n *\n * @private\n * @method Player#handleTechLoaddeddata_\n * @fires Player#loadeddata\n * @listens Tech#loadeddata\n */\n 'loadeddata',\n /**\n * Fires when the current playback position has changed.\n *\n * @event Player#timeupdate\n * @type {event}\n */\n /**\n * Retrigger the `timeupdate` event that was triggered by the {@link Tech}.\n *\n * @private\n * @method Player#handleTechTimeUpdate_\n * @fires Player#timeupdate\n * @listens Tech#timeupdate\n */\n 'timeupdate',\n /**\n * Fires when the video's intrinsic dimensions change\n *\n * @event Player#resize\n * @type {event}\n */\n /**\n * Retrigger the `resize` event that was triggered by the {@link Tech}.\n *\n * @private\n * @method Player#handleTechResize_\n * @fires Player#resize\n * @listens Tech#resize\n */\n 'resize',\n /**\n * Fires when the volume has been changed\n *\n * @event Player#volumechange\n * @type {event}\n */\n /**\n * Retrigger the `volumechange` event that was triggered by the {@link Tech}.\n *\n * @private\n * @method Player#handleTechVolumechange_\n * @fires Player#volumechange\n * @listens Tech#volumechange\n */\n 'volumechange',\n /**\n * Fires when the text track has been changed\n *\n * @event Player#texttrackchange\n * @type {event}\n */\n /**\n * Retrigger the `texttrackchange` event that was triggered by the {@link Tech}.\n *\n * @private\n * @method Player#handleTechTexttrackchange_\n * @fires Player#texttrackchange\n * @listens Tech#texttrackchange\n */\n 'texttrackchange'];\n\n // events to queue when playback rate is zero\n // this is a hash for the sole purpose of mapping non-camel-cased event names\n // to camel-cased function names\n const TECH_EVENTS_QUEUE = {\n canplay: 'CanPlay',\n canplaythrough: 'CanPlayThrough',\n playing: 'Playing',\n seeked: 'Seeked'\n };\n const BREAKPOINT_ORDER = ['tiny', 'xsmall', 'small', 'medium', 'large', 'xlarge', 'huge'];\n const BREAKPOINT_CLASSES = {};\n\n // grep: vjs-layout-tiny\n // grep: vjs-layout-x-small\n // grep: vjs-layout-small\n // grep: vjs-layout-medium\n // grep: vjs-layout-large\n // grep: vjs-layout-x-large\n // grep: vjs-layout-huge\n BREAKPOINT_ORDER.forEach(k => {\n const v = k.charAt(0) === 'x' ? `x-${k.substring(1)}` : k;\n BREAKPOINT_CLASSES[k] = `vjs-layout-${v}`;\n });\n const DEFAULT_BREAKPOINTS = {\n tiny: 210,\n xsmall: 320,\n small: 425,\n medium: 768,\n large: 1440,\n xlarge: 2560,\n huge: Infinity\n };\n\n /**\n * An instance of the `Player` class is created when any of the Video.js setup methods\n * are used to initialize a video.\n *\n * After an instance has been created it can be accessed globally in three ways:\n * 1. By calling `videojs.getPlayer('example_video_1');`\n * 2. By calling `videojs('example_video_1');` (not recommended)\n * 2. By using it directly via `videojs.players.example_video_1;`\n *\n * @extends Component\n * @global\n */\n class Player extends Component {\n /**\n * Create an instance of this class.\n *\n * @param {Element} tag\n * The original video DOM element used for configuring options.\n *\n * @param {Object} [options]\n * Object of option names and values.\n *\n * @param {PlayerReadyCallback} [ready]\n * Ready callback function.\n */\n constructor(tag, options, ready) {\n // Make sure tag ID exists\n // also here.. probably better\n tag.id = tag.id || options.id || `vjs_video_${newGUID()}`;\n\n // Set Options\n // The options argument overrides options set in the video tag\n // which overrides globally set options.\n // This latter part coincides with the load order\n // (tag must exist before Player)\n options = Object.assign(Player.getTagSettings(tag), options);\n\n // Delay the initialization of children because we need to set up\n // player properties first, and can't use `this` before `super()`\n options.initChildren = false;\n\n // Same with creating the element\n options.createEl = false;\n\n // don't auto mixin the evented mixin\n options.evented = false;\n\n // we don't want the player to report touch activity on itself\n // see enableTouchActivity in Component\n options.reportTouchActivity = false;\n\n // If language is not set, get the closest lang attribute\n if (!options.language) {\n const closest = tag.closest('[lang]');\n if (closest) {\n options.language = closest.getAttribute('lang');\n }\n }\n\n // Run base component initializing with new options\n super(null, options, ready);\n\n // Create bound methods for document listeners.\n this.boundDocumentFullscreenChange_ = e => this.documentFullscreenChange_(e);\n this.boundFullWindowOnEscKey_ = e => this.fullWindowOnEscKey(e);\n this.boundUpdateStyleEl_ = e => this.updateStyleEl_(e);\n this.boundApplyInitTime_ = e => this.applyInitTime_(e);\n this.boundUpdateCurrentBreakpoint_ = e => this.updateCurrentBreakpoint_(e);\n this.boundHandleTechClick_ = e => this.handleTechClick_(e);\n this.boundHandleTechDoubleClick_ = e => this.handleTechDoubleClick_(e);\n this.boundHandleTechTouchStart_ = e => this.handleTechTouchStart_(e);\n this.boundHandleTechTouchMove_ = e => this.handleTechTouchMove_(e);\n this.boundHandleTechTouchEnd_ = e => this.handleTechTouchEnd_(e);\n this.boundHandleTechTap_ = e => this.handleTechTap_(e);\n this.boundUpdatePlayerHeightOnAudioOnlyMode_ = e => this.updatePlayerHeightOnAudioOnlyMode_(e);\n\n // default isFullscreen_ to false\n this.isFullscreen_ = false;\n\n // create logger\n this.log = createLogger(this.id_);\n\n // Hold our own reference to fullscreen api so it can be mocked in tests\n this.fsApi_ = FullscreenApi;\n\n // Tracks when a tech changes the poster\n this.isPosterFromTech_ = false;\n\n // Holds callback info that gets queued when playback rate is zero\n // and a seek is happening\n this.queuedCallbacks_ = [];\n\n // Turn off API access because we're loading a new tech that might load asynchronously\n this.isReady_ = false;\n\n // Init state hasStarted_\n this.hasStarted_ = false;\n\n // Init state userActive_\n this.userActive_ = false;\n\n // Init debugEnabled_\n this.debugEnabled_ = false;\n\n // Init state audioOnlyMode_\n this.audioOnlyMode_ = false;\n\n // Init state audioPosterMode_\n this.audioPosterMode_ = false;\n\n // Init state audioOnlyCache_\n this.audioOnlyCache_ = {\n controlBarHeight: null,\n playerHeight: null,\n hiddenChildren: []\n };\n\n // if the global option object was accidentally blown away by\n // someone, bail early with an informative error\n if (!this.options_ || !this.options_.techOrder || !this.options_.techOrder.length) {\n throw new Error('No techOrder specified. Did you overwrite ' + 'videojs.options instead of just changing the ' + 'properties you want to override?');\n }\n\n // Store the original tag used to set options\n this.tag = tag;\n\n // Store the tag attributes used to restore html5 element\n this.tagAttributes = tag && getAttributes(tag);\n\n // Update current language\n this.language(this.options_.language);\n\n // Update Supported Languages\n if (options.languages) {\n // Normalise player option languages to lowercase\n const languagesToLower = {};\n Object.getOwnPropertyNames(options.languages).forEach(function (name) {\n languagesToLower[name.toLowerCase()] = options.languages[name];\n });\n this.languages_ = languagesToLower;\n } else {\n this.languages_ = Player.prototype.options_.languages;\n }\n this.resetCache_();\n\n // Set poster\n /** @type string */\n this.poster_ = options.poster || '';\n\n // Set controls\n /** @type {boolean} */\n this.controls_ = !!options.controls;\n\n // Original tag settings stored in options\n // now remove immediately so native controls don't flash.\n // May be turned back on by HTML5 tech if nativeControlsForTouch is true\n tag.controls = false;\n tag.removeAttribute('controls');\n this.changingSrc_ = false;\n this.playCallbacks_ = [];\n this.playTerminatedQueue_ = [];\n\n // the attribute overrides the option\n if (tag.hasAttribute('autoplay')) {\n this.autoplay(true);\n } else {\n // otherwise use the setter to validate and\n // set the correct value.\n this.autoplay(this.options_.autoplay);\n }\n\n // check plugins\n if (options.plugins) {\n Object.keys(options.plugins).forEach(name => {\n if (typeof this[name] !== 'function') {\n throw new Error(`plugin \"${name}\" does not exist`);\n }\n });\n }\n\n /*\n * Store the internal state of scrubbing\n *\n * @private\n * @return {Boolean} True if the user is scrubbing\n */\n this.scrubbing_ = false;\n this.el_ = this.createEl();\n\n // Make this an evented object and use `el_` as its event bus.\n evented(this, {\n eventBusKey: 'el_'\n });\n\n // listen to document and player fullscreenchange handlers so we receive those events\n // before a user can receive them so we can update isFullscreen appropriately.\n // make sure that we listen to fullscreenchange events before everything else to make sure that\n // our isFullscreen method is updated properly for internal components as well as external.\n if (this.fsApi_.requestFullscreen) {\n on(document, this.fsApi_.fullscreenchange, this.boundDocumentFullscreenChange_);\n this.on(this.fsApi_.fullscreenchange, this.boundDocumentFullscreenChange_);\n }\n if (this.fluid_) {\n this.on(['playerreset', 'resize'], this.boundUpdateStyleEl_);\n }\n // We also want to pass the original player options to each component and plugin\n // as well so they don't need to reach back into the player for options later.\n // We also need to do another copy of this.options_ so we don't end up with\n // an infinite loop.\n const playerOptionsCopy = merge(this.options_);\n\n // Load plugins\n if (options.plugins) {\n Object.keys(options.plugins).forEach(name => {\n this[name](options.plugins[name]);\n });\n }\n\n // Enable debug mode to fire debugon event for all plugins.\n if (options.debug) {\n this.debug(true);\n }\n this.options_.playerOptions = playerOptionsCopy;\n this.middleware_ = [];\n this.playbackRates(options.playbackRates);\n if (options.experimentalSvgIcons) {\n // Add SVG Sprite to the DOM\n const parser = new window.DOMParser();\n const parsedSVG = parser.parseFromString(icons, 'image/svg+xml');\n const errorNode = parsedSVG.querySelector('parsererror');\n if (errorNode) {\n log.warn('Failed to load SVG Icons. Falling back to Font Icons.');\n this.options_.experimentalSvgIcons = null;\n } else {\n const sprite = parsedSVG.documentElement;\n sprite.style.display = 'none';\n this.el_.appendChild(sprite);\n this.addClass('vjs-svg-icons-enabled');\n }\n }\n this.initChildren();\n\n // Set isAudio based on whether or not an audio tag was used\n this.isAudio(tag.nodeName.toLowerCase() === 'audio');\n\n // Update controls className. Can't do this when the controls are initially\n // set because the element doesn't exist yet.\n if (this.controls()) {\n this.addClass('vjs-controls-enabled');\n } else {\n this.addClass('vjs-controls-disabled');\n }\n\n // Set ARIA label and region role depending on player type\n this.el_.setAttribute('role', 'region');\n if (this.isAudio()) {\n this.el_.setAttribute('aria-label', this.localize('Audio Player'));\n } else {\n this.el_.setAttribute('aria-label', this.localize('Video Player'));\n }\n if (this.isAudio()) {\n this.addClass('vjs-audio');\n }\n\n // Check if spatial navigation is enabled in the options.\n // If enabled, instantiate the SpatialNavigation class.\n if (options.spatialNavigation && options.spatialNavigation.enabled) {\n this.spatialNavigation = new SpatialNavigation(this);\n this.addClass('vjs-spatial-navigation-enabled');\n }\n\n // TODO: Make this smarter. Toggle user state between touching/mousing\n // using events, since devices can have both touch and mouse events.\n // TODO: Make this check be performed again when the window switches between monitors\n // (See https://github.com/videojs/video.js/issues/5683)\n if (TOUCH_ENABLED) {\n this.addClass('vjs-touch-enabled');\n }\n\n // iOS Safari has broken hover handling\n if (!IS_IOS) {\n this.addClass('vjs-workinghover');\n }\n\n // Make player easily findable by ID\n Player.players[this.id_] = this;\n\n // Add a major version class to aid css in plugins\n const majorVersion = version.split('.')[0];\n this.addClass(`vjs-v${majorVersion}`);\n\n // When the player is first initialized, trigger activity so components\n // like the control bar show themselves if needed\n this.userActive(true);\n this.reportUserActivity();\n this.one('play', e => this.listenForUserActivity_(e));\n this.on('keydown', e => this.handleKeyDown(e));\n this.on('languagechange', e => this.handleLanguagechange(e));\n this.breakpoints(this.options_.breakpoints);\n this.responsive(this.options_.responsive);\n\n // Calling both the audio mode methods after the player is fully\n // setup to be able to listen to the events triggered by them\n this.on('ready', () => {\n // Calling the audioPosterMode method first so that\n // the audioOnlyMode can take precedence when both options are set to true\n this.audioPosterMode(this.options_.audioPosterMode);\n this.audioOnlyMode(this.options_.audioOnlyMode);\n });\n }\n\n /**\n * Destroys the video player and does any necessary cleanup.\n *\n * This is especially helpful if you are dynamically adding and removing videos\n * to/from the DOM.\n *\n * @fires Player#dispose\n */\n dispose() {\n /**\n * Called when the player is being disposed of.\n *\n * @event Player#dispose\n * @type {Event}\n */\n this.trigger('dispose');\n // prevent dispose from being called twice\n this.off('dispose');\n\n // Make sure all player-specific document listeners are unbound. This is\n off(document, this.fsApi_.fullscreenchange, this.boundDocumentFullscreenChange_);\n off(document, 'keydown', this.boundFullWindowOnEscKey_);\n if (this.styleEl_ && this.styleEl_.parentNode) {\n this.styleEl_.parentNode.removeChild(this.styleEl_);\n this.styleEl_ = null;\n }\n\n // Kill reference to this player\n Player.players[this.id_] = null;\n if (this.tag && this.tag.player) {\n this.tag.player = null;\n }\n if (this.el_ && this.el_.player) {\n this.el_.player = null;\n }\n if (this.tech_) {\n this.tech_.dispose();\n this.isPosterFromTech_ = false;\n this.poster_ = '';\n }\n if (this.playerElIngest_) {\n this.playerElIngest_ = null;\n }\n if (this.tag) {\n this.tag = null;\n }\n clearCacheForPlayer(this);\n\n // remove all event handlers for track lists\n // all tracks and track listeners are removed on\n // tech dispose\n ALL.names.forEach(name => {\n const props = ALL[name];\n const list = this[props.getterName]();\n\n // if it is not a native list\n // we have to manually remove event listeners\n if (list && list.off) {\n list.off();\n }\n });\n\n // the actual .el_ is removed here, or replaced if\n super.dispose({\n restoreEl: this.options_.restoreEl\n });\n }\n\n /**\n * Create the `Player`'s DOM element.\n *\n * @return {Element}\n * The DOM element that gets created.\n */\n createEl() {\n let tag = this.tag;\n let el;\n let playerElIngest = this.playerElIngest_ = tag.parentNode && tag.parentNode.hasAttribute && tag.parentNode.hasAttribute('data-vjs-player');\n const divEmbed = this.tag.tagName.toLowerCase() === 'video-js';\n if (playerElIngest) {\n el = this.el_ = tag.parentNode;\n } else if (!divEmbed) {\n el = this.el_ = super.createEl('div');\n }\n\n // Copy over all the attributes from the tag, including ID and class\n // ID will now reference player box, not the video tag\n const attrs = getAttributes(tag);\n if (divEmbed) {\n el = this.el_ = tag;\n tag = this.tag = document.createElement('video');\n while (el.children.length) {\n tag.appendChild(el.firstChild);\n }\n if (!hasClass(el, 'video-js')) {\n addClass(el, 'video-js');\n }\n el.appendChild(tag);\n playerElIngest = this.playerElIngest_ = el;\n // move properties over from our custom `video-js` element\n // to our new `video` element. This will move things like\n // `src` or `controls` that were set via js before the player\n // was initialized.\n Object.keys(el).forEach(k => {\n try {\n tag[k] = el[k];\n } catch (e) {\n // we got a a property like outerHTML which we can't actually copy, ignore it\n }\n });\n }\n\n // set tabindex to -1 to remove the video element from the focus order\n tag.setAttribute('tabindex', '-1');\n attrs.tabindex = '-1';\n\n // Workaround for #4583 on Chrome (on Windows) with JAWS.\n // See https://github.com/FreedomScientific/VFO-standards-support/issues/78\n // Note that we can't detect if JAWS is being used, but this ARIA attribute\n // doesn't change behavior of Chrome if JAWS is not being used\n if (IS_CHROME && IS_WINDOWS) {\n tag.setAttribute('role', 'application');\n attrs.role = 'application';\n }\n\n // Remove width/height attrs from tag so CSS can make it 100% width/height\n tag.removeAttribute('width');\n tag.removeAttribute('height');\n if ('width' in attrs) {\n delete attrs.width;\n }\n if ('height' in attrs) {\n delete attrs.height;\n }\n Object.getOwnPropertyNames(attrs).forEach(function (attr) {\n // don't copy over the class attribute to the player element when we're in a div embed\n // the class is already set up properly in the divEmbed case\n // and we want to make sure that the `video-js` class doesn't get lost\n if (!(divEmbed && attr === 'class')) {\n el.setAttribute(attr, attrs[attr]);\n }\n if (divEmbed) {\n tag.setAttribute(attr, attrs[attr]);\n }\n });\n\n // Update tag id/class for use as HTML5 playback tech\n // Might think we should do this after embedding in container so .vjs-tech class\n // doesn't flash 100% width/height, but class only applies with .video-js parent\n tag.playerId = tag.id;\n tag.id += '_html5_api';\n tag.className = 'vjs-tech';\n\n // Make player findable on elements\n tag.player = el.player = this;\n // Default state of video is paused\n this.addClass('vjs-paused');\n const deviceClassNames = ['IS_SMART_TV', 'IS_TIZEN', 'IS_WEBOS', 'IS_ANDROID', 'IS_IPAD', 'IS_IPHONE', 'IS_CHROMECAST_RECEIVER'].filter(key => browser[key]).map(key => {\n return 'vjs-device-' + key.substring(3).toLowerCase().replace(/\\_/g, '-');\n });\n this.addClass(...deviceClassNames);\n\n // Add a style element in the player that we'll use to set the width/height\n // of the player in a way that's still overridable by CSS, just like the\n // video element\n if (window.VIDEOJS_NO_DYNAMIC_STYLE !== true) {\n this.styleEl_ = createStyleElement('vjs-styles-dimensions');\n const defaultsStyleEl = $('.vjs-styles-defaults');\n const head = $('head');\n head.insertBefore(this.styleEl_, defaultsStyleEl ? defaultsStyleEl.nextSibling : head.firstChild);\n }\n this.fill_ = false;\n this.fluid_ = false;\n\n // Pass in the width/height/aspectRatio options which will update the style el\n this.width(this.options_.width);\n this.height(this.options_.height);\n this.fill(this.options_.fill);\n this.fluid(this.options_.fluid);\n this.aspectRatio(this.options_.aspectRatio);\n // support both crossOrigin and crossorigin to reduce confusion and issues around the name\n this.crossOrigin(this.options_.crossOrigin || this.options_.crossorigin);\n\n // Hide any links within the video/audio tag,\n // because IE doesn't hide them completely from screen readers.\n const links = tag.getElementsByTagName('a');\n for (let i = 0; i < links.length; i++) {\n const linkEl = links.item(i);\n addClass(linkEl, 'vjs-hidden');\n linkEl.setAttribute('hidden', 'hidden');\n }\n\n // insertElFirst seems to cause the networkState to flicker from 3 to 2, so\n // keep track of the original for later so we can know if the source originally failed\n tag.initNetworkState_ = tag.networkState;\n\n // Wrap video tag in div (el/box) container\n if (tag.parentNode && !playerElIngest) {\n tag.parentNode.insertBefore(el, tag);\n }\n\n // insert the tag as the first child of the player element\n // then manually add it to the children array so that this.addChild\n // will work properly for other components\n //\n // Breaks iPhone, fixed in HTML5 setup.\n prependTo(tag, el);\n this.children_.unshift(tag);\n\n // Set lang attr on player to ensure CSS :lang() in consistent with player\n // if it's been set to something different to the doc\n this.el_.setAttribute('lang', this.language_);\n this.el_.setAttribute('translate', 'no');\n this.el_ = el;\n return el;\n }\n\n /**\n * Get or set the `Player`'s crossOrigin option. For the HTML5 player, this\n * sets the `crossOrigin` property on the `<video>` tag to control the CORS\n * behavior.\n *\n * @see [Video Element Attributes]{@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#attr-crossorigin}\n *\n * @param {string|null} [value]\n * The value to set the `Player`'s crossOrigin to. If an argument is\n * given, must be one of `'anonymous'` or `'use-credentials'`, or 'null'.\n *\n * @return {string|null|undefined}\n * - The current crossOrigin value of the `Player` when getting.\n * - undefined when setting\n */\n crossOrigin(value) {\n // `null` can be set to unset a value\n if (typeof value === 'undefined') {\n return this.techGet_('crossOrigin');\n }\n if (value !== null && value !== 'anonymous' && value !== 'use-credentials') {\n log.warn(`crossOrigin must be null, \"anonymous\" or \"use-credentials\", given \"${value}\"`);\n return;\n }\n this.techCall_('setCrossOrigin', value);\n if (this.posterImage) {\n this.posterImage.crossOrigin(value);\n }\n return;\n }\n\n /**\n * A getter/setter for the `Player`'s width. Returns the player's configured value.\n * To get the current width use `currentWidth()`.\n *\n * @param {number|string} [value]\n * CSS value to set the `Player`'s width to.\n *\n * @return {number|undefined}\n * - The current width of the `Player` when getting.\n * - Nothing when setting\n */\n width(value) {\n return this.dimension('width', value);\n }\n\n /**\n * A getter/setter for the `Player`'s height. Returns the player's configured value.\n * To get the current height use `currentheight()`.\n *\n * @param {number|string} [value]\n * CSS value to set the `Player`'s height to.\n *\n * @return {number|undefined}\n * - The current height of the `Player` when getting.\n * - Nothing when setting\n */\n height(value) {\n return this.dimension('height', value);\n }\n\n /**\n * A getter/setter for the `Player`'s width & height.\n *\n * @param {string} dimension\n * This string can be:\n * - 'width'\n * - 'height'\n *\n * @param {number|string} [value]\n * Value for dimension specified in the first argument.\n *\n * @return {number}\n * The dimension arguments value when getting (width/height).\n */\n dimension(dimension, value) {\n const privDimension = dimension + '_';\n if (value === undefined) {\n return this[privDimension] || 0;\n }\n if (value === '' || value === 'auto') {\n // If an empty string is given, reset the dimension to be automatic\n this[privDimension] = undefined;\n this.updateStyleEl_();\n return;\n }\n const parsedVal = parseFloat(value);\n if (isNaN(parsedVal)) {\n log.error(`Improper value \"${value}\" supplied for for ${dimension}`);\n return;\n }\n this[privDimension] = parsedVal;\n this.updateStyleEl_();\n }\n\n /**\n * A getter/setter/toggler for the vjs-fluid `className` on the `Player`.\n *\n * Turning this on will turn off fill mode.\n *\n * @param {boolean} [bool]\n * - A value of true adds the class.\n * - A value of false removes the class.\n * - No value will be a getter.\n *\n * @return {boolean|undefined}\n * - The value of fluid when getting.\n * - `undefined` when setting.\n */\n fluid(bool) {\n if (bool === undefined) {\n return !!this.fluid_;\n }\n this.fluid_ = !!bool;\n if (isEvented(this)) {\n this.off(['playerreset', 'resize'], this.boundUpdateStyleEl_);\n }\n if (bool) {\n this.addClass('vjs-fluid');\n this.fill(false);\n addEventedCallback(this, () => {\n this.on(['playerreset', 'resize'], this.boundUpdateStyleEl_);\n });\n } else {\n this.removeClass('vjs-fluid');\n }\n this.updateStyleEl_();\n }\n\n /**\n * A getter/setter/toggler for the vjs-fill `className` on the `Player`.\n *\n * Turning this on will turn off fluid mode.\n *\n * @param {boolean} [bool]\n * - A value of true adds the class.\n * - A value of false removes the class.\n * - No value will be a getter.\n *\n * @return {boolean|undefined}\n * - The value of fluid when getting.\n * - `undefined` when setting.\n */\n fill(bool) {\n if (bool === undefined) {\n return !!this.fill_;\n }\n this.fill_ = !!bool;\n if (bool) {\n this.addClass('vjs-fill');\n this.fluid(false);\n } else {\n this.removeClass('vjs-fill');\n }\n }\n\n /**\n * Get/Set the aspect ratio\n *\n * @param {string} [ratio]\n * Aspect ratio for player\n *\n * @return {string|undefined}\n * returns the current aspect ratio when getting\n */\n\n /**\n * A getter/setter for the `Player`'s aspect ratio.\n *\n * @param {string} [ratio]\n * The value to set the `Player`'s aspect ratio to.\n *\n * @return {string|undefined}\n * - The current aspect ratio of the `Player` when getting.\n * - undefined when setting\n */\n aspectRatio(ratio) {\n if (ratio === undefined) {\n return this.aspectRatio_;\n }\n\n // Check for width:height format\n if (!/^\\d+\\:\\d+$/.test(ratio)) {\n throw new Error('Improper value supplied for aspect ratio. The format should be width:height, for example 16:9.');\n }\n this.aspectRatio_ = ratio;\n\n // We're assuming if you set an aspect ratio you want fluid mode,\n // because in fixed mode you could calculate width and height yourself.\n this.fluid(true);\n this.updateStyleEl_();\n }\n\n /**\n * Update styles of the `Player` element (height, width and aspect ratio).\n *\n * @private\n * @listens Tech#loadedmetadata\n */\n updateStyleEl_() {\n if (window.VIDEOJS_NO_DYNAMIC_STYLE === true) {\n const width = typeof this.width_ === 'number' ? this.width_ : this.options_.width;\n const height = typeof this.height_ === 'number' ? this.height_ : this.options_.height;\n const techEl = this.tech_ && this.tech_.el();\n if (techEl) {\n if (width >= 0) {\n techEl.width = width;\n }\n if (height >= 0) {\n techEl.height = height;\n }\n }\n return;\n }\n let width;\n let height;\n let aspectRatio;\n let idClass;\n\n // The aspect ratio is either used directly or to calculate width and height.\n if (this.aspectRatio_ !== undefined && this.aspectRatio_ !== 'auto') {\n // Use any aspectRatio that's been specifically set\n aspectRatio = this.aspectRatio_;\n } else if (this.videoWidth() > 0) {\n // Otherwise try to get the aspect ratio from the video metadata\n aspectRatio = this.videoWidth() + ':' + this.videoHeight();\n } else {\n // Or use a default. The video element's is 2:1, but 16:9 is more common.\n aspectRatio = '16:9';\n }\n\n // Get the ratio as a decimal we can use to calculate dimensions\n const ratioParts = aspectRatio.split(':');\n const ratioMultiplier = ratioParts[1] / ratioParts[0];\n if (this.width_ !== undefined) {\n // Use any width that's been specifically set\n width = this.width_;\n } else if (this.height_ !== undefined) {\n // Or calculate the width from the aspect ratio if a height has been set\n width = this.height_ / ratioMultiplier;\n } else {\n // Or use the video's metadata, or use the video el's default of 300\n width = this.videoWidth() || 300;\n }\n if (this.height_ !== undefined) {\n // Use any height that's been specifically set\n height = this.height_;\n } else {\n // Otherwise calculate the height from the ratio and the width\n height = width * ratioMultiplier;\n }\n\n // Ensure the CSS class is valid by starting with an alpha character\n if (/^[^a-zA-Z]/.test(this.id())) {\n idClass = 'dimensions-' + this.id();\n } else {\n idClass = this.id() + '-dimensions';\n }\n\n // Ensure the right class is still on the player for the style element\n this.addClass(idClass);\n setTextContent(this.styleEl_, `\n .${idClass} {\n width: ${width}px;\n height: ${height}px;\n }\n\n .${idClass}.vjs-fluid:not(.vjs-audio-only-mode) {\n padding-top: ${ratioMultiplier * 100}%;\n }\n `);\n }\n\n /**\n * Load/Create an instance of playback {@link Tech} including element\n * and API methods. Then append the `Tech` element in `Player` as a child.\n *\n * @param {string} techName\n * name of the playback technology\n *\n * @param {string} source\n * video source\n *\n * @private\n */\n loadTech_(techName, source) {\n // Pause and remove current playback technology\n if (this.tech_) {\n this.unloadTech_();\n }\n const titleTechName = toTitleCase(techName);\n const camelTechName = techName.charAt(0).toLowerCase() + techName.slice(1);\n\n // get rid of the HTML5 video tag as soon as we are using another tech\n if (titleTechName !== 'Html5' && this.tag) {\n Tech.getTech('Html5').disposeMediaElement(this.tag);\n this.tag.player = null;\n this.tag = null;\n }\n this.techName_ = titleTechName;\n\n // Turn off API access because we're loading a new tech that might load asynchronously\n this.isReady_ = false;\n let autoplay = this.autoplay();\n\n // if autoplay is a string (or `true` with normalizeAutoplay: true) we pass false to the tech\n // because the player is going to handle autoplay on `loadstart`\n if (typeof this.autoplay() === 'string' || this.autoplay() === true && this.options_.normalizeAutoplay) {\n autoplay = false;\n }\n\n // Grab tech-specific options from player options and add source and parent element to use.\n const techOptions = {\n source,\n autoplay,\n 'nativeControlsForTouch': this.options_.nativeControlsForTouch,\n 'playerId': this.id(),\n 'techId': `${this.id()}_${camelTechName}_api`,\n 'playsinline': this.options_.playsinline,\n 'preload': this.options_.preload,\n 'loop': this.options_.loop,\n 'disablePictureInPicture': this.options_.disablePictureInPicture,\n 'muted': this.options_.muted,\n 'poster': this.poster(),\n 'language': this.language(),\n 'playerElIngest': this.playerElIngest_ || false,\n 'vtt.js': this.options_['vtt.js'],\n 'canOverridePoster': !!this.options_.techCanOverridePoster,\n 'enableSourceset': this.options_.enableSourceset\n };\n ALL.names.forEach(name => {\n const props = ALL[name];\n techOptions[props.getterName] = this[props.privateName];\n });\n Object.assign(techOptions, this.options_[titleTechName]);\n Object.assign(techOptions, this.options_[camelTechName]);\n Object.assign(techOptions, this.options_[techName.toLowerCase()]);\n if (this.tag) {\n techOptions.tag = this.tag;\n }\n if (source && source.src === this.cache_.src && this.cache_.currentTime > 0) {\n techOptions.startTime = this.cache_.currentTime;\n }\n\n // Initialize tech instance\n const TechClass = Tech.getTech(techName);\n if (!TechClass) {\n throw new Error(`No Tech named '${titleTechName}' exists! '${titleTechName}' should be registered using videojs.registerTech()'`);\n }\n this.tech_ = new TechClass(techOptions);\n\n // player.triggerReady is always async, so don't need this to be async\n this.tech_.ready(bind_(this, this.handleTechReady_), true);\n textTrackConverter.jsonToTextTracks(this.textTracksJson_ || [], this.tech_);\n\n // Listen to all HTML5-defined events and trigger them on the player\n TECH_EVENTS_RETRIGGER.forEach(event => {\n this.on(this.tech_, event, e => this[`handleTech${toTitleCase(event)}_`](e));\n });\n Object.keys(TECH_EVENTS_QUEUE).forEach(event => {\n this.on(this.tech_, event, eventObj => {\n if (this.tech_.playbackRate() === 0 && this.tech_.seeking()) {\n this.queuedCallbacks_.push({\n callback: this[`handleTech${TECH_EVENTS_QUEUE[event]}_`].bind(this),\n event: eventObj\n });\n return;\n }\n this[`handleTech${TECH_EVENTS_QUEUE[event]}_`](eventObj);\n });\n });\n this.on(this.tech_, 'loadstart', e => this.handleTechLoadStart_(e));\n this.on(this.tech_, 'sourceset', e => this.handleTechSourceset_(e));\n this.on(this.tech_, 'waiting', e => this.handleTechWaiting_(e));\n this.on(this.tech_, 'ended', e => this.handleTechEnded_(e));\n this.on(this.tech_, 'seeking', e => this.handleTechSeeking_(e));\n this.on(this.tech_, 'play', e => this.handleTechPlay_(e));\n this.on(this.tech_, 'pause', e => this.handleTechPause_(e));\n this.on(this.tech_, 'durationchange', e => this.handleTechDurationChange_(e));\n this.on(this.tech_, 'fullscreenchange', (e, data) => this.handleTechFullscreenChange_(e, data));\n this.on(this.tech_, 'fullscreenerror', (e, err) => this.handleTechFullscreenError_(e, err));\n this.on(this.tech_, 'enterpictureinpicture', e => this.handleTechEnterPictureInPicture_(e));\n this.on(this.tech_, 'leavepictureinpicture', e => this.handleTechLeavePictureInPicture_(e));\n this.on(this.tech_, 'error', e => this.handleTechError_(e));\n this.on(this.tech_, 'posterchange', e => this.handleTechPosterChange_(e));\n this.on(this.tech_, 'textdata', e => this.handleTechTextData_(e));\n this.on(this.tech_, 'ratechange', e => this.handleTechRateChange_(e));\n this.on(this.tech_, 'loadedmetadata', this.boundUpdateStyleEl_);\n this.usingNativeControls(this.techGet_('controls'));\n if (this.controls() && !this.usingNativeControls()) {\n this.addTechControlsListeners_();\n }\n\n // Add the tech element in the DOM if it was not already there\n // Make sure to not insert the original video element if using Html5\n if (this.tech_.el().parentNode !== this.el() && (titleTechName !== 'Html5' || !this.tag)) {\n prependTo(this.tech_.el(), this.el());\n }\n\n // Get rid of the original video tag reference after the first tech is loaded\n if (this.tag) {\n this.tag.player = null;\n this.tag = null;\n }\n }\n\n /**\n * Unload and dispose of the current playback {@link Tech}.\n *\n * @private\n */\n unloadTech_() {\n // Save the current text tracks so that we can reuse the same text tracks with the next tech\n ALL.names.forEach(name => {\n const props = ALL[name];\n this[props.privateName] = this[props.getterName]();\n });\n this.textTracksJson_ = textTrackConverter.textTracksToJson(this.tech_);\n this.isReady_ = false;\n this.tech_.dispose();\n this.tech_ = false;\n if (this.isPosterFromTech_) {\n this.poster_ = '';\n this.trigger('posterchange');\n }\n this.isPosterFromTech_ = false;\n }\n\n /**\n * Return a reference to the current {@link Tech}.\n * It will print a warning by default about the danger of using the tech directly\n * but any argument that is passed in will silence the warning.\n *\n * @param {*} [safety]\n * Anything passed in to silence the warning\n *\n * @return {Tech}\n * The Tech\n */\n tech(safety) {\n if (safety === undefined) {\n log.warn('Using the tech directly can be dangerous. I hope you know what you\\'re doing.\\n' + 'See https://github.com/videojs/video.js/issues/2617 for more info.\\n');\n }\n return this.tech_;\n }\n\n /**\n * An object that contains Video.js version.\n *\n * @typedef {Object} PlayerVersion\n *\n * @property {string} 'video.js' - Video.js version\n */\n\n /**\n * Returns an object with Video.js version.\n *\n * @return {PlayerVersion}\n * An object with Video.js version.\n */\n version() {\n return {\n 'video.js': version\n };\n }\n\n /**\n * Set up click and touch listeners for the playback element\n *\n * - On desktops: a click on the video itself will toggle playback\n * - On mobile devices: a click on the video toggles controls\n * which is done by toggling the user state between active and\n * inactive\n * - A tap can signal that a user has become active or has become inactive\n * e.g. a quick tap on an iPhone movie should reveal the controls. Another\n * quick tap should hide them again (signaling the user is in an inactive\n * viewing state)\n * - In addition to this, we still want the user to be considered inactive after\n * a few seconds of inactivity.\n *\n * > Note: the only part of iOS interaction we can't mimic with this setup\n * is a touch and hold on the video element counting as activity in order to\n * keep the controls showing, but that shouldn't be an issue. A touch and hold\n * on any controls will still keep the user active\n *\n * @private\n */\n addTechControlsListeners_() {\n // Make sure to remove all the previous listeners in case we are called multiple times.\n this.removeTechControlsListeners_();\n this.on(this.tech_, 'click', this.boundHandleTechClick_);\n this.on(this.tech_, 'dblclick', this.boundHandleTechDoubleClick_);\n\n // If the controls were hidden we don't want that to change without a tap event\n // so we'll check if the controls were already showing before reporting user\n // activity\n this.on(this.tech_, 'touchstart', this.boundHandleTechTouchStart_);\n this.on(this.tech_, 'touchmove', this.boundHandleTechTouchMove_);\n this.on(this.tech_, 'touchend', this.boundHandleTechTouchEnd_);\n\n // The tap listener needs to come after the touchend listener because the tap\n // listener cancels out any reportedUserActivity when setting userActive(false)\n this.on(this.tech_, 'tap', this.boundHandleTechTap_);\n }\n\n /**\n * Remove the listeners used for click and tap controls. This is needed for\n * toggling to controls disabled, where a tap/touch should do nothing.\n *\n * @private\n */\n removeTechControlsListeners_() {\n // We don't want to just use `this.off()` because there might be other needed\n // listeners added by techs that extend this.\n this.off(this.tech_, 'tap', this.boundHandleTechTap_);\n this.off(this.tech_, 'touchstart', this.boundHandleTechTouchStart_);\n this.off(this.tech_, 'touchmove', this.boundHandleTechTouchMove_);\n this.off(this.tech_, 'touchend', this.boundHandleTechTouchEnd_);\n this.off(this.tech_, 'click', this.boundHandleTechClick_);\n this.off(this.tech_, 'dblclick', this.boundHandleTechDoubleClick_);\n }\n\n /**\n * Player waits for the tech to be ready\n *\n * @private\n */\n handleTechReady_() {\n this.triggerReady();\n\n // Keep the same volume as before\n if (this.cache_.volume) {\n this.techCall_('setVolume', this.cache_.volume);\n }\n\n // Look if the tech found a higher resolution poster while loading\n this.handleTechPosterChange_();\n\n // Update the duration if available\n this.handleTechDurationChange_();\n }\n\n /**\n * Retrigger the `loadstart` event that was triggered by the {@link Tech}.\n *\n * @fires Player#loadstart\n * @listens Tech#loadstart\n * @private\n */\n handleTechLoadStart_() {\n // TODO: Update to use `emptied` event instead. See #1277.\n\n this.removeClass('vjs-ended', 'vjs-seeking');\n\n // reset the error state\n this.error(null);\n\n // Update the duration\n this.handleTechDurationChange_();\n if (!this.paused()) {\n /**\n * Fired when the user agent begins looking for media data\n *\n * @event Player#loadstart\n * @type {Event}\n */\n this.trigger('loadstart');\n } else {\n // reset the hasStarted state\n this.hasStarted(false);\n this.trigger('loadstart');\n }\n\n // autoplay happens after loadstart for the browser,\n // so we mimic that behavior\n this.manualAutoplay_(this.autoplay() === true && this.options_.normalizeAutoplay ? 'play' : this.autoplay());\n }\n\n /**\n * Handle autoplay string values, rather than the typical boolean\n * values that should be handled by the tech. Note that this is not\n * part of any specification. Valid values and what they do can be\n * found on the autoplay getter at Player#autoplay()\n */\n manualAutoplay_(type) {\n if (!this.tech_ || typeof type !== 'string') {\n return;\n }\n\n // Save original muted() value, set muted to true, and attempt to play().\n // On promise rejection, restore muted from saved value\n const resolveMuted = () => {\n const previouslyMuted = this.muted();\n this.muted(true);\n const restoreMuted = () => {\n this.muted(previouslyMuted);\n };\n\n // restore muted on play terminatation\n this.playTerminatedQueue_.push(restoreMuted);\n const mutedPromise = this.play();\n if (!isPromise(mutedPromise)) {\n return;\n }\n return mutedPromise.catch(err => {\n restoreMuted();\n throw new Error(`Rejection at manualAutoplay. Restoring muted value. ${err ? err : ''}`);\n });\n };\n let promise;\n\n // if muted defaults to true\n // the only thing we can do is call play\n if (type === 'any' && !this.muted()) {\n promise = this.play();\n if (isPromise(promise)) {\n promise = promise.catch(resolveMuted);\n }\n } else if (type === 'muted' && !this.muted()) {\n promise = resolveMuted();\n } else {\n promise = this.play();\n }\n if (!isPromise(promise)) {\n return;\n }\n return promise.then(() => {\n this.trigger({\n type: 'autoplay-success',\n autoplay: type\n });\n }).catch(() => {\n this.trigger({\n type: 'autoplay-failure',\n autoplay: type\n });\n });\n }\n\n /**\n * Update the internal source caches so that we return the correct source from\n * `src()`, `currentSource()`, and `currentSources()`.\n *\n * > Note: `currentSources` will not be updated if the source that is passed in exists\n * in the current `currentSources` cache.\n *\n *\n * @param {Tech~SourceObject} srcObj\n * A string or object source to update our caches to.\n */\n updateSourceCaches_(srcObj = '') {\n let src = srcObj;\n let type = '';\n if (typeof src !== 'string') {\n src = srcObj.src;\n type = srcObj.type;\n }\n\n // make sure all the caches are set to default values\n // to prevent null checking\n this.cache_.source = this.cache_.source || {};\n this.cache_.sources = this.cache_.sources || [];\n\n // try to get the type of the src that was passed in\n if (src && !type) {\n type = findMimetype(this, src);\n }\n\n // update `currentSource` cache always\n this.cache_.source = merge({}, srcObj, {\n src,\n type\n });\n const matchingSources = this.cache_.sources.filter(s => s.src && s.src === src);\n const sourceElSources = [];\n const sourceEls = this.$$('source');\n const matchingSourceEls = [];\n for (let i = 0; i < sourceEls.length; i++) {\n const sourceObj = getAttributes(sourceEls[i]);\n sourceElSources.push(sourceObj);\n if (sourceObj.src && sourceObj.src === src) {\n matchingSourceEls.push(sourceObj.src);\n }\n }\n\n // if we have matching source els but not matching sources\n // the current source cache is not up to date\n if (matchingSourceEls.length && !matchingSources.length) {\n this.cache_.sources = sourceElSources;\n // if we don't have matching source or source els set the\n // sources cache to the `currentSource` cache\n } else if (!matchingSources.length) {\n this.cache_.sources = [this.cache_.source];\n }\n\n // update the tech `src` cache\n this.cache_.src = src;\n }\n\n /**\n * *EXPERIMENTAL* Fired when the source is set or changed on the {@link Tech}\n * causing the media element to reload.\n *\n * It will fire for the initial source and each subsequent source.\n * This event is a custom event from Video.js and is triggered by the {@link Tech}.\n *\n * The event object for this event contains a `src` property that will contain the source\n * that was available when the event was triggered. This is generally only necessary if Video.js\n * is switching techs while the source was being changed.\n *\n * It is also fired when `load` is called on the player (or media element)\n * because the {@link https://html.spec.whatwg.org/multipage/media.html#dom-media-load|specification for `load`}\n * says that the resource selection algorithm needs to be aborted and restarted.\n * In this case, it is very likely that the `src` property will be set to the\n * empty string `\"\"` to indicate we do not know what the source will be but\n * that it is changing.\n *\n * *This event is currently still experimental and may change in minor releases.*\n * __To use this, pass `enableSourceset` option to the player.__\n *\n * @event Player#sourceset\n * @type {Event}\n * @prop {string} src\n * The source url available when the `sourceset` was triggered.\n * It will be an empty string if we cannot know what the source is\n * but know that the source will change.\n */\n /**\n * Retrigger the `sourceset` event that was triggered by the {@link Tech}.\n *\n * @fires Player#sourceset\n * @listens Tech#sourceset\n * @private\n */\n handleTechSourceset_(event) {\n // only update the source cache when the source\n // was not updated using the player api\n if (!this.changingSrc_) {\n let updateSourceCaches = src => this.updateSourceCaches_(src);\n const playerSrc = this.currentSource().src;\n const eventSrc = event.src;\n\n // if we have a playerSrc that is not a blob, and a tech src that is a blob\n if (playerSrc && !/^blob:/.test(playerSrc) && /^blob:/.test(eventSrc)) {\n // if both the tech source and the player source were updated we assume\n // something like @videojs/http-streaming did the sourceset and skip updating the source cache.\n if (!this.lastSource_ || this.lastSource_.tech !== eventSrc && this.lastSource_.player !== playerSrc) {\n updateSourceCaches = () => {};\n }\n }\n\n // update the source to the initial source right away\n // in some cases this will be empty string\n updateSourceCaches(eventSrc);\n\n // if the `sourceset` `src` was an empty string\n // wait for a `loadstart` to update the cache to `currentSrc`.\n // If a sourceset happens before a `loadstart`, we reset the state\n if (!event.src) {\n this.tech_.any(['sourceset', 'loadstart'], e => {\n // if a sourceset happens before a `loadstart` there\n // is nothing to do as this `handleTechSourceset_`\n // will be called again and this will be handled there.\n if (e.type === 'sourceset') {\n return;\n }\n const techSrc = this.techGet_('currentSrc');\n this.lastSource_.tech = techSrc;\n this.updateSourceCaches_(techSrc);\n });\n }\n }\n this.lastSource_ = {\n player: this.currentSource().src,\n tech: event.src\n };\n this.trigger({\n src: event.src,\n type: 'sourceset'\n });\n }\n\n /**\n * Add/remove the vjs-has-started class\n *\n *\n * @param {boolean} request\n * - true: adds the class\n * - false: remove the class\n *\n * @return {boolean}\n * the boolean value of hasStarted_\n */\n hasStarted(request) {\n if (request === undefined) {\n // act as getter, if we have no request to change\n return this.hasStarted_;\n }\n if (request === this.hasStarted_) {\n return;\n }\n this.hasStarted_ = request;\n if (this.hasStarted_) {\n this.addClass('vjs-has-started');\n } else {\n this.removeClass('vjs-has-started');\n }\n }\n\n /**\n * Fired whenever the media begins or resumes playback\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-play}\n * @fires Player#play\n * @listens Tech#play\n * @private\n */\n handleTechPlay_() {\n this.removeClass('vjs-ended', 'vjs-paused');\n this.addClass('vjs-playing');\n\n // hide the poster when the user hits play\n this.hasStarted(true);\n /**\n * Triggered whenever an {@link Tech#play} event happens. Indicates that\n * playback has started or resumed.\n *\n * @event Player#play\n * @type {Event}\n */\n this.trigger('play');\n }\n\n /**\n * Retrigger the `ratechange` event that was triggered by the {@link Tech}.\n *\n * If there were any events queued while the playback rate was zero, fire\n * those events now.\n *\n * @private\n * @method Player#handleTechRateChange_\n * @fires Player#ratechange\n * @listens Tech#ratechange\n */\n handleTechRateChange_() {\n if (this.tech_.playbackRate() > 0 && this.cache_.lastPlaybackRate === 0) {\n this.queuedCallbacks_.forEach(queued => queued.callback(queued.event));\n this.queuedCallbacks_ = [];\n }\n this.cache_.lastPlaybackRate = this.tech_.playbackRate();\n /**\n * Fires when the playing speed of the audio/video is changed\n *\n * @event Player#ratechange\n * @type {event}\n */\n this.trigger('ratechange');\n }\n\n /**\n * Retrigger the `waiting` event that was triggered by the {@link Tech}.\n *\n * @fires Player#waiting\n * @listens Tech#waiting\n * @private\n */\n handleTechWaiting_() {\n this.addClass('vjs-waiting');\n /**\n * A readyState change on the DOM element has caused playback to stop.\n *\n * @event Player#waiting\n * @type {Event}\n */\n this.trigger('waiting');\n\n // Browsers may emit a timeupdate event after a waiting event. In order to prevent\n // premature removal of the waiting class, wait for the time to change.\n const timeWhenWaiting = this.currentTime();\n const timeUpdateListener = () => {\n if (timeWhenWaiting !== this.currentTime()) {\n this.removeClass('vjs-waiting');\n this.off('timeupdate', timeUpdateListener);\n }\n };\n this.on('timeupdate', timeUpdateListener);\n }\n\n /**\n * Retrigger the `canplay` event that was triggered by the {@link Tech}.\n * > Note: This is not consistent between browsers. See #1351\n *\n * @fires Player#canplay\n * @listens Tech#canplay\n * @private\n */\n handleTechCanPlay_() {\n this.removeClass('vjs-waiting');\n /**\n * The media has a readyState of HAVE_FUTURE_DATA or greater.\n *\n * @event Player#canplay\n * @type {Event}\n */\n this.trigger('canplay');\n }\n\n /**\n * Retrigger the `canplaythrough` event that was triggered by the {@link Tech}.\n *\n * @fires Player#canplaythrough\n * @listens Tech#canplaythrough\n * @private\n */\n handleTechCanPlayThrough_() {\n this.removeClass('vjs-waiting');\n /**\n * The media has a readyState of HAVE_ENOUGH_DATA or greater. This means that the\n * entire media file can be played without buffering.\n *\n * @event Player#canplaythrough\n * @type {Event}\n */\n this.trigger('canplaythrough');\n }\n\n /**\n * Retrigger the `playing` event that was triggered by the {@link Tech}.\n *\n * @fires Player#playing\n * @listens Tech#playing\n * @private\n */\n handleTechPlaying_() {\n this.removeClass('vjs-waiting');\n /**\n * The media is no longer blocked from playback, and has started playing.\n *\n * @event Player#playing\n * @type {Event}\n */\n this.trigger('playing');\n }\n\n /**\n * Retrigger the `seeking` event that was triggered by the {@link Tech}.\n *\n * @fires Player#seeking\n * @listens Tech#seeking\n * @private\n */\n handleTechSeeking_() {\n this.addClass('vjs-seeking');\n /**\n * Fired whenever the player is jumping to a new time\n *\n * @event Player#seeking\n * @type {Event}\n */\n this.trigger('seeking');\n }\n\n /**\n * Retrigger the `seeked` event that was triggered by the {@link Tech}.\n *\n * @fires Player#seeked\n * @listens Tech#seeked\n * @private\n */\n handleTechSeeked_() {\n this.removeClass('vjs-seeking', 'vjs-ended');\n /**\n * Fired when the player has finished jumping to a new time\n *\n * @event Player#seeked\n * @type {Event}\n */\n this.trigger('seeked');\n }\n\n /**\n * Retrigger the `pause` event that was triggered by the {@link Tech}.\n *\n * @fires Player#pause\n * @listens Tech#pause\n * @private\n */\n handleTechPause_() {\n this.removeClass('vjs-playing');\n this.addClass('vjs-paused');\n /**\n * Fired whenever the media has been paused\n *\n * @event Player#pause\n * @type {Event}\n */\n this.trigger('pause');\n }\n\n /**\n * Retrigger the `ended` event that was triggered by the {@link Tech}.\n *\n * @fires Player#ended\n * @listens Tech#ended\n * @private\n */\n handleTechEnded_() {\n this.addClass('vjs-ended');\n this.removeClass('vjs-waiting');\n if (this.options_.loop) {\n this.currentTime(0);\n this.play();\n } else if (!this.paused()) {\n this.pause();\n }\n\n /**\n * Fired when the end of the media resource is reached (currentTime == duration)\n *\n * @event Player#ended\n * @type {Event}\n */\n this.trigger('ended');\n }\n\n /**\n * Fired when the duration of the media resource is first known or changed\n *\n * @listens Tech#durationchange\n * @private\n */\n handleTechDurationChange_() {\n this.duration(this.techGet_('duration'));\n }\n\n /**\n * Handle a click on the media element to play/pause\n *\n * @param {Event} event\n * the event that caused this function to trigger\n *\n * @listens Tech#click\n * @private\n */\n handleTechClick_(event) {\n // When controls are disabled a click should not toggle playback because\n // the click is considered a control\n if (!this.controls_) {\n return;\n }\n if (this.options_ === undefined || this.options_.userActions === undefined || this.options_.userActions.click === undefined || this.options_.userActions.click !== false) {\n if (this.options_ !== undefined && this.options_.userActions !== undefined && typeof this.options_.userActions.click === 'function') {\n this.options_.userActions.click.call(this, event);\n } else if (this.paused()) {\n silencePromise(this.play());\n } else {\n this.pause();\n }\n }\n }\n\n /**\n * Handle a double-click on the media element to enter/exit fullscreen,\n * or exit documentPictureInPicture mode\n *\n * @param {Event} event\n * the event that caused this function to trigger\n *\n * @listens Tech#dblclick\n * @private\n */\n handleTechDoubleClick_(event) {\n if (!this.controls_) {\n return;\n }\n\n // we do not want to toggle fullscreen state\n // when double-clicking inside a control bar or a modal\n const inAllowedEls = Array.prototype.some.call(this.$$('.vjs-control-bar, .vjs-modal-dialog'), el => el.contains(event.target));\n if (!inAllowedEls) {\n /*\n * options.userActions.doubleClick\n *\n * If `undefined` or `true`, double-click toggles fullscreen if controls are present\n * Set to `false` to disable double-click handling\n * Set to a function to substitute an external double-click handler\n */\n if (this.options_ === undefined || this.options_.userActions === undefined || this.options_.userActions.doubleClick === undefined || this.options_.userActions.doubleClick !== false) {\n if (this.options_ !== undefined && this.options_.userActions !== undefined && typeof this.options_.userActions.doubleClick === 'function') {\n this.options_.userActions.doubleClick.call(this, event);\n } else if (this.isInPictureInPicture() && !document.pictureInPictureElement) {\n // Checking the presence of `window.documentPictureInPicture.window` complicates\n // tests, checking `document.pictureInPictureElement` also works. It wouldn't\n // be null in regular picture in picture.\n // Exit picture in picture mode. This gesture can't trigger pip on the main window.\n this.exitPictureInPicture();\n } else if (this.isFullscreen()) {\n this.exitFullscreen();\n } else {\n this.requestFullscreen();\n }\n }\n }\n }\n\n /**\n * Handle a tap on the media element. It will toggle the user\n * activity state, which hides and shows the controls.\n *\n * @listens Tech#tap\n * @private\n */\n handleTechTap_() {\n this.userActive(!this.userActive());\n }\n\n /**\n * Handle touch to start\n *\n * @listens Tech#touchstart\n * @private\n */\n handleTechTouchStart_() {\n this.userWasActive = this.userActive();\n }\n\n /**\n * Handle touch to move\n *\n * @listens Tech#touchmove\n * @private\n */\n handleTechTouchMove_() {\n if (this.userWasActive) {\n this.reportUserActivity();\n }\n }\n\n /**\n * Handle touch to end\n *\n * @param {Event} event\n * the touchend event that triggered\n * this function\n *\n * @listens Tech#touchend\n * @private\n */\n handleTechTouchEnd_(event) {\n // Stop the mouse events from also happening\n if (event.cancelable) {\n event.preventDefault();\n }\n }\n\n /**\n * @private\n */\n toggleFullscreenClass_() {\n if (this.isFullscreen()) {\n this.addClass('vjs-fullscreen');\n } else {\n this.removeClass('vjs-fullscreen');\n }\n }\n\n /**\n * when the document fschange event triggers it calls this\n */\n documentFullscreenChange_(e) {\n const targetPlayer = e.target.player;\n\n // if another player was fullscreen\n // do a null check for targetPlayer because older firefox's would put document as e.target\n if (targetPlayer && targetPlayer !== this) {\n return;\n }\n const el = this.el();\n let isFs = document[this.fsApi_.fullscreenElement] === el;\n if (!isFs && el.matches) {\n isFs = el.matches(':' + this.fsApi_.fullscreen);\n }\n this.isFullscreen(isFs);\n }\n\n /**\n * Handle Tech Fullscreen Change\n *\n * @param {Event} event\n * the fullscreenchange event that triggered this function\n *\n * @param {Object} data\n * the data that was sent with the event\n *\n * @private\n * @listens Tech#fullscreenchange\n * @fires Player#fullscreenchange\n */\n handleTechFullscreenChange_(event, data) {\n if (data) {\n if (data.nativeIOSFullscreen) {\n this.addClass('vjs-ios-native-fs');\n this.tech_.one('webkitendfullscreen', () => {\n this.removeClass('vjs-ios-native-fs');\n });\n }\n this.isFullscreen(data.isFullscreen);\n }\n }\n handleTechFullscreenError_(event, err) {\n this.trigger('fullscreenerror', err);\n }\n\n /**\n * @private\n */\n togglePictureInPictureClass_() {\n if (this.isInPictureInPicture()) {\n this.addClass('vjs-picture-in-picture');\n } else {\n this.removeClass('vjs-picture-in-picture');\n }\n }\n\n /**\n * Handle Tech Enter Picture-in-Picture.\n *\n * @param {Event} event\n * the enterpictureinpicture event that triggered this function\n *\n * @private\n * @listens Tech#enterpictureinpicture\n */\n handleTechEnterPictureInPicture_(event) {\n this.isInPictureInPicture(true);\n }\n\n /**\n * Handle Tech Leave Picture-in-Picture.\n *\n * @param {Event} event\n * the leavepictureinpicture event that triggered this function\n *\n * @private\n * @listens Tech#leavepictureinpicture\n */\n handleTechLeavePictureInPicture_(event) {\n this.isInPictureInPicture(false);\n }\n\n /**\n * Fires when an error occurred during the loading of an audio/video.\n *\n * @private\n * @listens Tech#error\n */\n handleTechError_() {\n const error = this.tech_.error();\n if (error) {\n this.error(error);\n }\n }\n\n /**\n * Retrigger the `textdata` event that was triggered by the {@link Tech}.\n *\n * @fires Player#textdata\n * @listens Tech#textdata\n * @private\n */\n handleTechTextData_() {\n let data = null;\n if (arguments.length > 1) {\n data = arguments[1];\n }\n\n /**\n * Fires when we get a textdata event from tech\n *\n * @event Player#textdata\n * @type {Event}\n */\n this.trigger('textdata', data);\n }\n\n /**\n * Get object for cached values.\n *\n * @return {Object}\n * get the current object cache\n */\n getCache() {\n return this.cache_;\n }\n\n /**\n * Resets the internal cache object.\n *\n * Using this function outside the player constructor or reset method may\n * have unintended side-effects.\n *\n * @private\n */\n resetCache_() {\n this.cache_ = {\n // Right now, the currentTime is not _really_ cached because it is always\n // retrieved from the tech (see: currentTime). However, for completeness,\n // we set it to zero here to ensure that if we do start actually caching\n // it, we reset it along with everything else.\n currentTime: 0,\n initTime: 0,\n inactivityTimeout: this.options_.inactivityTimeout,\n duration: NaN,\n lastVolume: 1,\n lastPlaybackRate: this.defaultPlaybackRate(),\n media: null,\n src: '',\n source: {},\n sources: [],\n playbackRates: [],\n volume: 1\n };\n }\n\n /**\n * Pass values to the playback tech\n *\n * @param {string} [method]\n * the method to call\n *\n * @param {Object} [arg]\n * the argument to pass\n *\n * @private\n */\n techCall_(method, arg) {\n // If it's not ready yet, call method when it is\n\n this.ready(function () {\n if (method in allowedSetters) {\n return set(this.middleware_, this.tech_, method, arg);\n } else if (method in allowedMediators) {\n return mediate(this.middleware_, this.tech_, method, arg);\n }\n try {\n if (this.tech_) {\n this.tech_[method](arg);\n }\n } catch (e) {\n log(e);\n throw e;\n }\n }, true);\n }\n\n /**\n * Mediate attempt to call playback tech method\n * and return the value of the method called.\n *\n * @param {string} method\n * Tech method\n *\n * @return {*}\n * Value returned by the tech method called, undefined if tech\n * is not ready or tech method is not present\n *\n * @private\n */\n techGet_(method) {\n if (!this.tech_ || !this.tech_.isReady_) {\n return;\n }\n if (method in allowedGetters) {\n return get(this.middleware_, this.tech_, method);\n } else if (method in allowedMediators) {\n return mediate(this.middleware_, this.tech_, method);\n }\n\n // Log error when playback tech object is present but method\n // is undefined or unavailable\n try {\n return this.tech_[method]();\n } catch (e) {\n // When building additional tech libs, an expected method may not be defined yet\n if (this.tech_[method] === undefined) {\n log(`Video.js: ${method} method not defined for ${this.techName_} playback technology.`, e);\n throw e;\n }\n\n // When a method isn't available on the object it throws a TypeError\n if (e.name === 'TypeError') {\n log(`Video.js: ${method} unavailable on ${this.techName_} playback technology element.`, e);\n this.tech_.isReady_ = false;\n throw e;\n }\n\n // If error unknown, just log and throw\n log(e);\n throw e;\n }\n }\n\n /**\n * Attempt to begin playback at the first opportunity.\n *\n * @return {Promise|undefined}\n * Returns a promise if the browser supports Promises (or one\n * was passed in as an option). This promise will be resolved on\n * the return value of play. If this is undefined it will fulfill the\n * promise chain otherwise the promise chain will be fulfilled when\n * the promise from play is fulfilled.\n */\n play() {\n return new Promise(resolve => {\n this.play_(resolve);\n });\n }\n\n /**\n * The actual logic for play, takes a callback that will be resolved on the\n * return value of play. This allows us to resolve to the play promise if there\n * is one on modern browsers.\n *\n * @private\n * @param {Function} [callback]\n * The callback that should be called when the techs play is actually called\n */\n play_(callback = silencePromise) {\n this.playCallbacks_.push(callback);\n const isSrcReady = Boolean(!this.changingSrc_ && (this.src() || this.currentSrc()));\n const isSafariOrIOS = Boolean(IS_ANY_SAFARI || IS_IOS);\n\n // treat calls to play_ somewhat like the `one` event function\n if (this.waitToPlay_) {\n this.off(['ready', 'loadstart'], this.waitToPlay_);\n this.waitToPlay_ = null;\n }\n\n // if the player/tech is not ready or the src itself is not ready\n // queue up a call to play on `ready` or `loadstart`\n if (!this.isReady_ || !isSrcReady) {\n this.waitToPlay_ = e => {\n this.play_();\n };\n this.one(['ready', 'loadstart'], this.waitToPlay_);\n\n // if we are in Safari, there is a high chance that loadstart will trigger after the gesture timeperiod\n // in that case, we need to prime the video element by calling load so it'll be ready in time\n if (!isSrcReady && isSafariOrIOS) {\n this.load();\n }\n return;\n }\n\n // If the player/tech is ready and we have a source, we can attempt playback.\n const val = this.techGet_('play');\n\n // For native playback, reset the progress bar if we get a play call from a replay.\n const isNativeReplay = isSafariOrIOS && this.hasClass('vjs-ended');\n if (isNativeReplay) {\n this.resetProgressBar_();\n }\n // play was terminated if the returned value is null\n if (val === null) {\n this.runPlayTerminatedQueue_();\n } else {\n this.runPlayCallbacks_(val);\n }\n }\n\n /**\n * These functions will be run when if play is terminated. If play\n * runPlayCallbacks_ is run these function will not be run. This allows us\n * to differentiate between a terminated play and an actual call to play.\n */\n runPlayTerminatedQueue_() {\n const queue = this.playTerminatedQueue_.slice(0);\n this.playTerminatedQueue_ = [];\n queue.forEach(function (q) {\n q();\n });\n }\n\n /**\n * When a callback to play is delayed we have to run these\n * callbacks when play is actually called on the tech. This function\n * runs the callbacks that were delayed and accepts the return value\n * from the tech.\n *\n * @param {undefined|Promise} val\n * The return value from the tech.\n */\n runPlayCallbacks_(val) {\n const callbacks = this.playCallbacks_.slice(0);\n this.playCallbacks_ = [];\n // clear play terminatedQueue since we finished a real play\n this.playTerminatedQueue_ = [];\n callbacks.forEach(function (cb) {\n cb(val);\n });\n }\n\n /**\n * Pause the video playback\n */\n pause() {\n this.techCall_('pause');\n }\n\n /**\n * Check if the player is paused or has yet to play\n *\n * @return {boolean}\n * - false: if the media is currently playing\n * - true: if media is not currently playing\n */\n paused() {\n // The initial state of paused should be true (in Safari it's actually false)\n return this.techGet_('paused') === false ? false : true;\n }\n\n /**\n * Get a TimeRange object representing the current ranges of time that the user\n * has played.\n *\n * @return {TimeRange}\n * A time range object that represents all the increments of time that have\n * been played.\n */\n played() {\n return this.techGet_('played') || createTimeRanges(0, 0);\n }\n\n /**\n * Sets or returns whether or not the user is \"scrubbing\". Scrubbing is\n * when the user has clicked the progress bar handle and is\n * dragging it along the progress bar.\n *\n * @param {boolean} [isScrubbing]\n * whether the user is or is not scrubbing\n *\n * @return {boolean|undefined}\n * - The value of scrubbing when getting\n * - Nothing when setting\n */\n scrubbing(isScrubbing) {\n if (typeof isScrubbing === 'undefined') {\n return this.scrubbing_;\n }\n this.scrubbing_ = !!isScrubbing;\n this.techCall_('setScrubbing', this.scrubbing_);\n if (isScrubbing) {\n this.addClass('vjs-scrubbing');\n } else {\n this.removeClass('vjs-scrubbing');\n }\n }\n\n /**\n * Get or set the current time (in seconds)\n *\n * @param {number|string} [seconds]\n * The time to seek to in seconds\n *\n * @return {number|undefined}\n * - the current time in seconds when getting\n * - Nothing when setting\n */\n currentTime(seconds) {\n if (seconds === undefined) {\n // cache last currentTime and return. default to 0 seconds\n //\n // Caching the currentTime is meant to prevent a massive amount of reads on the tech's\n // currentTime when scrubbing, but may not provide much performance benefit after all.\n // Should be tested. Also something has to read the actual current time or the cache will\n // never get updated.\n this.cache_.currentTime = this.techGet_('currentTime') || 0;\n return this.cache_.currentTime;\n }\n if (seconds < 0) {\n seconds = 0;\n }\n if (!this.isReady_ || this.changingSrc_ || !this.tech_ || !this.tech_.isReady_) {\n this.cache_.initTime = seconds;\n this.off('canplay', this.boundApplyInitTime_);\n this.one('canplay', this.boundApplyInitTime_);\n return;\n }\n this.techCall_('setCurrentTime', seconds);\n this.cache_.initTime = 0;\n if (isFinite(seconds)) {\n this.cache_.currentTime = Number(seconds);\n }\n }\n\n /**\n * Apply the value of initTime stored in cache as currentTime.\n *\n * @private\n */\n applyInitTime_() {\n this.currentTime(this.cache_.initTime);\n }\n\n /**\n * Normally gets the length in time of the video in seconds;\n * in all but the rarest use cases an argument will NOT be passed to the method\n *\n * > **NOTE**: The video must have started loading before the duration can be\n * known, and depending on preload behaviour may not be known until the video starts\n * playing.\n *\n * @fires Player#durationchange\n *\n * @param {number} [seconds]\n * The duration of the video to set in seconds\n *\n * @return {number|undefined}\n * - The duration of the video in seconds when getting\n * - Nothing when setting\n */\n duration(seconds) {\n if (seconds === undefined) {\n // return NaN if the duration is not known\n return this.cache_.duration !== undefined ? this.cache_.duration : NaN;\n }\n seconds = parseFloat(seconds);\n\n // Standardize on Infinity for signaling video is live\n if (seconds < 0) {\n seconds = Infinity;\n }\n if (seconds !== this.cache_.duration) {\n // Cache the last set value for optimized scrubbing\n this.cache_.duration = seconds;\n if (seconds === Infinity) {\n this.addClass('vjs-live');\n } else {\n this.removeClass('vjs-live');\n }\n if (!isNaN(seconds)) {\n // Do not fire durationchange unless the duration value is known.\n // @see [Spec]{@link https://www.w3.org/TR/2011/WD-html5-20110113/video.html#media-element-load-algorithm}\n\n /**\n * @event Player#durationchange\n * @type {Event}\n */\n this.trigger('durationchange');\n }\n }\n }\n\n /**\n * Calculates how much time is left in the video. Not part\n * of the native video API.\n *\n * @return {number}\n * The time remaining in seconds\n */\n remainingTime() {\n return this.duration() - this.currentTime();\n }\n\n /**\n * A remaining time function that is intended to be used when\n * the time is to be displayed directly to the user.\n *\n * @return {number}\n * The rounded time remaining in seconds\n */\n remainingTimeDisplay() {\n return Math.floor(this.duration()) - Math.floor(this.currentTime());\n }\n\n //\n // Kind of like an array of portions of the video that have been downloaded.\n\n /**\n * Get a TimeRange object with an array of the times of the video\n * that have been downloaded. If you just want the percent of the\n * video that's been downloaded, use bufferedPercent.\n *\n * @see [Buffered Spec]{@link http://dev.w3.org/html5/spec/video.html#dom-media-buffered}\n *\n * @return {TimeRange}\n * A mock {@link TimeRanges} object (following HTML spec)\n */\n buffered() {\n let buffered = this.techGet_('buffered');\n if (!buffered || !buffered.length) {\n buffered = createTimeRanges(0, 0);\n }\n return buffered;\n }\n\n /**\n * Get the TimeRanges of the media that are currently available\n * for seeking to.\n *\n * @see [Seekable Spec]{@link https://html.spec.whatwg.org/multipage/media.html#dom-media-seekable}\n *\n * @return {TimeRange}\n * A mock {@link TimeRanges} object (following HTML spec)\n */\n seekable() {\n let seekable = this.techGet_('seekable');\n if (!seekable || !seekable.length) {\n seekable = createTimeRanges(0, 0);\n }\n return seekable;\n }\n\n /**\n * Returns whether the player is in the \"seeking\" state.\n *\n * @return {boolean} True if the player is in the seeking state, false if not.\n */\n seeking() {\n return this.techGet_('seeking');\n }\n\n /**\n * Returns whether the player is in the \"ended\" state.\n *\n * @return {boolean} True if the player is in the ended state, false if not.\n */\n ended() {\n return this.techGet_('ended');\n }\n\n /**\n * Returns the current state of network activity for the element, from\n * the codes in the list below.\n * - NETWORK_EMPTY (numeric value 0)\n * The element has not yet been initialised. All attributes are in\n * their initial states.\n * - NETWORK_IDLE (numeric value 1)\n * The element's resource selection algorithm is active and has\n * selected a resource, but it is not actually using the network at\n * this time.\n * - NETWORK_LOADING (numeric value 2)\n * The user agent is actively trying to download data.\n * - NETWORK_NO_SOURCE (numeric value 3)\n * The element's resource selection algorithm is active, but it has\n * not yet found a resource to use.\n *\n * @see https://html.spec.whatwg.org/multipage/embedded-content.html#network-states\n * @return {number} the current network activity state\n */\n networkState() {\n return this.techGet_('networkState');\n }\n\n /**\n * Returns a value that expresses the current state of the element\n * with respect to rendering the current playback position, from the\n * codes in the list below.\n * - HAVE_NOTHING (numeric value 0)\n * No information regarding the media resource is available.\n * - HAVE_METADATA (numeric value 1)\n * Enough of the resource has been obtained that the duration of the\n * resource is available.\n * - HAVE_CURRENT_DATA (numeric value 2)\n * Data for the immediate current playback position is available.\n * - HAVE_FUTURE_DATA (numeric value 3)\n * Data for the immediate current playback position is available, as\n * well as enough data for the user agent to advance the current\n * playback position in the direction of playback.\n * - HAVE_ENOUGH_DATA (numeric value 4)\n * The user agent estimates that enough data is available for\n * playback to proceed uninterrupted.\n *\n * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-readystate\n * @return {number} the current playback rendering state\n */\n readyState() {\n return this.techGet_('readyState');\n }\n\n /**\n * Get the percent (as a decimal) of the video that's been downloaded.\n * This method is not a part of the native HTML video API.\n *\n * @return {number}\n * A decimal between 0 and 1 representing the percent\n * that is buffered 0 being 0% and 1 being 100%\n */\n bufferedPercent() {\n return bufferedPercent(this.buffered(), this.duration());\n }\n\n /**\n * Get the ending time of the last buffered time range\n * This is used in the progress bar to encapsulate all time ranges.\n *\n * @return {number}\n * The end of the last buffered time range\n */\n bufferedEnd() {\n const buffered = this.buffered();\n const duration = this.duration();\n let end = buffered.end(buffered.length - 1);\n if (end > duration) {\n end = duration;\n }\n return end;\n }\n\n /**\n * Get or set the current volume of the media\n *\n * @param {number} [percentAsDecimal]\n * The new volume as a decimal percent:\n * - 0 is muted/0%/off\n * - 1.0 is 100%/full\n * - 0.5 is half volume or 50%\n *\n * @return {number|undefined}\n * The current volume as a percent when getting\n */\n volume(percentAsDecimal) {\n let vol;\n if (percentAsDecimal !== undefined) {\n // Force value to between 0 and 1\n vol = Math.max(0, Math.min(1, percentAsDecimal));\n this.cache_.volume = vol;\n this.techCall_('setVolume', vol);\n if (vol > 0) {\n this.lastVolume_(vol);\n }\n return;\n }\n\n // Default to 1 when returning current volume.\n vol = parseFloat(this.techGet_('volume'));\n return isNaN(vol) ? 1 : vol;\n }\n\n /**\n * Get the current muted state, or turn mute on or off\n *\n * @param {boolean} [muted]\n * - true to mute\n * - false to unmute\n *\n * @return {boolean|undefined}\n * - true if mute is on and getting\n * - false if mute is off and getting\n * - nothing if setting\n */\n muted(muted) {\n if (muted !== undefined) {\n this.techCall_('setMuted', muted);\n return;\n }\n return this.techGet_('muted') || false;\n }\n\n /**\n * Get the current defaultMuted state, or turn defaultMuted on or off. defaultMuted\n * indicates the state of muted on initial playback.\n *\n * ```js\n * var myPlayer = videojs('some-player-id');\n *\n * myPlayer.src(\"http://www.example.com/path/to/video.mp4\");\n *\n * // get, should be false\n * console.log(myPlayer.defaultMuted());\n * // set to true\n * myPlayer.defaultMuted(true);\n * // get should be true\n * console.log(myPlayer.defaultMuted());\n * ```\n *\n * @param {boolean} [defaultMuted]\n * - true to mute\n * - false to unmute\n *\n * @return {boolean|undefined}\n * - true if defaultMuted is on and getting\n * - false if defaultMuted is off and getting\n * - Nothing when setting\n */\n defaultMuted(defaultMuted) {\n if (defaultMuted !== undefined) {\n this.techCall_('setDefaultMuted', defaultMuted);\n }\n return this.techGet_('defaultMuted') || false;\n }\n\n /**\n * Get the last volume, or set it\n *\n * @param {number} [percentAsDecimal]\n * The new last volume as a decimal percent:\n * - 0 is muted/0%/off\n * - 1.0 is 100%/full\n * - 0.5 is half volume or 50%\n *\n * @return {number|undefined}\n * - The current value of lastVolume as a percent when getting\n * - Nothing when setting\n *\n * @private\n */\n lastVolume_(percentAsDecimal) {\n if (percentAsDecimal !== undefined && percentAsDecimal !== 0) {\n this.cache_.lastVolume = percentAsDecimal;\n return;\n }\n return this.cache_.lastVolume;\n }\n\n /**\n * Check if current tech can support native fullscreen\n * (e.g. with built in controls like iOS)\n *\n * @return {boolean}\n * if native fullscreen is supported\n */\n supportsFullScreen() {\n return this.techGet_('supportsFullScreen') || false;\n }\n\n /**\n * Check if the player is in fullscreen mode or tell the player that it\n * is or is not in fullscreen mode.\n *\n * > NOTE: As of the latest HTML5 spec, isFullscreen is no longer an official\n * property and instead document.fullscreenElement is used. But isFullscreen is\n * still a valuable property for internal player workings.\n *\n * @param {boolean} [isFS]\n * Set the players current fullscreen state\n *\n * @return {boolean|undefined}\n * - true if fullscreen is on and getting\n * - false if fullscreen is off and getting\n * - Nothing when setting\n */\n isFullscreen(isFS) {\n if (isFS !== undefined) {\n const oldValue = this.isFullscreen_;\n this.isFullscreen_ = Boolean(isFS);\n\n // if we changed fullscreen state and we're in prefixed mode, trigger fullscreenchange\n // this is the only place where we trigger fullscreenchange events for older browsers\n // fullWindow mode is treated as a prefixed event and will get a fullscreenchange event as well\n if (this.isFullscreen_ !== oldValue && this.fsApi_.prefixed) {\n /**\n * @event Player#fullscreenchange\n * @type {Event}\n */\n this.trigger('fullscreenchange');\n }\n this.toggleFullscreenClass_();\n return;\n }\n return this.isFullscreen_;\n }\n\n /**\n * Increase the size of the video to full screen\n * In some browsers, full screen is not supported natively, so it enters\n * \"full window mode\", where the video fills the browser window.\n * In browsers and devices that support native full screen, sometimes the\n * browser's default controls will be shown, and not the Video.js custom skin.\n * This includes most mobile devices (iOS, Android) and older versions of\n * Safari.\n *\n * @param {Object} [fullscreenOptions]\n * Override the player fullscreen options\n *\n * @fires Player#fullscreenchange\n */\n requestFullscreen(fullscreenOptions) {\n if (this.isInPictureInPicture()) {\n this.exitPictureInPicture();\n }\n const self = this;\n return new Promise((resolve, reject) => {\n function offHandler() {\n self.off('fullscreenerror', errorHandler);\n self.off('fullscreenchange', changeHandler);\n }\n function changeHandler() {\n offHandler();\n resolve();\n }\n function errorHandler(e, err) {\n offHandler();\n reject(err);\n }\n self.one('fullscreenchange', changeHandler);\n self.one('fullscreenerror', errorHandler);\n const promise = self.requestFullscreenHelper_(fullscreenOptions);\n if (promise) {\n promise.then(offHandler, offHandler);\n promise.then(resolve, reject);\n }\n });\n }\n requestFullscreenHelper_(fullscreenOptions) {\n let fsOptions;\n\n // Only pass fullscreen options to requestFullscreen in spec-compliant browsers.\n // Use defaults or player configured option unless passed directly to this method.\n if (!this.fsApi_.prefixed) {\n fsOptions = this.options_.fullscreen && this.options_.fullscreen.options || {};\n if (fullscreenOptions !== undefined) {\n fsOptions = fullscreenOptions;\n }\n }\n\n // This method works as follows:\n // 1. if a fullscreen api is available, use it\n // 1. call requestFullscreen with potential options\n // 2. if we got a promise from above, use it to update isFullscreen()\n // 2. otherwise, if the tech supports fullscreen, call `enterFullScreen` on it.\n // This is particularly used for iPhone, older iPads, and non-safari browser on iOS.\n // 3. otherwise, use \"fullWindow\" mode\n if (this.fsApi_.requestFullscreen) {\n const promise = this.el_[this.fsApi_.requestFullscreen](fsOptions);\n\n // Even on browsers with promise support this may not return a promise\n if (promise) {\n promise.then(() => this.isFullscreen(true), () => this.isFullscreen(false));\n }\n return promise;\n } else if (this.tech_.supportsFullScreen() && !this.options_.preferFullWindow === true) {\n // we can't take the video.js controls fullscreen but we can go fullscreen\n // with native controls\n this.techCall_('enterFullScreen');\n } else {\n // fullscreen isn't supported so we'll just stretch the video element to\n // fill the viewport\n this.enterFullWindow();\n }\n }\n\n /**\n * Return the video to its normal size after having been in full screen mode\n *\n * @fires Player#fullscreenchange\n */\n exitFullscreen() {\n const self = this;\n return new Promise((resolve, reject) => {\n function offHandler() {\n self.off('fullscreenerror', errorHandler);\n self.off('fullscreenchange', changeHandler);\n }\n function changeHandler() {\n offHandler();\n resolve();\n }\n function errorHandler(e, err) {\n offHandler();\n reject(err);\n }\n self.one('fullscreenchange', changeHandler);\n self.one('fullscreenerror', errorHandler);\n const promise = self.exitFullscreenHelper_();\n if (promise) {\n promise.then(offHandler, offHandler);\n // map the promise to our resolve/reject methods\n promise.then(resolve, reject);\n }\n });\n }\n exitFullscreenHelper_() {\n if (this.fsApi_.requestFullscreen) {\n const promise = document[this.fsApi_.exitFullscreen]();\n\n // Even on browsers with promise support this may not return a promise\n if (promise) {\n // we're splitting the promise here, so, we want to catch the\n // potential error so that this chain doesn't have unhandled errors\n silencePromise(promise.then(() => this.isFullscreen(false)));\n }\n return promise;\n } else if (this.tech_.supportsFullScreen() && !this.options_.preferFullWindow === true) {\n this.techCall_('exitFullScreen');\n } else {\n this.exitFullWindow();\n }\n }\n\n /**\n * When fullscreen isn't supported we can stretch the\n * video container to as wide as the browser will let us.\n *\n * @fires Player#enterFullWindow\n */\n enterFullWindow() {\n this.isFullscreen(true);\n this.isFullWindow = true;\n\n // Storing original doc overflow value to return to when fullscreen is off\n this.docOrigOverflow = document.documentElement.style.overflow;\n\n // Add listener for esc key to exit fullscreen\n on(document, 'keydown', this.boundFullWindowOnEscKey_);\n\n // Hide any scroll bars\n document.documentElement.style.overflow = 'hidden';\n\n // Apply fullscreen styles\n addClass(document.body, 'vjs-full-window');\n\n /**\n * @event Player#enterFullWindow\n * @type {Event}\n */\n this.trigger('enterFullWindow');\n }\n\n /**\n * Check for call to either exit full window or\n * full screen on ESC key\n *\n * @param {string} event\n * Event to check for key press\n */\n fullWindowOnEscKey(event) {\n if (event.key === 'Escape') {\n if (this.isFullscreen() === true) {\n if (!this.isFullWindow) {\n this.exitFullscreen();\n } else {\n this.exitFullWindow();\n }\n }\n }\n }\n\n /**\n * Exit full window\n *\n * @fires Player#exitFullWindow\n */\n exitFullWindow() {\n this.isFullscreen(false);\n this.isFullWindow = false;\n off(document, 'keydown', this.boundFullWindowOnEscKey_);\n\n // Unhide scroll bars.\n document.documentElement.style.overflow = this.docOrigOverflow;\n\n // Remove fullscreen styles\n removeClass(document.body, 'vjs-full-window');\n\n // Resize the box, controller, and poster to original sizes\n // this.positionAll();\n /**\n * @event Player#exitFullWindow\n * @type {Event}\n */\n this.trigger('exitFullWindow');\n }\n\n /**\n * Get or set disable Picture-in-Picture mode.\n *\n * @param {boolean} [value]\n * - true will disable Picture-in-Picture mode\n * - false will enable Picture-in-Picture mode\n */\n disablePictureInPicture(value) {\n if (value === undefined) {\n return this.techGet_('disablePictureInPicture');\n }\n this.techCall_('setDisablePictureInPicture', value);\n this.options_.disablePictureInPicture = value;\n this.trigger('disablepictureinpicturechanged');\n }\n\n /**\n * Check if the player is in Picture-in-Picture mode or tell the player that it\n * is or is not in Picture-in-Picture mode.\n *\n * @param {boolean} [isPiP]\n * Set the players current Picture-in-Picture state\n *\n * @return {boolean|undefined}\n * - true if Picture-in-Picture is on and getting\n * - false if Picture-in-Picture is off and getting\n * - nothing if setting\n */\n isInPictureInPicture(isPiP) {\n if (isPiP !== undefined) {\n this.isInPictureInPicture_ = !!isPiP;\n this.togglePictureInPictureClass_();\n return;\n }\n return !!this.isInPictureInPicture_;\n }\n\n /**\n * Create a floating video window always on top of other windows so that users may\n * continue consuming media while they interact with other content sites, or\n * applications on their device.\n *\n * This can use document picture-in-picture or element picture in picture\n *\n * Set `enableDocumentPictureInPicture` to `true` to use docPiP on a supported browser\n * Else set `disablePictureInPicture` to `false` to disable elPiP on a supported browser\n *\n *\n * @see [Spec]{@link https://w3c.github.io/picture-in-picture/}\n * @see [Spec]{@link https://wicg.github.io/document-picture-in-picture/}\n *\n * @fires Player#enterpictureinpicture\n *\n * @return {Promise}\n * A promise with a Picture-in-Picture window.\n */\n requestPictureInPicture() {\n if (this.options_.enableDocumentPictureInPicture && window.documentPictureInPicture) {\n const pipContainer = document.createElement(this.el().tagName);\n pipContainer.classList = this.el().classList;\n pipContainer.classList.add('vjs-pip-container');\n if (this.posterImage) {\n pipContainer.appendChild(this.posterImage.el().cloneNode(true));\n }\n if (this.titleBar) {\n pipContainer.appendChild(this.titleBar.el().cloneNode(true));\n }\n pipContainer.appendChild(createEl('p', {\n className: 'vjs-pip-text'\n }, {}, this.localize('Playing in picture-in-picture')));\n return window.documentPictureInPicture.requestWindow({\n // The aspect ratio won't be correct, Chrome bug https://crbug.com/1407629\n width: this.videoWidth(),\n height: this.videoHeight()\n }).then(pipWindow => {\n copyStyleSheetsToWindow(pipWindow);\n this.el_.parentNode.insertBefore(pipContainer, this.el_);\n pipWindow.document.body.appendChild(this.el_);\n pipWindow.document.body.classList.add('vjs-pip-window');\n this.player_.isInPictureInPicture(true);\n this.player_.trigger({\n type: 'enterpictureinpicture',\n pipWindow\n });\n\n // Listen for the PiP closing event to move the video back.\n pipWindow.addEventListener('pagehide', event => {\n const pipVideo = event.target.querySelector('.video-js');\n pipContainer.parentNode.replaceChild(pipVideo, pipContainer);\n this.player_.isInPictureInPicture(false);\n this.player_.trigger('leavepictureinpicture');\n });\n return pipWindow;\n });\n }\n if ('pictureInPictureEnabled' in document && this.disablePictureInPicture() === false) {\n /**\n * This event fires when the player enters picture in picture mode\n *\n * @event Player#enterpictureinpicture\n * @type {Event}\n */\n return this.techGet_('requestPictureInPicture');\n }\n return Promise.reject('No PiP mode is available');\n }\n\n /**\n * Exit Picture-in-Picture mode.\n *\n * @see [Spec]{@link https://wicg.github.io/picture-in-picture}\n *\n * @fires Player#leavepictureinpicture\n *\n * @return {Promise}\n * A promise.\n */\n exitPictureInPicture() {\n if (window.documentPictureInPicture && window.documentPictureInPicture.window) {\n // With documentPictureInPicture, Player#leavepictureinpicture is fired in the pagehide handler\n window.documentPictureInPicture.window.close();\n return Promise.resolve();\n }\n if ('pictureInPictureEnabled' in document) {\n /**\n * This event fires when the player leaves picture in picture mode\n *\n * @event Player#leavepictureinpicture\n * @type {Event}\n */\n return document.exitPictureInPicture();\n }\n }\n\n /**\n * Called when this Player has focus and a key gets pressed down, or when\n * any Component of this player receives a key press that it doesn't handle.\n * This allows player-wide hotkeys (either as defined below, or optionally\n * by an external function).\n *\n * @param {KeyboardEvent} event\n * The `keydown` event that caused this function to be called.\n *\n * @listens keydown\n */\n handleKeyDown(event) {\n const {\n userActions\n } = this.options_;\n\n // Bail out if hotkeys are not configured.\n if (!userActions || !userActions.hotkeys) {\n return;\n }\n\n // Function that determines whether or not to exclude an element from\n // hotkeys handling.\n const excludeElement = el => {\n const tagName = el.tagName.toLowerCase();\n\n // The first and easiest test is for `contenteditable` elements.\n if (el.isContentEditable) {\n return true;\n }\n\n // Inputs matching these types will still trigger hotkey handling as\n // they are not text inputs.\n const allowedInputTypes = ['button', 'checkbox', 'hidden', 'radio', 'reset', 'submit'];\n if (tagName === 'input') {\n return allowedInputTypes.indexOf(el.type) === -1;\n }\n\n // The final test is by tag name. These tags will be excluded entirely.\n const excludedTags = ['textarea'];\n return excludedTags.indexOf(tagName) !== -1;\n };\n\n // Bail out if the user is focused on an interactive form element.\n if (excludeElement(this.el_.ownerDocument.activeElement)) {\n return;\n }\n if (typeof userActions.hotkeys === 'function') {\n userActions.hotkeys.call(this, event);\n } else {\n this.handleHotkeys(event);\n }\n }\n\n /**\n * Called when this Player receives a hotkey keydown event.\n * Supported player-wide hotkeys are:\n *\n * f - toggle fullscreen\n * m - toggle mute\n * k or Space - toggle play/pause\n *\n * @param {Event} event\n * The `keydown` event that caused this function to be called.\n */\n handleHotkeys(event) {\n const hotkeys = this.options_.userActions ? this.options_.userActions.hotkeys : {};\n\n // set fullscreenKey, muteKey, playPauseKey from `hotkeys`, use defaults if not set\n const {\n fullscreenKey = keydownEvent => event.key.toLowerCase() === 'f',\n muteKey = keydownEvent => event.key.toLowerCase() === 'm',\n playPauseKey = keydownEvent => event.key.toLowerCase() === 'k' || event.key.toLowerCase() === ' '\n } = hotkeys;\n if (fullscreenKey.call(this, event)) {\n event.preventDefault();\n event.stopPropagation();\n const FSToggle = Component.getComponent('FullscreenToggle');\n if (document[this.fsApi_.fullscreenEnabled] !== false) {\n FSToggle.prototype.handleClick.call(this, event);\n }\n } else if (muteKey.call(this, event)) {\n event.preventDefault();\n event.stopPropagation();\n const MuteToggle = Component.getComponent('MuteToggle');\n MuteToggle.prototype.handleClick.call(this, event);\n } else if (playPauseKey.call(this, event)) {\n event.preventDefault();\n event.stopPropagation();\n const PlayToggle = Component.getComponent('PlayToggle');\n PlayToggle.prototype.handleClick.call(this, event);\n }\n }\n\n /**\n * Check whether the player can play a given mimetype\n *\n * @see https://www.w3.org/TR/2011/WD-html5-20110113/video.html#dom-navigator-canplaytype\n *\n * @param {string} type\n * The mimetype to check\n *\n * @return {string}\n * 'probably', 'maybe', or '' (empty string)\n */\n canPlayType(type) {\n let can;\n\n // Loop through each playback technology in the options order\n for (let i = 0, j = this.options_.techOrder; i < j.length; i++) {\n const techName = j[i];\n let tech = Tech.getTech(techName);\n\n // Support old behavior of techs being registered as components.\n // Remove once that deprecated behavior is removed.\n if (!tech) {\n tech = Component.getComponent(techName);\n }\n\n // Check if the current tech is defined before continuing\n if (!tech) {\n log.error(`The \"${techName}\" tech is undefined. Skipped browser support check for that tech.`);\n continue;\n }\n\n // Check if the browser supports this technology\n if (tech.isSupported()) {\n can = tech.canPlayType(type);\n if (can) {\n return can;\n }\n }\n }\n return '';\n }\n\n /**\n * Select source based on tech-order or source-order\n * Uses source-order selection if `options.sourceOrder` is truthy. Otherwise,\n * defaults to tech-order selection\n *\n * @param {Array} sources\n * The sources for a media asset\n *\n * @return {Object|boolean}\n * Object of source and tech order or false\n */\n selectSource(sources) {\n // Get only the techs specified in `techOrder` that exist and are supported by the\n // current platform\n const techs = this.options_.techOrder.map(techName => {\n return [techName, Tech.getTech(techName)];\n }).filter(([techName, tech]) => {\n // Check if the current tech is defined before continuing\n if (tech) {\n // Check if the browser supports this technology\n return tech.isSupported();\n }\n log.error(`The \"${techName}\" tech is undefined. Skipped browser support check for that tech.`);\n return false;\n });\n\n // Iterate over each `innerArray` element once per `outerArray` element and execute\n // `tester` with both. If `tester` returns a non-falsy value, exit early and return\n // that value.\n const findFirstPassingTechSourcePair = function (outerArray, innerArray, tester) {\n let found;\n outerArray.some(outerChoice => {\n return innerArray.some(innerChoice => {\n found = tester(outerChoice, innerChoice);\n if (found) {\n return true;\n }\n });\n });\n return found;\n };\n let foundSourceAndTech;\n const flip = fn => (a, b) => fn(b, a);\n const finder = ([techName, tech], source) => {\n if (tech.canPlaySource(source, this.options_[techName.toLowerCase()])) {\n return {\n source,\n tech: techName\n };\n }\n };\n\n // Depending on the truthiness of `options.sourceOrder`, we swap the order of techs and sources\n // to select from them based on their priority.\n if (this.options_.sourceOrder) {\n // Source-first ordering\n foundSourceAndTech = findFirstPassingTechSourcePair(sources, techs, flip(finder));\n } else {\n // Tech-first ordering\n foundSourceAndTech = findFirstPassingTechSourcePair(techs, sources, finder);\n }\n return foundSourceAndTech || false;\n }\n\n /**\n * Executes source setting and getting logic\n *\n * @param {Tech~SourceObject|Tech~SourceObject[]|string} [source]\n * A SourceObject, an array of SourceObjects, or a string referencing\n * a URL to a media source. It is _highly recommended_ that an object\n * or array of objects is used here, so that source selection\n * algorithms can take the `type` into account.\n *\n * If not provided, this method acts as a getter.\n * @param {boolean} [isRetry]\n * Indicates whether this is being called internally as a result of a retry\n *\n * @return {string|undefined}\n * If the `source` argument is missing, returns the current source\n * URL. Otherwise, returns nothing/undefined.\n */\n handleSrc_(source, isRetry) {\n // getter usage\n if (typeof source === 'undefined') {\n return this.cache_.src || '';\n }\n\n // Reset retry behavior for new source\n if (this.resetRetryOnError_) {\n this.resetRetryOnError_();\n }\n\n // filter out invalid sources and turn our source into\n // an array of source objects\n const sources = filterSource(source);\n\n // if a source was passed in then it is invalid because\n // it was filtered to a zero length Array. So we have to\n // show an error\n if (!sources.length) {\n this.setTimeout(function () {\n this.error({\n code: 4,\n message: this.options_.notSupportedMessage\n });\n }, 0);\n return;\n }\n\n // initial sources\n this.changingSrc_ = true;\n\n // Only update the cached source list if we are not retrying a new source after error,\n // since in that case we want to include the failed source(s) in the cache\n if (!isRetry) {\n this.cache_.sources = sources;\n }\n this.updateSourceCaches_(sources[0]);\n\n // middlewareSource is the source after it has been changed by middleware\n setSource(this, sources[0], (middlewareSource, mws) => {\n this.middleware_ = mws;\n\n // since sourceSet is async we have to update the cache again after we select a source since\n // the source that is selected could be out of order from the cache update above this callback.\n if (!isRetry) {\n this.cache_.sources = sources;\n }\n this.updateSourceCaches_(middlewareSource);\n const err = this.src_(middlewareSource);\n if (err) {\n if (sources.length > 1) {\n return this.handleSrc_(sources.slice(1));\n }\n this.changingSrc_ = false;\n\n // We need to wrap this in a timeout to give folks a chance to add error event handlers\n this.setTimeout(function () {\n this.error({\n code: 4,\n message: this.options_.notSupportedMessage\n });\n }, 0);\n\n // we could not find an appropriate tech, but let's still notify the delegate that this is it\n // this needs a better comment about why this is needed\n this.triggerReady();\n return;\n }\n setTech(mws, this.tech_);\n });\n\n // Try another available source if this one fails before playback.\n if (sources.length > 1) {\n const retry = () => {\n // Remove the error modal\n this.error(null);\n this.handleSrc_(sources.slice(1), true);\n };\n const stopListeningForErrors = () => {\n this.off('error', retry);\n };\n this.one('error', retry);\n this.one('playing', stopListeningForErrors);\n this.resetRetryOnError_ = () => {\n this.off('error', retry);\n this.off('playing', stopListeningForErrors);\n };\n }\n }\n\n /**\n * Get or set the video source.\n *\n * @param {Tech~SourceObject|Tech~SourceObject[]|string} [source]\n * A SourceObject, an array of SourceObjects, or a string referencing\n * a URL to a media source. It is _highly recommended_ that an object\n * or array of objects is used here, so that source selection\n * algorithms can take the `type` into account.\n *\n * If not provided, this method acts as a getter.\n *\n * @return {string|undefined}\n * If the `source` argument is missing, returns the current source\n * URL. Otherwise, returns nothing/undefined.\n */\n src(source) {\n return this.handleSrc_(source, false);\n }\n\n /**\n * Set the source object on the tech, returns a boolean that indicates whether\n * there is a tech that can play the source or not\n *\n * @param {Tech~SourceObject} source\n * The source object to set on the Tech\n *\n * @return {boolean}\n * - True if there is no Tech to playback this source\n * - False otherwise\n *\n * @private\n */\n src_(source) {\n const sourceTech = this.selectSource([source]);\n if (!sourceTech) {\n return true;\n }\n if (!titleCaseEquals(sourceTech.tech, this.techName_)) {\n this.changingSrc_ = true;\n // load this technology with the chosen source\n this.loadTech_(sourceTech.tech, sourceTech.source);\n this.tech_.ready(() => {\n this.changingSrc_ = false;\n });\n return false;\n }\n\n // wait until the tech is ready to set the source\n // and set it synchronously if possible (#2326)\n this.ready(function () {\n // The setSource tech method was added with source handlers\n // so older techs won't support it\n // We need to check the direct prototype for the case where subclasses\n // of the tech do not support source handlers\n if (this.tech_.constructor.prototype.hasOwnProperty('setSource')) {\n this.techCall_('setSource', source);\n } else {\n this.techCall_('src', source.src);\n }\n this.changingSrc_ = false;\n }, true);\n return false;\n }\n\n /**\n * Add a <source> element to the <video> element.\n *\n * @param {string} srcUrl\n * The URL of the video source.\n *\n * @param {string} [mimeType]\n * The MIME type of the video source. Optional but recommended.\n *\n * @return {boolean}\n * Returns true if the source element was successfully added, false otherwise.\n */\n addSourceElement(srcUrl, mimeType) {\n if (!this.tech_) {\n return false;\n }\n return this.tech_.addSourceElement(srcUrl, mimeType);\n }\n\n /**\n * Remove a <source> element from the <video> element by its URL.\n *\n * @param {string} srcUrl\n * The URL of the source to remove.\n *\n * @return {boolean}\n * Returns true if the source element was successfully removed, false otherwise.\n */\n removeSourceElement(srcUrl) {\n if (!this.tech_) {\n return false;\n }\n return this.tech_.removeSourceElement(srcUrl);\n }\n\n /**\n * Begin loading the src data.\n */\n load() {\n // Workaround to use the load method with the VHS.\n // Does not cover the case when the load method is called directly from the mediaElement.\n if (this.tech_ && this.tech_.vhs) {\n this.src(this.currentSource());\n return;\n }\n this.techCall_('load');\n }\n\n /**\n * Reset the player. Loads the first tech in the techOrder,\n * removes all the text tracks in the existing `tech`,\n * and calls `reset` on the `tech`.\n */\n reset() {\n if (this.paused()) {\n this.doReset_();\n } else {\n const playPromise = this.play();\n silencePromise(playPromise.then(() => this.doReset_()));\n }\n }\n doReset_() {\n if (this.tech_) {\n this.tech_.clearTracks('text');\n }\n this.removeClass('vjs-playing');\n this.addClass('vjs-paused');\n this.resetCache_();\n this.poster('');\n this.loadTech_(this.options_.techOrder[0], null);\n this.techCall_('reset');\n this.resetControlBarUI_();\n this.error(null);\n if (this.titleBar) {\n this.titleBar.update({\n title: undefined,\n description: undefined\n });\n }\n if (isEvented(this)) {\n this.trigger('playerreset');\n }\n }\n\n /**\n * Reset Control Bar's UI by calling sub-methods that reset\n * all of Control Bar's components\n */\n resetControlBarUI_() {\n this.resetProgressBar_();\n this.resetPlaybackRate_();\n this.resetVolumeBar_();\n }\n\n /**\n * Reset tech's progress so progress bar is reset in the UI\n */\n resetProgressBar_() {\n this.currentTime(0);\n const {\n currentTimeDisplay,\n durationDisplay,\n progressControl,\n remainingTimeDisplay\n } = this.controlBar || {};\n const {\n seekBar\n } = progressControl || {};\n if (currentTimeDisplay) {\n currentTimeDisplay.updateContent();\n }\n if (durationDisplay) {\n durationDisplay.updateContent();\n }\n if (remainingTimeDisplay) {\n remainingTimeDisplay.updateContent();\n }\n if (seekBar) {\n seekBar.update();\n if (seekBar.loadProgressBar) {\n seekBar.loadProgressBar.update();\n }\n }\n }\n\n /**\n * Reset Playback ratio\n */\n resetPlaybackRate_() {\n this.playbackRate(this.defaultPlaybackRate());\n this.handleTechRateChange_();\n }\n\n /**\n * Reset Volume bar\n */\n resetVolumeBar_() {\n this.volume(1.0);\n this.trigger('volumechange');\n }\n\n /**\n * Returns all of the current source objects.\n *\n * @return {Tech~SourceObject[]}\n * The current source objects\n */\n currentSources() {\n const source = this.currentSource();\n const sources = [];\n\n // assume `{}` or `{ src }`\n if (Object.keys(source).length !== 0) {\n sources.push(source);\n }\n return this.cache_.sources || sources;\n }\n\n /**\n * Returns the current source object.\n *\n * @return {Tech~SourceObject}\n * The current source object\n */\n currentSource() {\n return this.cache_.source || {};\n }\n\n /**\n * Returns the fully qualified URL of the current source value e.g. http://mysite.com/video.mp4\n * Can be used in conjunction with `currentType` to assist in rebuilding the current source object.\n *\n * @return {string}\n * The current source\n */\n currentSrc() {\n return this.currentSource() && this.currentSource().src || '';\n }\n\n /**\n * Get the current source type e.g. video/mp4\n * This can allow you rebuild the current source object so that you could load the same\n * source and tech later\n *\n * @return {string}\n * The source MIME type\n */\n currentType() {\n return this.currentSource() && this.currentSource().type || '';\n }\n\n /**\n * Get or set the preload attribute\n *\n * @param {'none'|'auto'|'metadata'} [value]\n * Preload mode to pass to tech\n *\n * @return {string|undefined}\n * - The preload attribute value when getting\n * - Nothing when setting\n */\n preload(value) {\n if (value !== undefined) {\n this.techCall_('setPreload', value);\n this.options_.preload = value;\n return;\n }\n return this.techGet_('preload');\n }\n\n /**\n * Get or set the autoplay option. When this is a boolean it will\n * modify the attribute on the tech. When this is a string the attribute on\n * the tech will be removed and `Player` will handle autoplay on loadstarts.\n *\n * @param {boolean|'play'|'muted'|'any'} [value]\n * - true: autoplay using the browser behavior\n * - false: do not autoplay\n * - 'play': call play() on every loadstart\n * - 'muted': call muted() then play() on every loadstart\n * - 'any': call play() on every loadstart. if that fails call muted() then play().\n * - *: values other than those listed here will be set `autoplay` to true\n *\n * @return {boolean|string|undefined}\n * - The current value of autoplay when getting\n * - Nothing when setting\n */\n autoplay(value) {\n // getter usage\n if (value === undefined) {\n return this.options_.autoplay || false;\n }\n let techAutoplay;\n\n // if the value is a valid string set it to that, or normalize `true` to 'play', if need be\n if (typeof value === 'string' && /(any|play|muted)/.test(value) || value === true && this.options_.normalizeAutoplay) {\n this.options_.autoplay = value;\n this.manualAutoplay_(typeof value === 'string' ? value : 'play');\n techAutoplay = false;\n\n // any falsy value sets autoplay to false in the browser,\n // lets do the same\n } else if (!value) {\n this.options_.autoplay = false;\n\n // any other value (ie truthy) sets autoplay to true\n } else {\n this.options_.autoplay = true;\n }\n techAutoplay = typeof techAutoplay === 'undefined' ? this.options_.autoplay : techAutoplay;\n\n // if we don't have a tech then we do not queue up\n // a setAutoplay call on tech ready. We do this because the\n // autoplay option will be passed in the constructor and we\n // do not need to set it twice\n if (this.tech_) {\n this.techCall_('setAutoplay', techAutoplay);\n }\n }\n\n /**\n * Set or unset the playsinline attribute.\n * Playsinline tells the browser that non-fullscreen playback is preferred.\n *\n * @param {boolean} [value]\n * - true means that we should try to play inline by default\n * - false means that we should use the browser's default playback mode,\n * which in most cases is inline. iOS Safari is a notable exception\n * and plays fullscreen by default.\n *\n * @return {string|undefined}\n * - the current value of playsinline\n * - Nothing when setting\n *\n * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}\n */\n playsinline(value) {\n if (value !== undefined) {\n this.techCall_('setPlaysinline', value);\n this.options_.playsinline = value;\n }\n return this.techGet_('playsinline');\n }\n\n /**\n * Get or set the loop attribute on the video element.\n *\n * @param {boolean} [value]\n * - true means that we should loop the video\n * - false means that we should not loop the video\n *\n * @return {boolean|undefined}\n * - The current value of loop when getting\n * - Nothing when setting\n */\n loop(value) {\n if (value !== undefined) {\n this.techCall_('setLoop', value);\n this.options_.loop = value;\n return;\n }\n return this.techGet_('loop');\n }\n\n /**\n * Get or set the poster image source url\n *\n * @fires Player#posterchange\n *\n * @param {string} [src]\n * Poster image source URL\n *\n * @return {string|undefined}\n * - The current value of poster when getting\n * - Nothing when setting\n */\n poster(src) {\n if (src === undefined) {\n return this.poster_;\n }\n\n // The correct way to remove a poster is to set as an empty string\n // other falsey values will throw errors\n if (!src) {\n src = '';\n }\n if (src === this.poster_) {\n return;\n }\n\n // update the internal poster variable\n this.poster_ = src;\n\n // update the tech's poster\n this.techCall_('setPoster', src);\n this.isPosterFromTech_ = false;\n\n // alert components that the poster has been set\n /**\n * This event fires when the poster image is changed on the player.\n *\n * @event Player#posterchange\n * @type {Event}\n */\n this.trigger('posterchange');\n }\n\n /**\n * Some techs (e.g. YouTube) can provide a poster source in an\n * asynchronous way. We want the poster component to use this\n * poster source so that it covers up the tech's controls.\n * (YouTube's play button). However we only want to use this\n * source if the player user hasn't set a poster through\n * the normal APIs.\n *\n * @fires Player#posterchange\n * @listens Tech#posterchange\n * @private\n */\n handleTechPosterChange_() {\n if ((!this.poster_ || this.options_.techCanOverridePoster) && this.tech_ && this.tech_.poster) {\n const newPoster = this.tech_.poster() || '';\n if (newPoster !== this.poster_) {\n this.poster_ = newPoster;\n this.isPosterFromTech_ = true;\n\n // Let components know the poster has changed\n this.trigger('posterchange');\n }\n }\n }\n\n /**\n * Get or set whether or not the controls are showing.\n *\n * @fires Player#controlsenabled\n *\n * @param {boolean} [bool]\n * - true to turn controls on\n * - false to turn controls off\n *\n * @return {boolean|undefined}\n * - The current value of controls when getting\n * - Nothing when setting\n */\n controls(bool) {\n if (bool === undefined) {\n return !!this.controls_;\n }\n bool = !!bool;\n\n // Don't trigger a change event unless it actually changed\n if (this.controls_ === bool) {\n return;\n }\n this.controls_ = bool;\n if (this.usingNativeControls()) {\n this.techCall_('setControls', bool);\n }\n if (this.controls_) {\n this.removeClass('vjs-controls-disabled');\n this.addClass('vjs-controls-enabled');\n /**\n * @event Player#controlsenabled\n * @type {Event}\n */\n this.trigger('controlsenabled');\n if (!this.usingNativeControls()) {\n this.addTechControlsListeners_();\n }\n } else {\n this.removeClass('vjs-controls-enabled');\n this.addClass('vjs-controls-disabled');\n /**\n * @event Player#controlsdisabled\n * @type {Event}\n */\n this.trigger('controlsdisabled');\n if (!this.usingNativeControls()) {\n this.removeTechControlsListeners_();\n }\n }\n }\n\n /**\n * Toggle native controls on/off. Native controls are the controls built into\n * devices (e.g. default iPhone controls) or other techs\n * (e.g. Vimeo Controls)\n * **This should only be set by the current tech, because only the tech knows\n * if it can support native controls**\n *\n * @fires Player#usingnativecontrols\n * @fires Player#usingcustomcontrols\n *\n * @param {boolean} [bool]\n * - true to turn native controls on\n * - false to turn native controls off\n *\n * @return {boolean|undefined}\n * - The current value of native controls when getting\n * - Nothing when setting\n */\n usingNativeControls(bool) {\n if (bool === undefined) {\n return !!this.usingNativeControls_;\n }\n bool = !!bool;\n\n // Don't trigger a change event unless it actually changed\n if (this.usingNativeControls_ === bool) {\n return;\n }\n this.usingNativeControls_ = bool;\n if (this.usingNativeControls_) {\n this.addClass('vjs-using-native-controls');\n\n /**\n * player is using the native device controls\n *\n * @event Player#usingnativecontrols\n * @type {Event}\n */\n this.trigger('usingnativecontrols');\n } else {\n this.removeClass('vjs-using-native-controls');\n\n /**\n * player is using the custom HTML controls\n *\n * @event Player#usingcustomcontrols\n * @type {Event}\n */\n this.trigger('usingcustomcontrols');\n }\n }\n\n /**\n * Set or get the current MediaError\n *\n * @fires Player#error\n *\n * @param {MediaError|string|number} [err]\n * A MediaError or a string/number to be turned\n * into a MediaError\n *\n * @return {MediaError|null|undefined}\n * - The current MediaError when getting (or null)\n * - Nothing when setting\n */\n error(err) {\n if (err === undefined) {\n return this.error_ || null;\n }\n\n // allow hooks to modify error object\n hooks('beforeerror').forEach(hookFunction => {\n const newErr = hookFunction(this, err);\n if (!(isObject(newErr) && !Array.isArray(newErr) || typeof newErr === 'string' || typeof newErr === 'number' || newErr === null)) {\n this.log.error('please return a value that MediaError expects in beforeerror hooks');\n return;\n }\n err = newErr;\n });\n\n // Suppress the first error message for no compatible source until\n // user interaction\n if (this.options_.suppressNotSupportedError && err && err.code === 4) {\n const triggerSuppressedError = function () {\n this.error(err);\n };\n this.options_.suppressNotSupportedError = false;\n this.any(['click', 'touchstart'], triggerSuppressedError);\n this.one('loadstart', function () {\n this.off(['click', 'touchstart'], triggerSuppressedError);\n });\n return;\n }\n\n // restoring to default\n if (err === null) {\n this.error_ = null;\n this.removeClass('vjs-error');\n if (this.errorDisplay) {\n this.errorDisplay.close();\n }\n return;\n }\n this.error_ = new MediaError(err);\n\n // add the vjs-error classname to the player\n this.addClass('vjs-error');\n\n // log the name of the error type and any message\n // IE11 logs \"[object object]\" and required you to expand message to see error object\n log.error(`(CODE:${this.error_.code} ${MediaError.errorTypes[this.error_.code]})`, this.error_.message, this.error_);\n\n /**\n * @event Player#error\n * @type {Event}\n */\n this.trigger('error');\n\n // notify hooks of the per player error\n hooks('error').forEach(hookFunction => hookFunction(this, this.error_));\n return;\n }\n\n /**\n * Report user activity\n *\n * @param {Object} event\n * Event object\n */\n reportUserActivity(event) {\n this.userActivity_ = true;\n }\n\n /**\n * Get/set if user is active\n *\n * @fires Player#useractive\n * @fires Player#userinactive\n *\n * @param {boolean} [bool]\n * - true if the user is active\n * - false if the user is inactive\n *\n * @return {boolean|undefined}\n * - The current value of userActive when getting\n * - Nothing when setting\n */\n userActive(bool) {\n if (bool === undefined) {\n return this.userActive_;\n }\n bool = !!bool;\n if (bool === this.userActive_) {\n return;\n }\n this.userActive_ = bool;\n if (this.userActive_) {\n this.userActivity_ = true;\n this.removeClass('vjs-user-inactive');\n this.addClass('vjs-user-active');\n /**\n * @event Player#useractive\n * @type {Event}\n */\n this.trigger('useractive');\n return;\n }\n\n // Chrome/Safari/IE have bugs where when you change the cursor it can\n // trigger a mousemove event. This causes an issue when you're hiding\n // the cursor when the user is inactive, and a mousemove signals user\n // activity. Making it impossible to go into inactive mode. Specifically\n // this happens in fullscreen when we really need to hide the cursor.\n //\n // When this gets resolved in ALL browsers it can be removed\n // https://code.google.com/p/chromium/issues/detail?id=103041\n if (this.tech_) {\n this.tech_.one('mousemove', function (e) {\n e.stopPropagation();\n e.preventDefault();\n });\n }\n this.userActivity_ = false;\n this.removeClass('vjs-user-active');\n this.addClass('vjs-user-inactive');\n /**\n * @event Player#userinactive\n * @type {Event}\n */\n this.trigger('userinactive');\n }\n\n /**\n * Listen for user activity based on timeout value\n *\n * @private\n */\n listenForUserActivity_() {\n let mouseInProgress;\n let lastMoveX;\n let lastMoveY;\n const handleActivity = bind_(this, this.reportUserActivity);\n const handleMouseMove = function (e) {\n // #1068 - Prevent mousemove spamming\n // Chrome Bug: https://code.google.com/p/chromium/issues/detail?id=366970\n if (e.screenX !== lastMoveX || e.screenY !== lastMoveY) {\n lastMoveX = e.screenX;\n lastMoveY = e.screenY;\n handleActivity();\n }\n };\n const handleMouseDown = function () {\n handleActivity();\n // For as long as the they are touching the device or have their mouse down,\n // we consider them active even if they're not moving their finger or mouse.\n // So we want to continue to update that they are active\n this.clearInterval(mouseInProgress);\n // Setting userActivity=true now and setting the interval to the same time\n // as the activityCheck interval (250) should ensure we never miss the\n // next activityCheck\n mouseInProgress = this.setInterval(handleActivity, 250);\n };\n const handleMouseUpAndMouseLeave = function (event) {\n handleActivity();\n // Stop the interval that maintains activity if the mouse/touch is down\n this.clearInterval(mouseInProgress);\n };\n\n // Any mouse movement will be considered user activity\n this.on('mousedown', handleMouseDown);\n this.on('mousemove', handleMouseMove);\n this.on('mouseup', handleMouseUpAndMouseLeave);\n this.on('mouseleave', handleMouseUpAndMouseLeave);\n const controlBar = this.getChild('controlBar');\n\n // Fixes bug on Android & iOS where when tapping progressBar (when control bar is displayed)\n // controlBar would no longer be hidden by default timeout.\n if (controlBar && !IS_IOS && !IS_ANDROID) {\n controlBar.on('mouseenter', function (event) {\n if (this.player().options_.inactivityTimeout !== 0) {\n this.player().cache_.inactivityTimeout = this.player().options_.inactivityTimeout;\n }\n this.player().options_.inactivityTimeout = 0;\n });\n controlBar.on('mouseleave', function (event) {\n this.player().options_.inactivityTimeout = this.player().cache_.inactivityTimeout;\n });\n }\n\n // Listen for keyboard navigation\n // Shouldn't need to use inProgress interval because of key repeat\n this.on('keydown', handleActivity);\n this.on('keyup', handleActivity);\n\n // Run an interval every 250 milliseconds instead of stuffing everything into\n // the mousemove/touchmove function itself, to prevent performance degradation.\n // `this.reportUserActivity` simply sets this.userActivity_ to true, which\n // then gets picked up by this loop\n // http://ejohn.org/blog/learning-from-twitter/\n let inactivityTimeout;\n\n /** @this Player */\n const activityCheck = function () {\n // Check to see if mouse/touch activity has happened\n if (!this.userActivity_) {\n return;\n }\n\n // Reset the activity tracker\n this.userActivity_ = false;\n\n // If the user state was inactive, set the state to active\n this.userActive(true);\n\n // Clear any existing inactivity timeout to start the timer over\n this.clearTimeout(inactivityTimeout);\n const timeout = this.options_.inactivityTimeout;\n if (timeout <= 0) {\n return;\n }\n\n // In <timeout> milliseconds, if no more activity has occurred the\n // user will be considered inactive\n inactivityTimeout = this.setTimeout(function () {\n // Protect against the case where the inactivityTimeout can trigger just\n // before the next user activity is picked up by the activity check loop\n // causing a flicker\n if (!this.userActivity_) {\n this.userActive(false);\n }\n }, timeout);\n };\n this.setInterval(activityCheck, 250);\n }\n\n /**\n * Gets or sets the current playback rate. A playback rate of\n * 1.0 represents normal speed and 0.5 would indicate half-speed\n * playback, for instance.\n *\n * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-playbackrate\n *\n * @param {number} [rate]\n * New playback rate to set.\n *\n * @return {number|undefined}\n * - The current playback rate when getting or 1.0\n * - Nothing when setting\n */\n playbackRate(rate) {\n if (rate !== undefined) {\n // NOTE: this.cache_.lastPlaybackRate is set from the tech handler\n // that is registered above\n this.techCall_('setPlaybackRate', rate);\n return;\n }\n if (this.tech_ && this.tech_.featuresPlaybackRate) {\n return this.cache_.lastPlaybackRate || this.techGet_('playbackRate');\n }\n return 1.0;\n }\n\n /**\n * Gets or sets the current default playback rate. A default playback rate of\n * 1.0 represents normal speed and 0.5 would indicate half-speed playback, for instance.\n * defaultPlaybackRate will only represent what the initial playbackRate of a video was, not\n * not the current playbackRate.\n *\n * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-defaultplaybackrate\n *\n * @param {number} [rate]\n * New default playback rate to set.\n *\n * @return {number|undefined}\n * - The default playback rate when getting or 1.0\n * - Nothing when setting\n */\n defaultPlaybackRate(rate) {\n if (rate !== undefined) {\n return this.techCall_('setDefaultPlaybackRate', rate);\n }\n if (this.tech_ && this.tech_.featuresPlaybackRate) {\n return this.techGet_('defaultPlaybackRate');\n }\n return 1.0;\n }\n\n /**\n * Gets or sets the audio flag\n *\n * @param {boolean} [bool]\n * - true signals that this is an audio player\n * - false signals that this is not an audio player\n *\n * @return {boolean|undefined}\n * - The current value of isAudio when getting\n * - Nothing when setting\n */\n isAudio(bool) {\n if (bool !== undefined) {\n this.isAudio_ = !!bool;\n return;\n }\n return !!this.isAudio_;\n }\n updatePlayerHeightOnAudioOnlyMode_() {\n const controlBar = this.getChild('ControlBar');\n if (!controlBar || this.audioOnlyCache_.controlBarHeight === controlBar.currentHeight()) {\n return;\n }\n this.audioOnlyCache_.controlBarHeight = controlBar.currentHeight();\n this.height(this.audioOnlyCache_.controlBarHeight);\n }\n enableAudioOnlyUI_() {\n // Update styling immediately to show the control bar so we can get its height\n this.addClass('vjs-audio-only-mode');\n const playerChildren = this.children();\n const controlBar = this.getChild('ControlBar');\n const controlBarHeight = controlBar && controlBar.currentHeight();\n\n // Hide all player components except the control bar. Control bar components\n // needed only for video are hidden with CSS\n playerChildren.forEach(child => {\n if (child === controlBar) {\n return;\n }\n if (child.el_ && !child.hasClass('vjs-hidden')) {\n child.hide();\n this.audioOnlyCache_.hiddenChildren.push(child);\n }\n });\n this.audioOnlyCache_.playerHeight = this.currentHeight();\n this.audioOnlyCache_.controlBarHeight = controlBarHeight;\n this.on('playerresize', this.boundUpdatePlayerHeightOnAudioOnlyMode_);\n\n // Set the player height the same as the control bar\n this.height(controlBarHeight);\n this.trigger('audioonlymodechange');\n }\n disableAudioOnlyUI_() {\n this.removeClass('vjs-audio-only-mode');\n this.off('playerresize', this.boundUpdatePlayerHeightOnAudioOnlyMode_);\n\n // Show player components that were previously hidden\n this.audioOnlyCache_.hiddenChildren.forEach(child => child.show());\n\n // Reset player height\n this.height(this.audioOnlyCache_.playerHeight);\n this.trigger('audioonlymodechange');\n }\n\n /**\n * Get the current audioOnlyMode state or set audioOnlyMode to true or false.\n *\n * Setting this to `true` will hide all player components except the control bar,\n * as well as control bar components needed only for video.\n *\n * @param {boolean} [value]\n * The value to set audioOnlyMode to.\n *\n * @return {Promise|boolean}\n * A Promise is returned when setting the state, and a boolean when getting\n * the present state\n */\n audioOnlyMode(value) {\n if (typeof value !== 'boolean' || value === this.audioOnlyMode_) {\n return this.audioOnlyMode_;\n }\n this.audioOnlyMode_ = value;\n\n // Enable Audio Only Mode\n if (value) {\n const exitPromises = [];\n\n // Fullscreen and PiP are not supported in audioOnlyMode, so exit if we need to.\n if (this.isInPictureInPicture()) {\n exitPromises.push(this.exitPictureInPicture());\n }\n if (this.isFullscreen()) {\n exitPromises.push(this.exitFullscreen());\n }\n if (this.audioPosterMode()) {\n exitPromises.push(this.audioPosterMode(false));\n }\n return Promise.all(exitPromises).then(() => this.enableAudioOnlyUI_());\n }\n\n // Disable Audio Only Mode\n return Promise.resolve().then(() => this.disableAudioOnlyUI_());\n }\n enablePosterModeUI_() {\n // Hide the video element and show the poster image to enable posterModeUI\n const tech = this.tech_ && this.tech_;\n tech.hide();\n this.addClass('vjs-audio-poster-mode');\n this.trigger('audiopostermodechange');\n }\n disablePosterModeUI_() {\n // Show the video element and hide the poster image to disable posterModeUI\n const tech = this.tech_ && this.tech_;\n tech.show();\n this.removeClass('vjs-audio-poster-mode');\n this.trigger('audiopostermodechange');\n }\n\n /**\n * Get the current audioPosterMode state or set audioPosterMode to true or false\n *\n * @param {boolean} [value]\n * The value to set audioPosterMode to.\n *\n * @return {Promise|boolean}\n * A Promise is returned when setting the state, and a boolean when getting\n * the present state\n */\n audioPosterMode(value) {\n if (typeof value !== 'boolean' || value === this.audioPosterMode_) {\n return this.audioPosterMode_;\n }\n this.audioPosterMode_ = value;\n if (value) {\n if (this.audioOnlyMode()) {\n const audioOnlyModePromise = this.audioOnlyMode(false);\n return audioOnlyModePromise.then(() => {\n // enable audio poster mode after audio only mode is disabled\n this.enablePosterModeUI_();\n });\n }\n return Promise.resolve().then(() => {\n // enable audio poster mode\n this.enablePosterModeUI_();\n });\n }\n return Promise.resolve().then(() => {\n // disable audio poster mode\n this.disablePosterModeUI_();\n });\n }\n\n /**\n * A helper method for adding a {@link TextTrack} to our\n * {@link TextTrackList}.\n *\n * In addition to the W3C settings we allow adding additional info through options.\n *\n * @see http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-addtexttrack\n *\n * @param {string} [kind]\n * the kind of TextTrack you are adding\n *\n * @param {string} [label]\n * the label to give the TextTrack label\n *\n * @param {string} [language]\n * the language to set on the TextTrack\n *\n * @return {TextTrack|undefined}\n * the TextTrack that was added or undefined\n * if there is no tech\n */\n addTextTrack(kind, label, language) {\n if (this.tech_) {\n return this.tech_.addTextTrack(kind, label, language);\n }\n }\n\n /**\n * Create a remote {@link TextTrack} and an {@link HTMLTrackElement}.\n *\n * @param {Object} options\n * Options to pass to {@link HTMLTrackElement} during creation. See\n * {@link HTMLTrackElement} for object properties that you should use.\n *\n * @param {boolean} [manualCleanup=false] if set to true, the TextTrack will not be removed\n * from the TextTrackList and HtmlTrackElementList\n * after a source change\n *\n * @return {HtmlTrackElement}\n * the HTMLTrackElement that was created and added\n * to the HtmlTrackElementList and the remote\n * TextTrackList\n *\n */\n addRemoteTextTrack(options, manualCleanup) {\n if (this.tech_) {\n return this.tech_.addRemoteTextTrack(options, manualCleanup);\n }\n }\n\n /**\n * Remove a remote {@link TextTrack} from the respective\n * {@link TextTrackList} and {@link HtmlTrackElementList}.\n *\n * @param {Object} track\n * Remote {@link TextTrack} to remove\n *\n * @return {undefined}\n * does not return anything\n */\n removeRemoteTextTrack(obj = {}) {\n let {\n track\n } = obj;\n if (!track) {\n track = obj;\n }\n\n // destructure the input into an object with a track argument, defaulting to arguments[0]\n // default the whole argument to an empty object if nothing was passed in\n\n if (this.tech_) {\n return this.tech_.removeRemoteTextTrack(track);\n }\n }\n\n /**\n * Gets available media playback quality metrics as specified by the W3C's Media\n * Playback Quality API.\n *\n * @see [Spec]{@link https://wicg.github.io/media-playback-quality}\n *\n * @return {Object|undefined}\n * An object with supported media playback quality metrics or undefined if there\n * is no tech or the tech does not support it.\n */\n getVideoPlaybackQuality() {\n return this.techGet_('getVideoPlaybackQuality');\n }\n\n /**\n * Get video width\n *\n * @return {number}\n * current video width\n */\n videoWidth() {\n return this.tech_ && this.tech_.videoWidth && this.tech_.videoWidth() || 0;\n }\n\n /**\n * Get video height\n *\n * @return {number}\n * current video height\n */\n videoHeight() {\n return this.tech_ && this.tech_.videoHeight && this.tech_.videoHeight() || 0;\n }\n\n /**\n * Set or get the player's language code.\n *\n * Changing the language will trigger\n * [languagechange]{@link Player#event:languagechange}\n * which Components can use to update control text.\n * ClickableComponent will update its control text by default on\n * [languagechange]{@link Player#event:languagechange}.\n *\n * @fires Player#languagechange\n *\n * @param {string} [code]\n * the language code to set the player to\n *\n * @return {string|undefined}\n * - The current language code when getting\n * - Nothing when setting\n */\n language(code) {\n if (code === undefined) {\n return this.language_;\n }\n if (this.language_ !== String(code).toLowerCase()) {\n this.language_ = String(code).toLowerCase();\n\n // during first init, it's possible some things won't be evented\n if (isEvented(this)) {\n /**\n * fires when the player language change\n *\n * @event Player#languagechange\n * @type {Event}\n */\n this.trigger('languagechange');\n }\n }\n }\n\n /**\n * Get the player's language dictionary\n * Merge every time, because a newly added plugin might call videojs.addLanguage() at any time\n * Languages specified directly in the player options have precedence\n *\n * @return {Array}\n * An array of of supported languages\n */\n languages() {\n return merge(Player.prototype.options_.languages, this.languages_);\n }\n\n /**\n * returns a JavaScript object representing the current track\n * information. **DOES not return it as JSON**\n *\n * @return {Object}\n * Object representing the current of track info\n */\n toJSON() {\n const options = merge(this.options_);\n const tracks = options.tracks;\n options.tracks = [];\n for (let i = 0; i < tracks.length; i++) {\n let track = tracks[i];\n\n // deep merge tracks and null out player so no circular references\n track = merge(track);\n track.player = undefined;\n options.tracks[i] = track;\n }\n return options;\n }\n\n /**\n * Creates a simple modal dialog (an instance of the {@link ModalDialog}\n * component) that immediately overlays the player with arbitrary\n * content and removes itself when closed.\n *\n * @param {string|Function|Element|Array|null} content\n * Same as {@link ModalDialog#content}'s param of the same name.\n * The most straight-forward usage is to provide a string or DOM\n * element.\n *\n * @param {Object} [options]\n * Extra options which will be passed on to the {@link ModalDialog}.\n *\n * @return {ModalDialog}\n * the {@link ModalDialog} that was created\n */\n createModal(content, options) {\n options = options || {};\n options.content = content || '';\n const modal = new ModalDialog(this, options);\n this.addChild(modal);\n modal.on('dispose', () => {\n this.removeChild(modal);\n });\n modal.open();\n return modal;\n }\n\n /**\n * Change breakpoint classes when the player resizes.\n *\n * @private\n */\n updateCurrentBreakpoint_() {\n if (!this.responsive()) {\n return;\n }\n const currentBreakpoint = this.currentBreakpoint();\n const currentWidth = this.currentWidth();\n for (let i = 0; i < BREAKPOINT_ORDER.length; i++) {\n const candidateBreakpoint = BREAKPOINT_ORDER[i];\n const maxWidth = this.breakpoints_[candidateBreakpoint];\n if (currentWidth <= maxWidth) {\n // The current breakpoint did not change, nothing to do.\n if (currentBreakpoint === candidateBreakpoint) {\n return;\n }\n\n // Only remove a class if there is a current breakpoint.\n if (currentBreakpoint) {\n this.removeClass(BREAKPOINT_CLASSES[currentBreakpoint]);\n }\n this.addClass(BREAKPOINT_CLASSES[candidateBreakpoint]);\n this.breakpoint_ = candidateBreakpoint;\n break;\n }\n }\n }\n\n /**\n * Removes the current breakpoint.\n *\n * @private\n */\n removeCurrentBreakpoint_() {\n const className = this.currentBreakpointClass();\n this.breakpoint_ = '';\n if (className) {\n this.removeClass(className);\n }\n }\n\n /**\n * Get or set breakpoints on the player.\n *\n * Calling this method with an object or `true` will remove any previous\n * custom breakpoints and start from the defaults again.\n *\n * @param {Object|boolean} [breakpoints]\n * If an object is given, it can be used to provide custom\n * breakpoints. If `true` is given, will set default breakpoints.\n * If this argument is not given, will simply return the current\n * breakpoints.\n *\n * @param {number} [breakpoints.tiny]\n * The maximum width for the \"vjs-layout-tiny\" class.\n *\n * @param {number} [breakpoints.xsmall]\n * The maximum width for the \"vjs-layout-x-small\" class.\n *\n * @param {number} [breakpoints.small]\n * The maximum width for the \"vjs-layout-small\" class.\n *\n * @param {number} [breakpoints.medium]\n * The maximum width for the \"vjs-layout-medium\" class.\n *\n * @param {number} [breakpoints.large]\n * The maximum width for the \"vjs-layout-large\" class.\n *\n * @param {number} [breakpoints.xlarge]\n * The maximum width for the \"vjs-layout-x-large\" class.\n *\n * @param {number} [breakpoints.huge]\n * The maximum width for the \"vjs-layout-huge\" class.\n *\n * @return {Object}\n * An object mapping breakpoint names to maximum width values.\n */\n breakpoints(breakpoints) {\n // Used as a getter.\n if (breakpoints === undefined) {\n return Object.assign(this.breakpoints_);\n }\n this.breakpoint_ = '';\n this.breakpoints_ = Object.assign({}, DEFAULT_BREAKPOINTS, breakpoints);\n\n // When breakpoint definitions change, we need to update the currently\n // selected breakpoint.\n this.updateCurrentBreakpoint_();\n\n // Clone the breakpoints before returning.\n return Object.assign(this.breakpoints_);\n }\n\n /**\n * Get or set a flag indicating whether or not this player should adjust\n * its UI based on its dimensions.\n *\n * @param {boolean} [value]\n * Should be `true` if the player should adjust its UI based on its\n * dimensions; otherwise, should be `false`.\n *\n * @return {boolean|undefined}\n * Will be `true` if this player should adjust its UI based on its\n * dimensions; otherwise, will be `false`.\n * Nothing if setting\n */\n responsive(value) {\n // Used as a getter.\n if (value === undefined) {\n return this.responsive_;\n }\n value = Boolean(value);\n const current = this.responsive_;\n\n // Nothing changed.\n if (value === current) {\n return;\n }\n\n // The value actually changed, set it.\n this.responsive_ = value;\n\n // Start listening for breakpoints and set the initial breakpoint if the\n // player is now responsive.\n if (value) {\n this.on('playerresize', this.boundUpdateCurrentBreakpoint_);\n this.updateCurrentBreakpoint_();\n\n // Stop listening for breakpoints if the player is no longer responsive.\n } else {\n this.off('playerresize', this.boundUpdateCurrentBreakpoint_);\n this.removeCurrentBreakpoint_();\n }\n return value;\n }\n\n /**\n * Get current breakpoint name, if any.\n *\n * @return {string}\n * If there is currently a breakpoint set, returns a the key from the\n * breakpoints object matching it. Otherwise, returns an empty string.\n */\n currentBreakpoint() {\n return this.breakpoint_;\n }\n\n /**\n * Get the current breakpoint class name.\n *\n * @return {string}\n * The matching class name (e.g. `\"vjs-layout-tiny\"` or\n * `\"vjs-layout-large\"`) for the current breakpoint. Empty string if\n * there is no current breakpoint.\n */\n currentBreakpointClass() {\n return BREAKPOINT_CLASSES[this.breakpoint_] || '';\n }\n\n /**\n * An object that describes a single piece of media.\n *\n * Properties that are not part of this type description will be retained; so,\n * this can be viewed as a generic metadata storage mechanism as well.\n *\n * @see {@link https://wicg.github.io/mediasession/#the-mediametadata-interface}\n * @typedef {Object} Player~MediaObject\n *\n * @property {string} [album]\n * Unused, except if this object is passed to the `MediaSession`\n * API.\n *\n * @property {string} [artist]\n * Unused, except if this object is passed to the `MediaSession`\n * API.\n *\n * @property {Object[]} [artwork]\n * Unused, except if this object is passed to the `MediaSession`\n * API. If not specified, will be populated via the `poster`, if\n * available.\n *\n * @property {string} [poster]\n * URL to an image that will display before playback.\n *\n * @property {Tech~SourceObject|Tech~SourceObject[]|string} [src]\n * A single source object, an array of source objects, or a string\n * referencing a URL to a media source. It is _highly recommended_\n * that an object or array of objects is used here, so that source\n * selection algorithms can take the `type` into account.\n *\n * @property {string} [title]\n * Unused, except if this object is passed to the `MediaSession`\n * API.\n *\n * @property {Object[]} [textTracks]\n * An array of objects to be used to create text tracks, following\n * the {@link https://www.w3.org/TR/html50/embedded-content-0.html#the-track-element|native track element format}.\n * For ease of removal, these will be created as \"remote\" text\n * tracks and set to automatically clean up on source changes.\n *\n * These objects may have properties like `src`, `kind`, `label`,\n * and `language`, see {@link Tech#createRemoteTextTrack}.\n */\n\n /**\n * Populate the player using a {@link Player~MediaObject|MediaObject}.\n *\n * @param {Player~MediaObject} media\n * A media object.\n *\n * @param {Function} ready\n * A callback to be called when the player is ready.\n */\n loadMedia(media, ready) {\n if (!media || typeof media !== 'object') {\n return;\n }\n const crossOrigin = this.crossOrigin();\n this.reset();\n\n // Clone the media object so it cannot be mutated from outside.\n this.cache_.media = merge(media);\n const {\n artist,\n artwork,\n description,\n poster,\n src,\n textTracks,\n title\n } = this.cache_.media;\n\n // If `artwork` is not given, create it using `poster`.\n if (!artwork && poster) {\n this.cache_.media.artwork = [{\n src: poster,\n type: getMimetype(poster)\n }];\n }\n if (crossOrigin) {\n this.crossOrigin(crossOrigin);\n }\n if (src) {\n this.src(src);\n }\n if (poster) {\n this.poster(poster);\n }\n if (Array.isArray(textTracks)) {\n textTracks.forEach(tt => this.addRemoteTextTrack(tt, false));\n }\n if (this.titleBar) {\n this.titleBar.update({\n title,\n description: description || artist || ''\n });\n }\n this.ready(ready);\n }\n\n /**\n * Get a clone of the current {@link Player~MediaObject} for this player.\n *\n * If the `loadMedia` method has not been used, will attempt to return a\n * {@link Player~MediaObject} based on the current state of the player.\n *\n * @return {Player~MediaObject}\n */\n getMedia() {\n if (!this.cache_.media) {\n const poster = this.poster();\n const src = this.currentSources();\n const textTracks = Array.prototype.map.call(this.remoteTextTracks(), tt => ({\n kind: tt.kind,\n label: tt.label,\n language: tt.language,\n src: tt.src\n }));\n const media = {\n src,\n textTracks\n };\n if (poster) {\n media.poster = poster;\n media.artwork = [{\n src: media.poster,\n type: getMimetype(media.poster)\n }];\n }\n return media;\n }\n return merge(this.cache_.media);\n }\n\n /**\n * Gets tag settings\n *\n * @param {Element} tag\n * The player tag\n *\n * @return {Object}\n * An object containing all of the settings\n * for a player tag\n */\n static getTagSettings(tag) {\n const baseOptions = {\n sources: [],\n tracks: []\n };\n const tagOptions = getAttributes(tag);\n const dataSetup = tagOptions['data-setup'];\n if (hasClass(tag, 'vjs-fill')) {\n tagOptions.fill = true;\n }\n if (hasClass(tag, 'vjs-fluid')) {\n tagOptions.fluid = true;\n }\n\n // Check if data-setup attr exists.\n if (dataSetup !== null) {\n // Parse options JSON\n try {\n // If empty string, make it a parsable json object.\n Object.assign(tagOptions, JSON.parse(dataSetup || '{}'));\n } catch (e) {\n log.error('data-setup', e);\n }\n }\n Object.assign(baseOptions, tagOptions);\n\n // Get tag children settings\n if (tag.hasChildNodes()) {\n const children = tag.childNodes;\n for (let i = 0, j = children.length; i < j; i++) {\n const child = children[i];\n // Change case needed: http://ejohn.org/blog/nodename-case-sensitivity/\n const childName = child.nodeName.toLowerCase();\n if (childName === 'source') {\n baseOptions.sources.push(getAttributes(child));\n } else if (childName === 'track') {\n baseOptions.tracks.push(getAttributes(child));\n }\n }\n }\n return baseOptions;\n }\n\n /**\n * Set debug mode to enable/disable logs at info level.\n *\n * @param {boolean} enabled\n * @fires Player#debugon\n * @fires Player#debugoff\n * @return {boolean|undefined}\n */\n debug(enabled) {\n if (enabled === undefined) {\n return this.debugEnabled_;\n }\n if (enabled) {\n this.trigger('debugon');\n this.previousLogLevel_ = this.log.level;\n this.log.level('debug');\n this.debugEnabled_ = true;\n } else {\n this.trigger('debugoff');\n this.log.level(this.previousLogLevel_);\n this.previousLogLevel_ = undefined;\n this.debugEnabled_ = false;\n }\n }\n\n /**\n * Set or get current playback rates.\n * Takes an array and updates the playback rates menu with the new items.\n * Pass in an empty array to hide the menu.\n * Values other than arrays are ignored.\n *\n * @fires Player#playbackrateschange\n * @param {number[]} [newRates]\n * The new rates that the playback rates menu should update to.\n * An empty array will hide the menu\n * @return {number[]} When used as a getter will return the current playback rates\n */\n playbackRates(newRates) {\n if (newRates === undefined) {\n return this.cache_.playbackRates;\n }\n\n // ignore any value that isn't an array\n if (!Array.isArray(newRates)) {\n return;\n }\n\n // ignore any arrays that don't only contain numbers\n if (!newRates.every(rate => typeof rate === 'number')) {\n return;\n }\n this.cache_.playbackRates = newRates;\n\n /**\n * fires when the playback rates in a player are changed\n *\n * @event Player#playbackrateschange\n * @type {Event}\n */\n this.trigger('playbackrateschange');\n }\n\n /**\n * Reports whether or not a player has a plugin available.\n *\n * This does not report whether or not the plugin has ever been initialized\n * on this player. For that, [usingPlugin]{@link Player#usingPlugin}.\n *\n * @method hasPlugin\n * @param {string} name\n * The name of a plugin.\n *\n * @return {boolean}\n * Whether or not this player has the requested plugin available.\n */\n\n /**\n * Reports whether or not a player is using a plugin by name.\n *\n * For basic plugins, this only reports whether the plugin has _ever_ been\n * initialized on this player.\n *\n * @method Player#usingPlugin\n * @param {string} name\n * The name of a plugin.\n *\n * @return {boolean}\n * Whether or not this player is using the requested plugin.\n */\n }\n\n /**\n * Get the {@link VideoTrackList}\n *\n * @link https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist\n *\n * @return {VideoTrackList}\n * the current video track list\n *\n * @method Player.prototype.videoTracks\n */\n Player.prototype.videoTracks = () => {};\n\n /**\n * Get the {@link AudioTrackList}\n *\n * @link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist\n *\n * @return {AudioTrackList}\n * the current audio track list\n *\n * @method Player.prototype.audioTracks\n */\n Player.prototype.audioTracks = () => {};\n\n /**\n * Get the {@link TextTrackList}\n *\n * @link http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-texttracks\n *\n * @return {TextTrackList}\n * the current text track list\n *\n * @method Player.prototype.textTracks\n */\n Player.prototype.textTracks = () => {};\n\n /**\n * Get the remote {@link TextTrackList}\n *\n * @return {TextTrackList}\n * The current remote text track list\n *\n * @method Player.prototype.remoteTextTracks\n */\n Player.prototype.remoteTextTracks = () => {};\n\n /**\n * Get the remote {@link HtmlTrackElementList} tracks.\n *\n * @return {HtmlTrackElementList}\n * The current remote text track element list\n *\n * @method Player.prototype.remoteTextTrackEls\n */\n Player.prototype.remoteTextTrackEls = () => {};\n ALL.names.forEach(function (name) {\n const props = ALL[name];\n Player.prototype[props.getterName] = function () {\n if (this.tech_) {\n return this.tech_[props.getterName]();\n }\n\n // if we have not yet loadTech_, we create {video,audio,text}Tracks_\n // these will be passed to the tech during loading\n this[props.privateName] = this[props.privateName] || new props.ListClass();\n return this[props.privateName];\n };\n });\n\n /**\n * Get or set the `Player`'s crossorigin option. For the HTML5 player, this\n * sets the `crossOrigin` property on the `<video>` tag to control the CORS\n * behavior.\n *\n * @see [Video Element Attributes]{@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#attr-crossorigin}\n *\n * @param {string} [value]\n * The value to set the `Player`'s crossorigin to. If an argument is\n * given, must be one of `anonymous` or `use-credentials`.\n *\n * @return {string|undefined}\n * - The current crossorigin value of the `Player` when getting.\n * - undefined when setting\n */\n Player.prototype.crossorigin = Player.prototype.crossOrigin;\n\n /**\n * Global enumeration of players.\n *\n * The keys are the player IDs and the values are either the {@link Player}\n * instance or `null` for disposed players.\n *\n * @type {Object}\n */\n Player.players = {};\n const navigator = window.navigator;\n\n /*\n * Player instance options, surfaced using options\n * options = Player.prototype.options_\n * Make changes in options, not here.\n *\n * @type {Object}\n * @private\n */\n Player.prototype.options_ = {\n // Default order of fallback technology\n techOrder: Tech.defaultTechOrder_,\n html5: {},\n // enable sourceset by default\n enableSourceset: true,\n // default inactivity timeout\n inactivityTimeout: 2000,\n // default playback rates\n playbackRates: [],\n // Add playback rate selection by adding rates\n // 'playbackRates': [0.5, 1, 1.5, 2],\n liveui: false,\n // Included control sets\n children: ['mediaLoader', 'posterImage', 'titleBar', 'textTrackDisplay', 'loadingSpinner', 'bigPlayButton', 'liveTracker', 'controlBar', 'errorDisplay', 'textTrackSettings', 'resizeManager'],\n language: navigator && (navigator.languages && navigator.languages[0] || navigator.userLanguage || navigator.language) || 'en',\n // locales and their language translations\n languages: {},\n // Default message to show when a video cannot be played.\n notSupportedMessage: 'No compatible source was found for this media.',\n normalizeAutoplay: false,\n fullscreen: {\n options: {\n navigationUI: 'hide'\n }\n },\n breakpoints: {},\n responsive: false,\n audioOnlyMode: false,\n audioPosterMode: false,\n spatialNavigation: {\n enabled: false,\n horizontalSeek: false\n },\n // Default smooth seeking to false\n enableSmoothSeeking: false,\n disableSeekWhileScrubbingOnMobile: false,\n disableSeekWhileScrubbingOnSTV: false\n };\n TECH_EVENTS_RETRIGGER.forEach(function (event) {\n Player.prototype[`handleTech${toTitleCase(event)}_`] = function () {\n return this.trigger(event);\n };\n });\n\n /**\n * Fired when the player has initial duration and dimension information\n *\n * @event Player#loadedmetadata\n * @type {Event}\n */\n\n /**\n * Fired when the player has downloaded data at the current playback position\n *\n * @event Player#loadeddata\n * @type {Event}\n */\n\n /**\n * Fired when the current playback position has changed *\n * During playback this is fired every 15-250 milliseconds, depending on the\n * playback technology in use.\n *\n * @event Player#timeupdate\n * @type {Event}\n */\n\n /**\n * Fired when the volume changes\n *\n * @event Player#volumechange\n * @type {Event}\n */\n\n Component.registerComponent('Player', Player);\n\n /**\n * @file plugin.js\n */\n\n /**\n * The base plugin name.\n *\n * @private\n * @constant\n * @type {string}\n */\n const BASE_PLUGIN_NAME = 'plugin';\n\n /**\n * The key on which a player's active plugins cache is stored.\n *\n * @private\n * @constant\n * @type {string}\n */\n const PLUGIN_CACHE_KEY = 'activePlugins_';\n\n /**\n * Stores registered plugins in a private space.\n *\n * @private\n * @type {Object}\n */\n const pluginStorage = {};\n\n /**\n * Reports whether or not a plugin has been registered.\n *\n * @private\n * @param {string} name\n * The name of a plugin.\n *\n * @return {boolean}\n * Whether or not the plugin has been registered.\n */\n const pluginExists = name => pluginStorage.hasOwnProperty(name);\n\n /**\n * Get a single registered plugin by name.\n *\n * @private\n * @param {string} name\n * The name of a plugin.\n *\n * @return {typeof Plugin|Function|undefined}\n * The plugin (or undefined).\n */\n const getPlugin = name => pluginExists(name) ? pluginStorage[name] : undefined;\n\n /**\n * Marks a plugin as \"active\" on a player.\n *\n * Also, ensures that the player has an object for tracking active plugins.\n *\n * @private\n * @param {Player} player\n * A Video.js player instance.\n *\n * @param {string} name\n * The name of a plugin.\n */\n const markPluginAsActive = (player, name) => {\n player[PLUGIN_CACHE_KEY] = player[PLUGIN_CACHE_KEY] || {};\n player[PLUGIN_CACHE_KEY][name] = true;\n };\n\n /**\n * Triggers a pair of plugin setup events.\n *\n * @private\n * @param {Player} player\n * A Video.js player instance.\n *\n * @param {PluginEventHash} hash\n * A plugin event hash.\n *\n * @param {boolean} [before]\n * If true, prefixes the event name with \"before\". In other words,\n * use this to trigger \"beforepluginsetup\" instead of \"pluginsetup\".\n */\n const triggerSetupEvent = (player, hash, before) => {\n const eventName = (before ? 'before' : '') + 'pluginsetup';\n player.trigger(eventName, hash);\n player.trigger(eventName + ':' + hash.name, hash);\n };\n\n /**\n * Takes a basic plugin function and returns a wrapper function which marks\n * on the player that the plugin has been activated.\n *\n * @private\n * @param {string} name\n * The name of the plugin.\n *\n * @param {Function} plugin\n * The basic plugin.\n *\n * @return {Function}\n * A wrapper function for the given plugin.\n */\n const createBasicPlugin = function (name, plugin) {\n const basicPluginWrapper = function () {\n // We trigger the \"beforepluginsetup\" and \"pluginsetup\" events on the player\n // regardless, but we want the hash to be consistent with the hash provided\n // for advanced plugins.\n //\n // The only potentially counter-intuitive thing here is the `instance` in\n // the \"pluginsetup\" event is the value returned by the `plugin` function.\n triggerSetupEvent(this, {\n name,\n plugin,\n instance: null\n }, true);\n const instance = plugin.apply(this, arguments);\n markPluginAsActive(this, name);\n triggerSetupEvent(this, {\n name,\n plugin,\n instance\n });\n return instance;\n };\n Object.keys(plugin).forEach(function (prop) {\n basicPluginWrapper[prop] = plugin[prop];\n });\n return basicPluginWrapper;\n };\n\n /**\n * Takes a plugin sub-class and returns a factory function for generating\n * instances of it.\n *\n * This factory function will replace itself with an instance of the requested\n * sub-class of Plugin.\n *\n * @private\n * @param {string} name\n * The name of the plugin.\n *\n * @param {Plugin} PluginSubClass\n * The advanced plugin.\n *\n * @return {Function}\n */\n const createPluginFactory = (name, PluginSubClass) => {\n // Add a `name` property to the plugin prototype so that each plugin can\n // refer to itself by name.\n PluginSubClass.prototype.name = name;\n return function (...args) {\n triggerSetupEvent(this, {\n name,\n plugin: PluginSubClass,\n instance: null\n }, true);\n const instance = new PluginSubClass(...[this, ...args]);\n\n // The plugin is replaced by a function that returns the current instance.\n this[name] = () => instance;\n triggerSetupEvent(this, instance.getEventHash());\n return instance;\n };\n };\n\n /**\n * Parent class for all advanced plugins.\n *\n * @mixes module:evented~EventedMixin\n * @mixes module:stateful~StatefulMixin\n * @fires Player#beforepluginsetup\n * @fires Player#beforepluginsetup:$name\n * @fires Player#pluginsetup\n * @fires Player#pluginsetup:$name\n * @listens Player#dispose\n * @throws {Error}\n * If attempting to instantiate the base {@link Plugin} class\n * directly instead of via a sub-class.\n */\n class Plugin {\n /**\n * Creates an instance of this class.\n *\n * Sub-classes should call `super` to ensure plugins are properly initialized.\n *\n * @param {Player} player\n * A Video.js player instance.\n */\n constructor(player) {\n if (this.constructor === Plugin) {\n throw new Error('Plugin must be sub-classed; not directly instantiated.');\n }\n this.player = player;\n if (!this.log) {\n this.log = this.player.log.createLogger(this.name);\n }\n\n // Make this object evented, but remove the added `trigger` method so we\n // use the prototype version instead.\n evented(this);\n delete this.trigger;\n stateful(this, this.constructor.defaultState);\n markPluginAsActive(player, this.name);\n\n // Auto-bind the dispose method so we can use it as a listener and unbind\n // it later easily.\n this.dispose = this.dispose.bind(this);\n\n // If the player is disposed, dispose the plugin.\n player.on('dispose', this.dispose);\n }\n\n /**\n * Get the version of the plugin that was set on <pluginName>.VERSION\n */\n version() {\n return this.constructor.VERSION;\n }\n\n /**\n * Each event triggered by plugins includes a hash of additional data with\n * conventional properties.\n *\n * This returns that object or mutates an existing hash.\n *\n * @param {Object} [hash={}]\n * An object to be used as event an event hash.\n *\n * @return {PluginEventHash}\n * An event hash object with provided properties mixed-in.\n */\n getEventHash(hash = {}) {\n hash.name = this.name;\n hash.plugin = this.constructor;\n hash.instance = this;\n return hash;\n }\n\n /**\n * Triggers an event on the plugin object and overrides\n * {@link module:evented~EventedMixin.trigger|EventedMixin.trigger}.\n *\n * @param {string|Object} event\n * An event type or an object with a type property.\n *\n * @param {Object} [hash={}]\n * Additional data hash to merge with a\n * {@link PluginEventHash|PluginEventHash}.\n *\n * @return {boolean}\n * Whether or not default was prevented.\n */\n trigger(event, hash = {}) {\n return trigger(this.eventBusEl_, event, this.getEventHash(hash));\n }\n\n /**\n * Handles \"statechanged\" events on the plugin. No-op by default, override by\n * subclassing.\n *\n * @abstract\n * @param {Event} e\n * An event object provided by a \"statechanged\" event.\n *\n * @param {Object} e.changes\n * An object describing changes that occurred with the \"statechanged\"\n * event.\n */\n handleStateChanged(e) {}\n\n /**\n * Disposes a plugin.\n *\n * Subclasses can override this if they want, but for the sake of safety,\n * it's probably best to subscribe the \"dispose\" event.\n *\n * @fires Plugin#dispose\n */\n dispose() {\n const {\n name,\n player\n } = this;\n\n /**\n * Signals that a advanced plugin is about to be disposed.\n *\n * @event Plugin#dispose\n * @type {Event}\n */\n this.trigger('dispose');\n this.off();\n player.off('dispose', this.dispose);\n\n // Eliminate any possible sources of leaking memory by clearing up\n // references between the player and the plugin instance and nulling out\n // the plugin's state and replacing methods with a function that throws.\n player[PLUGIN_CACHE_KEY][name] = false;\n this.player = this.state = null;\n\n // Finally, replace the plugin name on the player with a new factory\n // function, so that the plugin is ready to be set up again.\n player[name] = createPluginFactory(name, pluginStorage[name]);\n }\n\n /**\n * Determines if a plugin is a basic plugin (i.e. not a sub-class of `Plugin`).\n *\n * @param {string|Function} plugin\n * If a string, matches the name of a plugin. If a function, will be\n * tested directly.\n *\n * @return {boolean}\n * Whether or not a plugin is a basic plugin.\n */\n static isBasic(plugin) {\n const p = typeof plugin === 'string' ? getPlugin(plugin) : plugin;\n return typeof p === 'function' && !Plugin.prototype.isPrototypeOf(p.prototype);\n }\n\n /**\n * Register a Video.js plugin.\n *\n * @param {string} name\n * The name of the plugin to be registered. Must be a string and\n * must not match an existing plugin or a method on the `Player`\n * prototype.\n *\n * @param {typeof Plugin|Function} plugin\n * A sub-class of `Plugin` or a function for basic plugins.\n *\n * @return {typeof Plugin|Function}\n * For advanced plugins, a factory function for that plugin. For\n * basic plugins, a wrapper function that initializes the plugin.\n */\n static registerPlugin(name, plugin) {\n if (typeof name !== 'string') {\n throw new Error(`Illegal plugin name, \"${name}\", must be a string, was ${typeof name}.`);\n }\n if (pluginExists(name)) {\n log.warn(`A plugin named \"${name}\" already exists. You may want to avoid re-registering plugins!`);\n } else if (Player.prototype.hasOwnProperty(name)) {\n throw new Error(`Illegal plugin name, \"${name}\", cannot share a name with an existing player method!`);\n }\n if (typeof plugin !== 'function') {\n throw new Error(`Illegal plugin for \"${name}\", must be a function, was ${typeof plugin}.`);\n }\n pluginStorage[name] = plugin;\n\n // Add a player prototype method for all sub-classed plugins (but not for\n // the base Plugin class).\n if (name !== BASE_PLUGIN_NAME) {\n if (Plugin.isBasic(plugin)) {\n Player.prototype[name] = createBasicPlugin(name, plugin);\n } else {\n Player.prototype[name] = createPluginFactory(name, plugin);\n }\n }\n return plugin;\n }\n\n /**\n * De-register a Video.js plugin.\n *\n * @param {string} name\n * The name of the plugin to be de-registered. Must be a string that\n * matches an existing plugin.\n *\n * @throws {Error}\n * If an attempt is made to de-register the base plugin.\n */\n static deregisterPlugin(name) {\n if (name === BASE_PLUGIN_NAME) {\n throw new Error('Cannot de-register base plugin.');\n }\n if (pluginExists(name)) {\n delete pluginStorage[name];\n delete Player.prototype[name];\n }\n }\n\n /**\n * Gets an object containing multiple Video.js plugins.\n *\n * @param {Array} [names]\n * If provided, should be an array of plugin names. Defaults to _all_\n * plugin names.\n *\n * @return {Object|undefined}\n * An object containing plugin(s) associated with their name(s) or\n * `undefined` if no matching plugins exist).\n */\n static getPlugins(names = Object.keys(pluginStorage)) {\n let result;\n names.forEach(name => {\n const plugin = getPlugin(name);\n if (plugin) {\n result = result || {};\n result[name] = plugin;\n }\n });\n return result;\n }\n\n /**\n * Gets a plugin's version, if available\n *\n * @param {string} name\n * The name of a plugin.\n *\n * @return {string}\n * The plugin's version or an empty string.\n */\n static getPluginVersion(name) {\n const plugin = getPlugin(name);\n return plugin && plugin.VERSION || '';\n }\n }\n\n /**\n * Gets a plugin by name if it exists.\n *\n * @static\n * @method getPlugin\n * @memberOf Plugin\n * @param {string} name\n * The name of a plugin.\n *\n * @returns {typeof Plugin|Function|undefined}\n * The plugin (or `undefined`).\n */\n Plugin.getPlugin = getPlugin;\n\n /**\n * The name of the base plugin class as it is registered.\n *\n * @type {string}\n */\n Plugin.BASE_PLUGIN_NAME = BASE_PLUGIN_NAME;\n Plugin.registerPlugin(BASE_PLUGIN_NAME, Plugin);\n\n /**\n * Documented in player.js\n *\n * @ignore\n */\n Player.prototype.usingPlugin = function (name) {\n return !!this[PLUGIN_CACHE_KEY] && this[PLUGIN_CACHE_KEY][name] === true;\n };\n\n /**\n * Documented in player.js\n *\n * @ignore\n */\n Player.prototype.hasPlugin = function (name) {\n return !!pluginExists(name);\n };\n\n /**\n * Signals that a plugin is about to be set up on a player.\n *\n * @event Player#beforepluginsetup\n * @type {PluginEventHash}\n */\n\n /**\n * Signals that a plugin is about to be set up on a player - by name. The name\n * is the name of the plugin.\n *\n * @event Player#beforepluginsetup:$name\n * @type {PluginEventHash}\n */\n\n /**\n * Signals that a plugin has just been set up on a player.\n *\n * @event Player#pluginsetup\n * @type {PluginEventHash}\n */\n\n /**\n * Signals that a plugin has just been set up on a player - by name. The name\n * is the name of the plugin.\n *\n * @event Player#pluginsetup:$name\n * @type {PluginEventHash}\n */\n\n /**\n * @typedef {Object} PluginEventHash\n *\n * @property {string} instance\n * For basic plugins, the return value of the plugin function. For\n * advanced plugins, the plugin instance on which the event is fired.\n *\n * @property {string} name\n * The name of the plugin.\n *\n * @property {string} plugin\n * For basic plugins, the plugin function. For advanced plugins, the\n * plugin class/constructor.\n */\n\n /**\n * @file deprecate.js\n * @module deprecate\n */\n\n /**\n * Decorate a function with a deprecation message the first time it is called.\n *\n * @param {string} message\n * A deprecation message to log the first time the returned function\n * is called.\n *\n * @param {Function} fn\n * The function to be deprecated.\n *\n * @return {Function}\n * A wrapper function that will log a deprecation warning the first\n * time it is called. The return value will be the return value of\n * the wrapped function.\n */\n function deprecate(message, fn) {\n let warned = false;\n return function (...args) {\n if (!warned) {\n log.warn(message);\n }\n warned = true;\n return fn.apply(this, args);\n };\n }\n\n /**\n * Internal function used to mark a function as deprecated in the next major\n * version with consistent messaging.\n *\n * @param {number} major The major version where it will be removed\n * @param {string} oldName The old function name\n * @param {string} newName The new function name\n * @param {Function} fn The function to deprecate\n * @return {Function} The decorated function\n */\n function deprecateForMajor(major, oldName, newName, fn) {\n return deprecate(`${oldName} is deprecated and will be removed in ${major}.0; please use ${newName} instead.`, fn);\n }\n\n var VjsErrors = {\n NetworkBadStatus: 'networkbadstatus',\n NetworkRequestFailed: 'networkrequestfailed',\n NetworkRequestAborted: 'networkrequestaborted',\n NetworkRequestTimeout: 'networkrequesttimeout',\n NetworkBodyParserFailed: 'networkbodyparserfailed',\n StreamingHlsPlaylistParserError: 'streaminghlsplaylistparsererror',\n StreamingDashManifestParserError: 'streamingdashmanifestparsererror',\n StreamingContentSteeringParserError: 'streamingcontentsteeringparsererror',\n StreamingVttParserError: 'streamingvttparsererror',\n StreamingFailedToSelectNextSegment: 'streamingfailedtoselectnextsegment',\n StreamingFailedToDecryptSegment: 'streamingfailedtodecryptsegment',\n StreamingFailedToTransmuxSegment: 'streamingfailedtotransmuxsegment',\n StreamingFailedToAppendSegment: 'streamingfailedtoappendsegment',\n StreamingCodecsChangeError: 'streamingcodecschangeerror'\n };\n\n /**\n * @file video.js\n * @module videojs\n */\n\n /** @import { PlayerReadyCallback } from './player' */\n\n /**\n * Normalize an `id` value by trimming off a leading `#`\n *\n * @private\n * @param {string} id\n * A string, maybe with a leading `#`.\n *\n * @return {string}\n * The string, without any leading `#`.\n */\n const normalizeId = id => id.indexOf('#') === 0 ? id.slice(1) : id;\n\n /**\n * The `videojs()` function doubles as the main function for users to create a\n * {@link Player} instance as well as the main library namespace.\n *\n * It can also be used as a getter for a pre-existing {@link Player} instance.\n * However, we _strongly_ recommend using `videojs.getPlayer()` for this\n * purpose because it avoids any potential for unintended initialization.\n *\n * Due to [limitations](https://github.com/jsdoc3/jsdoc/issues/955#issuecomment-313829149)\n * of our JSDoc template, we cannot properly document this as both a function\n * and a namespace, so its function signature is documented here.\n *\n * #### Arguments\n * ##### id\n * string|Element, **required**\n *\n * Video element or video element ID.\n *\n * ##### options\n * Object, optional\n *\n * Options object for providing settings.\n * See: [Options Guide](https://docs.videojs.com/tutorial-options.html).\n *\n * ##### ready\n * {@link Component~ReadyCallback}, optional\n *\n * A function to be called when the {@link Player} and {@link Tech} are ready.\n *\n * #### Return Value\n *\n * The `videojs()` function returns a {@link Player} instance.\n *\n * @namespace\n *\n * @borrows AudioTrack as AudioTrack\n * @borrows Component.getComponent as getComponent\n * @borrows module:events.on as on\n * @borrows module:events.one as one\n * @borrows module:events.off as off\n * @borrows module:events.trigger as trigger\n * @borrows EventTarget as EventTarget\n * @borrows module:middleware.use as use\n * @borrows Player.players as players\n * @borrows Plugin.registerPlugin as registerPlugin\n * @borrows Plugin.deregisterPlugin as deregisterPlugin\n * @borrows Plugin.getPlugins as getPlugins\n * @borrows Plugin.getPlugin as getPlugin\n * @borrows Plugin.getPluginVersion as getPluginVersion\n * @borrows Tech.getTech as getTech\n * @borrows Tech.registerTech as registerTech\n * @borrows TextTrack as TextTrack\n * @borrows VideoTrack as VideoTrack\n *\n * @param {string|Element} id\n * Video element or video element ID.\n *\n * @param {Object} [options]\n * Options object for providing settings.\n * See: [Options Guide](https://docs.videojs.com/tutorial-options.html).\n *\n * @param {PlayerReadyCallback} [ready]\n * A function to be called when the {@link Player} and {@link Tech} are\n * ready.\n *\n * @return {Player}\n * The `videojs()` function returns a {@link Player|Player} instance.\n */\n function videojs(id, options, ready) {\n let player = videojs.getPlayer(id);\n if (player) {\n if (options) {\n log.warn(`Player \"${id}\" is already initialised. Options will not be applied.`);\n }\n if (ready) {\n player.ready(ready);\n }\n return player;\n }\n const el = typeof id === 'string' ? $('#' + normalizeId(id)) : id;\n if (!isEl(el)) {\n throw new TypeError('The element or ID supplied is not valid. (videojs)');\n }\n\n // document.body.contains(el) will only check if el is contained within that one document.\n // This causes problems for elements in iframes.\n // Instead, use the element's ownerDocument instead of the global document.\n // This will make sure that the element is indeed in the dom of that document.\n // Additionally, check that the document in question has a default view.\n // If the document is no longer attached to the dom, the defaultView of the document will be null.\n // If element is inside Shadow DOM (e.g. is part of a Custom element), ownerDocument.body\n // always returns false. Instead, use the Shadow DOM root.\n const inShadowDom = 'getRootNode' in el ? el.getRootNode() instanceof window.ShadowRoot : false;\n const rootNode = inShadowDom ? el.getRootNode() : el.ownerDocument.body;\n if (!el.ownerDocument.defaultView || !rootNode.contains(el)) {\n log.warn('The element supplied is not included in the DOM');\n }\n options = options || {};\n\n // Store a copy of the el before modification, if it is to be restored in destroy()\n // If div ingest, store the parent div\n if (options.restoreEl === true) {\n options.restoreEl = (el.parentNode && el.parentNode.hasAttribute && el.parentNode.hasAttribute('data-vjs-player') ? el.parentNode : el).cloneNode(true);\n }\n hooks('beforesetup').forEach(hookFunction => {\n const opts = hookFunction(el, merge(options));\n if (!isObject(opts) || Array.isArray(opts)) {\n log.error('please return an object in beforesetup hooks');\n return;\n }\n options = merge(options, opts);\n });\n\n // We get the current \"Player\" component here in case an integration has\n // replaced it with a custom player.\n const PlayerComponent = Component.getComponent('Player');\n player = new PlayerComponent(el, options, ready);\n hooks('setup').forEach(hookFunction => hookFunction(player));\n return player;\n }\n videojs.hooks_ = hooks_;\n videojs.hooks = hooks;\n videojs.hook = hook;\n videojs.hookOnce = hookOnce;\n videojs.removeHook = removeHook;\n\n // Add default styles\n if (window.VIDEOJS_NO_DYNAMIC_STYLE !== true && isReal()) {\n let style = $('.vjs-styles-defaults');\n if (!style) {\n style = createStyleElement('vjs-styles-defaults');\n const head = $('head');\n if (head) {\n head.insertBefore(style, head.firstChild);\n }\n setTextContent(style, `\n .video-js {\n width: 300px;\n height: 150px;\n }\n\n .vjs-fluid:not(.vjs-audio-only-mode) {\n padding-top: 56.25%\n }\n `);\n }\n }\n\n // Run Auto-load players\n // You have to wait at least once in case this script is loaded after your\n // video in the DOM (weird behavior only with minified version)\n autoSetupTimeout(1, videojs);\n\n /**\n * Current Video.js version. Follows [semantic versioning](https://semver.org/).\n *\n * @type {string}\n */\n videojs.VERSION = version;\n\n /**\n * The global options object. These are the settings that take effect\n * if no overrides are specified when the player is created.\n *\n * @type {Object}\n */\n videojs.options = Player.prototype.options_;\n\n /**\n * Get an object with the currently created players, keyed by player ID\n *\n * @return {Object}\n * The created players\n */\n videojs.getPlayers = () => Player.players;\n\n /**\n * Get a single player based on an ID or DOM element.\n *\n * This is useful if you want to check if an element or ID has an associated\n * Video.js player, but not create one if it doesn't.\n *\n * @param {string|Element} id\n * An HTML element - `<video>`, `<audio>`, or `<video-js>` -\n * or a string matching the `id` of such an element.\n *\n * @return {Player|undefined}\n * A player instance or `undefined` if there is no player instance\n * matching the argument.\n */\n videojs.getPlayer = id => {\n const players = Player.players;\n let tag;\n if (typeof id === 'string') {\n const nId = normalizeId(id);\n const player = players[nId];\n if (player) {\n return player;\n }\n tag = $('#' + nId);\n } else {\n tag = id;\n }\n if (isEl(tag)) {\n const {\n player,\n playerId\n } = tag;\n\n // Element may have a `player` property referring to an already created\n // player instance. If so, return that.\n if (player || players[playerId]) {\n return player || players[playerId];\n }\n }\n };\n\n /**\n * Returns an array of all current players.\n *\n * @return {Array}\n * An array of all players. The array will be in the order that\n * `Object.keys` provides, which could potentially vary between\n * JavaScript engines.\n *\n */\n videojs.getAllPlayers = () =>\n // Disposed players leave a key with a `null` value, so we need to make sure\n // we filter those out.\n Object.keys(Player.players).map(k => Player.players[k]).filter(Boolean);\n videojs.players = Player.players;\n videojs.getComponent = Component.getComponent;\n\n /**\n * Register a component so it can referred to by name. Used when adding to other\n * components, either through addChild `component.addChild('myComponent')` or through\n * default children options `{ children: ['myComponent'] }`.\n *\n * > NOTE: You could also just initialize the component before adding.\n * `component.addChild(new MyComponent());`\n *\n * @param {string} name\n * The class name of the component\n *\n * @param {typeof Component} comp\n * The component class\n *\n * @return {typeof Component}\n * The newly registered component\n */\n videojs.registerComponent = (name, comp) => {\n if (Tech.isTech(comp)) {\n log.warn(`The ${name} tech was registered as a component. It should instead be registered using videojs.registerTech(name, tech)`);\n }\n return Component.registerComponent.call(Component, name, comp);\n };\n videojs.getTech = Tech.getTech;\n videojs.registerTech = Tech.registerTech;\n videojs.use = use;\n\n /**\n * An object that can be returned by a middleware to signify\n * that the middleware is being terminated.\n *\n * @type {object}\n * @property {object} middleware.TERMINATOR\n */\n Object.defineProperty(videojs, 'middleware', {\n value: {},\n writeable: false,\n enumerable: true\n });\n Object.defineProperty(videojs.middleware, 'TERMINATOR', {\n value: TERMINATOR,\n writeable: false,\n enumerable: true\n });\n\n /**\n * A reference to the {@link module:browser|browser utility module} as an object.\n *\n * @type {Object}\n * @see {@link module:browser|browser}\n */\n videojs.browser = browser;\n\n /**\n * A reference to the {@link module:obj|obj utility module} as an object.\n *\n * @type {Object}\n * @see {@link module:obj|obj}\n */\n videojs.obj = Obj;\n\n /**\n * Deprecated reference to the {@link module:obj.merge|merge function}\n *\n * @type {Function}\n * @see {@link module:obj.merge|merge}\n * @deprecated Deprecated and will be removed in 9.0. Please use videojs.obj.merge instead.\n */\n videojs.mergeOptions = deprecateForMajor(9, 'videojs.mergeOptions', 'videojs.obj.merge', merge);\n\n /**\n * Deprecated reference to the {@link module:obj.defineLazyProperty|defineLazyProperty function}\n *\n * @type {Function}\n * @see {@link module:obj.defineLazyProperty|defineLazyProperty}\n * @deprecated Deprecated and will be removed in 9.0. Please use videojs.obj.defineLazyProperty instead.\n */\n videojs.defineLazyProperty = deprecateForMajor(9, 'videojs.defineLazyProperty', 'videojs.obj.defineLazyProperty', defineLazyProperty);\n\n /**\n * Deprecated reference to the {@link module:fn.bind_|fn.bind_ function}\n *\n * @type {Function}\n * @see {@link module:fn.bind_|fn.bind_}\n * @deprecated Deprecated and will be removed in 9.0. Please use native Function.prototype.bind instead.\n */\n videojs.bind = deprecateForMajor(9, 'videojs.bind', 'native Function.prototype.bind', bind_);\n videojs.registerPlugin = Plugin.registerPlugin;\n videojs.deregisterPlugin = Plugin.deregisterPlugin;\n\n /**\n * Deprecated method to register a plugin with Video.js\n *\n * @deprecated Deprecated and will be removed in 9.0. Use videojs.registerPlugin() instead.\n *\n * @param {string} name\n * The plugin name\n *\n * @param {typeof Plugin|Function} plugin\n * The plugin sub-class or function\n *\n * @return {typeof Plugin|Function}\n */\n videojs.plugin = (name, plugin) => {\n log.warn('videojs.plugin() is deprecated; use videojs.registerPlugin() instead');\n return Plugin.registerPlugin(name, plugin);\n };\n videojs.getPlugins = Plugin.getPlugins;\n videojs.getPlugin = Plugin.getPlugin;\n videojs.getPluginVersion = Plugin.getPluginVersion;\n\n /**\n * Adding languages so that they're available to all players.\n * Example: `videojs.addLanguage('es', { 'Hello': 'Hola' });`\n *\n * @param {string} code\n * The language code or dictionary property\n *\n * @param {Object} data\n * The data values to be translated\n *\n * @return {Object}\n * The resulting language dictionary object\n */\n videojs.addLanguage = function (code, data) {\n code = ('' + code).toLowerCase();\n videojs.options.languages = merge(videojs.options.languages, {\n [code]: data\n });\n return videojs.options.languages[code];\n };\n\n /**\n * A reference to the {@link module:log|log utility module} as an object.\n *\n * @type {Function}\n * @see {@link module:log|log}\n */\n videojs.log = log;\n videojs.createLogger = createLogger;\n\n /**\n * A reference to the {@link module:time|time utility module} as an object.\n *\n * @type {Object}\n * @see {@link module:time|time}\n */\n videojs.time = Time;\n\n /**\n * Deprecated reference to the {@link module:time.createTimeRanges|createTimeRanges function}\n *\n * @type {Function}\n * @see {@link module:time.createTimeRanges|createTimeRanges}\n * @deprecated Deprecated and will be removed in 9.0. Please use videojs.time.createTimeRanges instead.\n */\n videojs.createTimeRange = deprecateForMajor(9, 'videojs.createTimeRange', 'videojs.time.createTimeRanges', createTimeRanges);\n\n /**\n * Deprecated reference to the {@link module:time.createTimeRanges|createTimeRanges function}\n *\n * @type {Function}\n * @see {@link module:time.createTimeRanges|createTimeRanges}\n * @deprecated Deprecated and will be removed in 9.0. Please use videojs.time.createTimeRanges instead.\n */\n videojs.createTimeRanges = deprecateForMajor(9, 'videojs.createTimeRanges', 'videojs.time.createTimeRanges', createTimeRanges);\n\n /**\n * Deprecated reference to the {@link module:time.formatTime|formatTime function}\n *\n * @type {Function}\n * @see {@link module:time.formatTime|formatTime}\n * @deprecated Deprecated and will be removed in 9.0. Please use videojs.time.format instead.\n */\n videojs.formatTime = deprecateForMajor(9, 'videojs.formatTime', 'videojs.time.formatTime', formatTime);\n\n /**\n * Deprecated reference to the {@link module:time.setFormatTime|setFormatTime function}\n *\n * @type {Function}\n * @see {@link module:time.setFormatTime|setFormatTime}\n * @deprecated Deprecated and will be removed in 9.0. Please use videojs.time.setFormat instead.\n */\n videojs.setFormatTime = deprecateForMajor(9, 'videojs.setFormatTime', 'videojs.time.setFormatTime', setFormatTime);\n\n /**\n * Deprecated reference to the {@link module:time.resetFormatTime|resetFormatTime function}\n *\n * @type {Function}\n * @see {@link module:time.resetFormatTime|resetFormatTime}\n * @deprecated Deprecated and will be removed in 9.0. Please use videojs.time.resetFormat instead.\n */\n videojs.resetFormatTime = deprecateForMajor(9, 'videojs.resetFormatTime', 'videojs.time.resetFormatTime', resetFormatTime);\n\n /**\n * Deprecated reference to the {@link module:url.parseUrl|Url.parseUrl function}\n *\n * @type {Function}\n * @see {@link module:url.parseUrl|parseUrl}\n * @deprecated Deprecated and will be removed in 9.0. Please use videojs.url.parseUrl instead.\n */\n videojs.parseUrl = deprecateForMajor(9, 'videojs.parseUrl', 'videojs.url.parseUrl', parseUrl);\n\n /**\n * Deprecated reference to the {@link module:url.isCrossOrigin|Url.isCrossOrigin function}\n *\n * @type {Function}\n * @see {@link module:url.isCrossOrigin|isCrossOrigin}\n * @deprecated Deprecated and will be removed in 9.0. Please use videojs.url.isCrossOrigin instead.\n */\n videojs.isCrossOrigin = deprecateForMajor(9, 'videojs.isCrossOrigin', 'videojs.url.isCrossOrigin', isCrossOrigin);\n videojs.EventTarget = EventTarget;\n videojs.any = any;\n videojs.on = on;\n videojs.one = one;\n videojs.off = off;\n videojs.trigger = trigger;\n\n /**\n * A cross-browser XMLHttpRequest wrapper.\n *\n * @function\n * @param {Object} options\n * Settings for the request.\n *\n * @return {XMLHttpRequest|XDomainRequest}\n * The request object.\n *\n * @see https://github.com/Raynos/xhr\n */\n videojs.xhr = lib;\n videojs.TrackList = TrackList;\n videojs.TextTrack = TextTrack;\n videojs.TextTrackList = TextTrackList;\n videojs.AudioTrack = AudioTrack;\n videojs.AudioTrackList = AudioTrackList;\n videojs.VideoTrack = VideoTrack;\n videojs.VideoTrackList = VideoTrackList;\n ['isEl', 'isTextNode', 'createEl', 'hasClass', 'addClass', 'removeClass', 'toggleClass', 'setAttributes', 'getAttributes', 'emptyEl', 'appendContent', 'insertContent'].forEach(k => {\n videojs[k] = function () {\n log.warn(`videojs.${k}() is deprecated; use videojs.dom.${k}() instead`);\n return Dom[k].apply(null, arguments);\n };\n });\n videojs.computedStyle = deprecateForMajor(9, 'videojs.computedStyle', 'videojs.dom.computedStyle', computedStyle);\n\n /**\n * A reference to the {@link module:dom|DOM utility module} as an object.\n *\n * @type {Object}\n * @see {@link module:dom|dom}\n */\n videojs.dom = Dom;\n\n /**\n * A reference to the {@link module:fn|fn utility module} as an object.\n *\n * @type {Object}\n * @see {@link module:fn|fn}\n */\n videojs.fn = Fn;\n\n /**\n * A reference to the {@link module:num|num utility module} as an object.\n *\n * @type {Object}\n * @see {@link module:num|num}\n */\n videojs.num = Num;\n\n /**\n * A reference to the {@link module:str|str utility module} as an object.\n *\n * @type {Object}\n * @see {@link module:str|str}\n */\n videojs.str = Str;\n\n /**\n * A reference to the {@link module:url|URL utility module} as an object.\n *\n * @type {Object}\n * @see {@link module:url|url}\n */\n videojs.url = Url;\n\n // The list of possible error types to occur in video.js\n videojs.Error = VjsErrors;\n\n return videojs;\n\n}));\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/video.js/dist/alt/video.core.js?");
/***/ }),
/***/ "../node_modules/videojs-per-source-behaviors/dist/videojs-per-source-behaviors.es.js":
/*!********************************************************************************************!*\
!*** ../node_modules/videojs-per-source-behaviors/dist/videojs-per-source-behaviors.es.js ***!
\********************************************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ perSourceBehaviors)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/*! @name videojs-per-source-behaviors @version 3.0.1 @license Apache-2.0 */\n\n\nvar version = \"3.0.1\";\n\nconst Html5 = video_js__WEBPACK_IMPORTED_MODULE_0___default().getTech('Html5'); // Video.js 5/6 cross-compatibility.\n\nconst registerPlugin = (video_js__WEBPACK_IMPORTED_MODULE_0___default().registerPlugin) || (video_js__WEBPACK_IMPORTED_MODULE_0___default().plugin);\n/**\n * For the most part, these are the events that occur early in the lifecycle\n * of a source, but there is considerable variability across browsers and\n * devices (not to mention properties like autoplay and preload). As such, we\n * listen to a bunch of events for source changes.\n *\n * @type {Array}\n */\n\nconst CHANGE_DETECT_EVENTS = ['abort', 'emptied', 'loadstart', 'play'];\n/**\n * These events will indicate that the source is \"unstable\" (i.e. it might be\n * about to change).\n *\n * @type {Array}\n */\n\nconst UNSTABLE_EVENTS = ['abort', 'emptied'];\n/**\n * These are the ad loading and playback states we care about from\n * contrib-ads 5.\n *\n * @type {Array}\n */\n\nconst AD_STATES = ['ad-playback', 'ads-ready?', 'postroll?', 'preroll?'];\n/**\n * Whether or not a string represents an \"ad state\".\n *\n * @param {string} s\n * The string to check\n *\n * @return {boolean}\n * If the string is an ad state\n */\n\nconst isAdState = s => AD_STATES.indexOf(s) > -1;\n/**\n * Determine whether or not a player is using contrib-ads 6+.\n *\n * @param {Player} p\n * The player\n *\n * @return {boolean}\n * if the player is using contrib-ads 6+\n */\n\n\nconst usingAds6Plus = p => p.usingPlugin('ads') && typeof p.ads.inAdBreak === 'function';\n/**\n * Whether or not the player should ignore an event due to ad states.\n *\n * @param {Player} p\n * The player\n *\n * @param {Event} e\n * An event object\n *\n * @return {boolean}\n * If the player is in an ad state\n */\n\n\nconst ignoreEvent = (p, e) => {\n // No ads, no ad states to ignore!\n if (!p.usingPlugin('ads')) {\n return false;\n } // In contrib-ads 6+ we only care about non-loadstart events because\n // loadstart events _may_ happen during ad mode.\n\n\n if (usingAds6Plus(p)) {\n return p.ads.isInAdMode() && e.type !== 'loadstart';\n } // contrib-ads 5+\n\n\n return isAdState(p.ads.state);\n};\n\nlet psbGuid = 0;\n/**\n * Applies per-source behaviors to a video.js Player object.\n */\n\nconst perSourceBehaviors = function () {\n const perSrcListeners = [];\n let cachedSrc;\n let disabled = false;\n let srcChangeTimer;\n let srcStable = true;\n /**\n * Creates an event binder function of a given type.\n *\n * @param {boolean} isOne\n * Rather than delegating to the player's `one()` method, we want to\n * retain full control over when the listener is unbound (particularly\n * due to the ability for per-source behaviors to be toggled on and\n * off at will).\n *\n * @return {Function}\n * the per source binder function\n */\n\n const createPerSrcBinder = isOne => {\n return function (first, second) {\n // Do not bind new listeners when per-source behaviors are disabled.\n if (this.perSourceBehaviors.disabled()) {\n return;\n }\n\n const isTargetPlayer = arguments.length === 2;\n const originalSrc = this.currentSrc(); // This array is the set of arguments to use for `on()` and `off()` methods\n // of the player.\n\n const args = [first]; // Make sure we bind here so that a GUID is set on the original listener\n // and that it is bound to the proper context.\n\n const passedListener = arguments[arguments.length - 1];\n const listenerContext = isTargetPlayer ? this : first;\n const originalListener = passedListener.bind(listenerContext); // The wrapped listener `subargs` are the arguments passed to the original\n // listener (i.e. the Event object and an additional data hash).\n\n const wrappedListener = (...subargs) => {\n const changed = this.currentSrc() !== originalSrc; // Do not evaluate listeners if per-source behaviors are disabled.\n\n if (this.perSourceBehaviors.disabled()) {\n return;\n }\n\n if (changed || isOne) {\n this.off(...args);\n }\n\n if (!changed) {\n originalListener(...subargs);\n }\n }; // Make sure the wrapped listener and the original listener share a GUID,\n // so that video.js properly removes event bindings when `off()` is passed\n // the original listener!\n //\n // This property is used internally by Video.js for tracking bound\n // listeners in its event system. Normally, Video.js creates this `guid`\n // through its `bind` method, but that method is deprecated in public\n // interfaces.\n //\n // Basically, this allows us to avoid deprecation warnings from calling\n // `videojs.bind` when used with Video.js 8.\n\n\n wrappedListener.guid = originalListener.guid = passedListener.guid = `psb-${++psbGuid}`; // If we are targeting a different object from the player, we need to include\n // the second argument.\n\n if (!isTargetPlayer) {\n args.push(second);\n }\n\n args.push(wrappedListener);\n perSrcListeners.push(args);\n return this.on(...args);\n };\n };\n\n this.perSourceBehaviors = {\n /**\n * Disable per-source behaviors on this player.\n *\n * @return {boolean}\n */\n disable: function disable() {\n this.clearTimeout(srcChangeTimer);\n srcChangeTimer = null;\n disabled = true;\n return disabled;\n }.bind(this),\n\n /**\n * Whether per-source behaviors are disabled on this player.\n *\n * @return {boolean}\n * if the per-source behaviors are disabled\n */\n disabled() {\n return disabled;\n },\n\n /**\n * Enable per-source behaviors on this player.\n *\n * @return {boolean}\n * always returns true\n */\n enable() {\n disabled = false;\n return disabled;\n },\n\n /**\n * Whether per-source behaviors are disabled on this player.\n *\n * @return {boolean}\n * if the per-source behaviors are enabled\n */\n enabled() {\n return !disabled;\n },\n\n /**\n * Whether or not the source is \"stable\". This will return `true` if the\n * plugin feels that we may be about to change sources.\n *\n * @return {boolean}\n * Whether the source is stable or not\n */\n isSrcStable() {\n return srcStable;\n },\n\n VERSION: version\n };\n /**\n * Bind an event listener on a per-source basis.\n *\n * @function onPerSrc\n * @param {String|Array|Component|Element} first\n * The event type(s) or target Component or Element.\n *\n * @param {Function|String|Array} second\n * The event listener or event type(s) (when `first` is target).\n *\n * @param {Function} third\n * The event listener (when `second` is event type(s)).\n *\n * @return {Player}\n */\n\n this.onPerSrc = createPerSrcBinder();\n /**\n * Bind an event listener on a per-source basis. This listener can only\n * be called once.\n *\n * @function onePerSrc\n * @param {String|Array|Component|Element} first\n * The event type(s) or target Component or Element.\n *\n * @param {Function|String|Array} second\n * The event listener or event type(s) (when `first` is target).\n *\n * @param {Function} third\n * The event listener (when `second` is event type(s)).\n *\n * @return {Player}\n */\n\n this.onePerSrc = createPerSrcBinder(true); // Clear out perSrcListeners cache on player dispose.\n\n this.on('dispose', () => {\n perSrcListeners.length = 0;\n });\n this.on(CHANGE_DETECT_EVENTS, e => {\n // Bail-out conditions.\n if (this.perSourceBehaviors.disabled() || srcChangeTimer || ignoreEvent(this, e)) {\n return;\n } // If we did not previously detect that we were in an unstable state and\n // this was an event that qualifies as unstable, do that now. In the future,\n // we may want to restrict the conditions under which this is triggered by\n // checking networkState and/or readyState for reasonable values such as\n // NETWORK_NO_SOURCE and HAVE_NOTHING.\n\n\n if (srcStable && UNSTABLE_EVENTS.indexOf(e.type) > -1) {\n srcStable = false;\n this.trigger('sourceunstable');\n } // Track any and all interim events from this one until the next tick\n // when we evaluate the timer.\n\n\n const interimEvents = [];\n\n const addInterimEvent = f => interimEvents.push({\n time: Date.now(),\n event: f\n });\n\n addInterimEvent(e);\n this.on(Html5.Events, addInterimEvent);\n srcChangeTimer = this.setTimeout(() => {\n const currentSrc = this.currentSrc();\n srcStable = true;\n srcChangeTimer = null;\n this.off(Html5.Events, addInterimEvent);\n\n if (currentSrc && currentSrc !== cachedSrc) {\n // Remove per-source listeners explicitly when we know the source has\n // changed before we trigger the \"sourcechanged\" listener.\n perSrcListeners.forEach(args => this.off(...args));\n perSrcListeners.length = 0;\n this.trigger('sourcechanged', {\n interimEvents,\n from: cachedSrc,\n to: currentSrc\n });\n cachedSrc = currentSrc;\n }\n }, 1);\n });\n};\n\nperSourceBehaviors.VERSION = version;\nregisterPlugin('perSourceBehaviors', perSourceBehaviors);\n\n\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/videojs-per-source-behaviors/dist/videojs-per-source-behaviors.es.js?");
/***/ }),
/***/ "../node_modules/webfontloader/webfontloader.js":
/*!******************************************************!*\
!*** ../node_modules/webfontloader/webfontloader.js ***!
\******************************************************/
/***/ ((module, exports, __webpack_require__) => {
eval("var __WEBPACK_AMD_DEFINE_RESULT__;/* Web Font Loader v1.6.28 - (c) Adobe Systems, Google. License: Apache 2.0 */(function(){function aa(a,b,c){return a.call.apply(a.bind,arguments)}function ba(a,b,c){if(!a)throw Error();if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}}function p(a,b,c){p=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf(\"native code\")?aa:ba;return p.apply(null,arguments)}var q=Date.now||function(){return+new Date};function ca(a,b){this.a=a;this.o=b||a;this.c=this.o.document}var da=!!window.FontFace;function t(a,b,c,d){b=a.c.createElement(b);if(c)for(var e in c)c.hasOwnProperty(e)&&(\"style\"==e?b.style.cssText=c[e]:b.setAttribute(e,c[e]));d&&b.appendChild(a.c.createTextNode(d));return b}function u(a,b,c){a=a.c.getElementsByTagName(b)[0];a||(a=document.documentElement);a.insertBefore(c,a.lastChild)}function v(a){a.parentNode&&a.parentNode.removeChild(a)}\nfunction w(a,b,c){b=b||[];c=c||[];for(var d=a.className.split(/\\s+/),e=0;e<b.length;e+=1){for(var f=!1,g=0;g<d.length;g+=1)if(b[e]===d[g]){f=!0;break}f||d.push(b[e])}b=[];for(e=0;e<d.length;e+=1){f=!1;for(g=0;g<c.length;g+=1)if(d[e]===c[g]){f=!0;break}f||b.push(d[e])}a.className=b.join(\" \").replace(/\\s+/g,\" \").replace(/^\\s+|\\s+$/,\"\")}function y(a,b){for(var c=a.className.split(/\\s+/),d=0,e=c.length;d<e;d++)if(c[d]==b)return!0;return!1}\nfunction ea(a){return a.o.location.hostname||a.a.location.hostname}function z(a,b,c){function d(){m&&e&&f&&(m(g),m=null)}b=t(a,\"link\",{rel:\"stylesheet\",href:b,media:\"all\"});var e=!1,f=!0,g=null,m=c||null;da?(b.onload=function(){e=!0;d()},b.onerror=function(){e=!0;g=Error(\"Stylesheet failed to load\");d()}):setTimeout(function(){e=!0;d()},0);u(a,\"head\",b)}\nfunction A(a,b,c,d){var e=a.c.getElementsByTagName(\"head\")[0];if(e){var f=t(a,\"script\",{src:b}),g=!1;f.onload=f.onreadystatechange=function(){g||this.readyState&&\"loaded\"!=this.readyState&&\"complete\"!=this.readyState||(g=!0,c&&c(null),f.onload=f.onreadystatechange=null,\"HEAD\"==f.parentNode.tagName&&e.removeChild(f))};e.appendChild(f);setTimeout(function(){g||(g=!0,c&&c(Error(\"Script load timeout\")))},d||5E3);return f}return null};function B(){this.a=0;this.c=null}function C(a){a.a++;return function(){a.a--;D(a)}}function E(a,b){a.c=b;D(a)}function D(a){0==a.a&&a.c&&(a.c(),a.c=null)};function F(a){this.a=a||\"-\"}F.prototype.c=function(a){for(var b=[],c=0;c<arguments.length;c++)b.push(arguments[c].replace(/[\\W_]+/g,\"\").toLowerCase());return b.join(this.a)};function G(a,b){this.c=a;this.f=4;this.a=\"n\";var c=(b||\"n4\").match(/^([nio])([1-9])$/i);c&&(this.a=c[1],this.f=parseInt(c[2],10))}function fa(a){return H(a)+\" \"+(a.f+\"00\")+\" 300px \"+I(a.c)}function I(a){var b=[];a=a.split(/,\\s*/);for(var c=0;c<a.length;c++){var d=a[c].replace(/['\"]/g,\"\");-1!=d.indexOf(\" \")||/^\\d/.test(d)?b.push(\"'\"+d+\"'\"):b.push(d)}return b.join(\",\")}function J(a){return a.a+a.f}function H(a){var b=\"normal\";\"o\"===a.a?b=\"oblique\":\"i\"===a.a&&(b=\"italic\");return b}\nfunction ga(a){var b=4,c=\"n\",d=null;a&&((d=a.match(/(normal|oblique|italic)/i))&&d[1]&&(c=d[1].substr(0,1).toLowerCase()),(d=a.match(/([1-9]00|normal|bold)/i))&&d[1]&&(/bold/i.test(d[1])?b=7:/[1-9]00/.test(d[1])&&(b=parseInt(d[1].substr(0,1),10))));return c+b};function ha(a,b){this.c=a;this.f=a.o.document.documentElement;this.h=b;this.a=new F(\"-\");this.j=!1!==b.events;this.g=!1!==b.classes}function ia(a){a.g&&w(a.f,[a.a.c(\"wf\",\"loading\")]);K(a,\"loading\")}function L(a){if(a.g){var b=y(a.f,a.a.c(\"wf\",\"active\")),c=[],d=[a.a.c(\"wf\",\"loading\")];b||c.push(a.a.c(\"wf\",\"inactive\"));w(a.f,c,d)}K(a,\"inactive\")}function K(a,b,c){if(a.j&&a.h[b])if(c)a.h[b](c.c,J(c));else a.h[b]()};function ja(){this.c={}}function ka(a,b,c){var d=[],e;for(e in b)if(b.hasOwnProperty(e)){var f=a.c[e];f&&d.push(f(b[e],c))}return d};function M(a,b){this.c=a;this.f=b;this.a=t(this.c,\"span\",{\"aria-hidden\":\"true\"},this.f)}function N(a){u(a.c,\"body\",a.a)}function O(a){return\"display:block;position:absolute;top:-9999px;left:-9999px;font-size:300px;width:auto;height:auto;line-height:normal;margin:0;padding:0;font-variant:normal;white-space:nowrap;font-family:\"+I(a.c)+\";\"+(\"font-style:\"+H(a)+\";font-weight:\"+(a.f+\"00\")+\";\")};function P(a,b,c,d,e,f){this.g=a;this.j=b;this.a=d;this.c=c;this.f=e||3E3;this.h=f||void 0}P.prototype.start=function(){var a=this.c.o.document,b=this,c=q(),d=new Promise(function(d,e){function f(){q()-c>=b.f?e():a.fonts.load(fa(b.a),b.h).then(function(a){1<=a.length?d():setTimeout(f,25)},function(){e()})}f()}),e=null,f=new Promise(function(a,d){e=setTimeout(d,b.f)});Promise.race([f,d]).then(function(){e&&(clearTimeout(e),e=null);b.g(b.a)},function(){b.j(b.a)})};function Q(a,b,c,d,e,f,g){this.v=a;this.B=b;this.c=c;this.a=d;this.s=g||\"BESbswy\";this.f={};this.w=e||3E3;this.u=f||null;this.m=this.j=this.h=this.g=null;this.g=new M(this.c,this.s);this.h=new M(this.c,this.s);this.j=new M(this.c,this.s);this.m=new M(this.c,this.s);a=new G(this.a.c+\",serif\",J(this.a));a=O(a);this.g.a.style.cssText=a;a=new G(this.a.c+\",sans-serif\",J(this.a));a=O(a);this.h.a.style.cssText=a;a=new G(\"serif\",J(this.a));a=O(a);this.j.a.style.cssText=a;a=new G(\"sans-serif\",J(this.a));a=\nO(a);this.m.a.style.cssText=a;N(this.g);N(this.h);N(this.j);N(this.m)}var R={D:\"serif\",C:\"sans-serif\"},S=null;function T(){if(null===S){var a=/AppleWebKit\\/([0-9]+)(?:\\.([0-9]+))/.exec(window.navigator.userAgent);S=!!a&&(536>parseInt(a[1],10)||536===parseInt(a[1],10)&&11>=parseInt(a[2],10))}return S}Q.prototype.start=function(){this.f.serif=this.j.a.offsetWidth;this.f[\"sans-serif\"]=this.m.a.offsetWidth;this.A=q();U(this)};\nfunction la(a,b,c){for(var d in R)if(R.hasOwnProperty(d)&&b===a.f[R[d]]&&c===a.f[R[d]])return!0;return!1}function U(a){var b=a.g.a.offsetWidth,c=a.h.a.offsetWidth,d;(d=b===a.f.serif&&c===a.f[\"sans-serif\"])||(d=T()&&la(a,b,c));d?q()-a.A>=a.w?T()&&la(a,b,c)&&(null===a.u||a.u.hasOwnProperty(a.a.c))?V(a,a.v):V(a,a.B):ma(a):V(a,a.v)}function ma(a){setTimeout(p(function(){U(this)},a),50)}function V(a,b){setTimeout(p(function(){v(this.g.a);v(this.h.a);v(this.j.a);v(this.m.a);b(this.a)},a),0)};function W(a,b,c){this.c=a;this.a=b;this.f=0;this.m=this.j=!1;this.s=c}var X=null;W.prototype.g=function(a){var b=this.a;b.g&&w(b.f,[b.a.c(\"wf\",a.c,J(a).toString(),\"active\")],[b.a.c(\"wf\",a.c,J(a).toString(),\"loading\"),b.a.c(\"wf\",a.c,J(a).toString(),\"inactive\")]);K(b,\"fontactive\",a);this.m=!0;na(this)};\nW.prototype.h=function(a){var b=this.a;if(b.g){var c=y(b.f,b.a.c(\"wf\",a.c,J(a).toString(),\"active\")),d=[],e=[b.a.c(\"wf\",a.c,J(a).toString(),\"loading\")];c||d.push(b.a.c(\"wf\",a.c,J(a).toString(),\"inactive\"));w(b.f,d,e)}K(b,\"fontinactive\",a);na(this)};function na(a){0==--a.f&&a.j&&(a.m?(a=a.a,a.g&&w(a.f,[a.a.c(\"wf\",\"active\")],[a.a.c(\"wf\",\"loading\"),a.a.c(\"wf\",\"inactive\")]),K(a,\"active\")):L(a.a))};function oa(a){this.j=a;this.a=new ja;this.h=0;this.f=this.g=!0}oa.prototype.load=function(a){this.c=new ca(this.j,a.context||this.j);this.g=!1!==a.events;this.f=!1!==a.classes;pa(this,new ha(this.c,a),a)};\nfunction qa(a,b,c,d,e){var f=0==--a.h;(a.f||a.g)&&setTimeout(function(){var a=e||null,m=d||null||{};if(0===c.length&&f)L(b.a);else{b.f+=c.length;f&&(b.j=f);var h,l=[];for(h=0;h<c.length;h++){var k=c[h],n=m[k.c],r=b.a,x=k;r.g&&w(r.f,[r.a.c(\"wf\",x.c,J(x).toString(),\"loading\")]);K(r,\"fontloading\",x);r=null;if(null===X)if(window.FontFace){var x=/Gecko.*Firefox\\/(\\d+)/.exec(window.navigator.userAgent),xa=/OS X.*Version\\/10\\..*Safari/.exec(window.navigator.userAgent)&&/Apple/.exec(window.navigator.vendor);\nX=x?42<parseInt(x[1],10):xa?!1:!0}else X=!1;X?r=new P(p(b.g,b),p(b.h,b),b.c,k,b.s,n):r=new Q(p(b.g,b),p(b.h,b),b.c,k,b.s,a,n);l.push(r)}for(h=0;h<l.length;h++)l[h].start()}},0)}function pa(a,b,c){var d=[],e=c.timeout;ia(b);var d=ka(a.a,c,a.c),f=new W(a.c,b,e);a.h=d.length;b=0;for(c=d.length;b<c;b++)d[b].load(function(b,d,c){qa(a,f,b,d,c)})};function ra(a,b){this.c=a;this.a=b}\nra.prototype.load=function(a){function b(){if(f[\"__mti_fntLst\"+d]){var c=f[\"__mti_fntLst\"+d](),e=[],h;if(c)for(var l=0;l<c.length;l++){var k=c[l].fontfamily;void 0!=c[l].fontStyle&&void 0!=c[l].fontWeight?(h=c[l].fontStyle+c[l].fontWeight,e.push(new G(k,h))):e.push(new G(k))}a(e)}else setTimeout(function(){b()},50)}var c=this,d=c.a.projectId,e=c.a.version;if(d){var f=c.c.o;A(this.c,(c.a.api||\"https://fast.fonts.net/jsapi\")+\"/\"+d+\".js\"+(e?\"?v=\"+e:\"\"),function(e){e?a([]):(f[\"__MonotypeConfiguration__\"+\nd]=function(){return c.a},b())}).id=\"__MonotypeAPIScript__\"+d}else a([])};function sa(a,b){this.c=a;this.a=b}sa.prototype.load=function(a){var b,c,d=this.a.urls||[],e=this.a.families||[],f=this.a.testStrings||{},g=new B;b=0;for(c=d.length;b<c;b++)z(this.c,d[b],C(g));var m=[];b=0;for(c=e.length;b<c;b++)if(d=e[b].split(\":\"),d[1])for(var h=d[1].split(\",\"),l=0;l<h.length;l+=1)m.push(new G(d[0],h[l]));else m.push(new G(d[0]));E(g,function(){a(m,f)})};function ta(a,b){a?this.c=a:this.c=ua;this.a=[];this.f=[];this.g=b||\"\"}var ua=\"https://fonts.googleapis.com/css\";function va(a,b){for(var c=b.length,d=0;d<c;d++){var e=b[d].split(\":\");3==e.length&&a.f.push(e.pop());var f=\"\";2==e.length&&\"\"!=e[1]&&(f=\":\");a.a.push(e.join(f))}}\nfunction wa(a){if(0==a.a.length)throw Error(\"No fonts to load!\");if(-1!=a.c.indexOf(\"kit=\"))return a.c;for(var b=a.a.length,c=[],d=0;d<b;d++)c.push(a.a[d].replace(/ /g,\"+\"));b=a.c+\"?family=\"+c.join(\"%7C\");0<a.f.length&&(b+=\"&subset=\"+a.f.join(\",\"));0<a.g.length&&(b+=\"&text=\"+encodeURIComponent(a.g));return b};function ya(a){this.f=a;this.a=[];this.c={}}\nvar za={latin:\"BESbswy\",\"latin-ext\":\"\\u00e7\\u00f6\\u00fc\\u011f\\u015f\",cyrillic:\"\\u0439\\u044f\\u0416\",greek:\"\\u03b1\\u03b2\\u03a3\",khmer:\"\\u1780\\u1781\\u1782\",Hanuman:\"\\u1780\\u1781\\u1782\"},Aa={thin:\"1\",extralight:\"2\",\"extra-light\":\"2\",ultralight:\"2\",\"ultra-light\":\"2\",light:\"3\",regular:\"4\",book:\"4\",medium:\"5\",\"semi-bold\":\"6\",semibold:\"6\",\"demi-bold\":\"6\",demibold:\"6\",bold:\"7\",\"extra-bold\":\"8\",extrabold:\"8\",\"ultra-bold\":\"8\",ultrabold:\"8\",black:\"9\",heavy:\"9\",l:\"3\",r:\"4\",b:\"7\"},Ba={i:\"i\",italic:\"i\",n:\"n\",normal:\"n\"},\nCa=/^(thin|(?:(?:extra|ultra)-?)?light|regular|book|medium|(?:(?:semi|demi|extra|ultra)-?)?bold|black|heavy|l|r|b|[1-9]00)?(n|i|normal|italic)?$/;\nfunction Da(a){for(var b=a.f.length,c=0;c<b;c++){var d=a.f[c].split(\":\"),e=d[0].replace(/\\+/g,\" \"),f=[\"n4\"];if(2<=d.length){var g;var m=d[1];g=[];if(m)for(var m=m.split(\",\"),h=m.length,l=0;l<h;l++){var k;k=m[l];if(k.match(/^[\\w-]+$/)){var n=Ca.exec(k.toLowerCase());if(null==n)k=\"\";else{k=n[2];k=null==k||\"\"==k?\"n\":Ba[k];n=n[1];if(null==n||\"\"==n)n=\"4\";else var r=Aa[n],n=r?r:isNaN(n)?\"4\":n.substr(0,1);k=[k,n].join(\"\")}}else k=\"\";k&&g.push(k)}0<g.length&&(f=g);3==d.length&&(d=d[2],g=[],d=d?d.split(\",\"):\ng,0<d.length&&(d=za[d[0]])&&(a.c[e]=d))}a.c[e]||(d=za[e])&&(a.c[e]=d);for(d=0;d<f.length;d+=1)a.a.push(new G(e,f[d]))}};function Ea(a,b){this.c=a;this.a=b}var Fa={Arimo:!0,Cousine:!0,Tinos:!0};Ea.prototype.load=function(a){var b=new B,c=this.c,d=new ta(this.a.api,this.a.text),e=this.a.families;va(d,e);var f=new ya(e);Da(f);z(c,wa(d),C(b));E(b,function(){a(f.a,f.c,Fa)})};function Ga(a,b){this.c=a;this.a=b}Ga.prototype.load=function(a){var b=this.a.id,c=this.c.o;b?A(this.c,(this.a.api||\"https://use.typekit.net\")+\"/\"+b+\".js\",function(b){if(b)a([]);else if(c.Typekit&&c.Typekit.config&&c.Typekit.config.fn){b=c.Typekit.config.fn;for(var e=[],f=0;f<b.length;f+=2)for(var g=b[f],m=b[f+1],h=0;h<m.length;h++)e.push(new G(g,m[h]));try{c.Typekit.load({events:!1,classes:!1,async:!0})}catch(l){}a(e)}},2E3):a([])};function Ha(a,b){this.c=a;this.f=b;this.a=[]}Ha.prototype.load=function(a){var b=this.f.id,c=this.c.o,d=this;b?(c.__webfontfontdeckmodule__||(c.__webfontfontdeckmodule__={}),c.__webfontfontdeckmodule__[b]=function(b,c){for(var g=0,m=c.fonts.length;g<m;++g){var h=c.fonts[g];d.a.push(new G(h.name,ga(\"font-weight:\"+h.weight+\";font-style:\"+h.style)))}a(d.a)},A(this.c,(this.f.api||\"https://f.fontdeck.com/s/css/js/\")+ea(this.c)+\"/\"+b+\".js\",function(b){b&&a([])})):a([])};var Y=new oa(window);Y.a.c.custom=function(a,b){return new sa(b,a)};Y.a.c.fontdeck=function(a,b){return new Ha(b,a)};Y.a.c.monotype=function(a,b){return new ra(b,a)};Y.a.c.typekit=function(a,b){return new Ga(b,a)};Y.a.c.google=function(a,b){return new Ea(b,a)};var Z={load:p(Y.load,Y)}; true?!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(){return Z}).call(exports, __webpack_require__, exports, module),\n\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)):0;}());\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/webfontloader/webfontloader.js?");
/***/ }),
/***/ "../node_modules/cloudinary-video-player-profiles/dist/index.js":
/*!**********************************************************************!*\
!*** ../node_modules/cloudinary-video-player-profiles/dist/index.js ***!
\**********************************************************************/
/***/ ((__unused_webpack_module, exports) => {
eval("var e={607:function(e,o,t){var l=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(o,\"__esModule\",{value:!0}),o.defaultProfiles=o.cldLiveStreamingProfile=o.cldAdaptiveStreamProfile=o.cldLoopingProfile=o.cldDefaultProfile=void 0;const r=l(t(704)),i=l(t(83)),a=l(t(832)),s=l(t(877));o.cldDefaultProfile={name:\"cld-default\",isDefault:!0,config:r.default},o.cldLoopingProfile={name:\"cld-looping\",isDefault:!0,config:i.default},o.cldAdaptiveStreamProfile={name:\"cld-adaptive-stream\",isDefault:!0,config:a.default},o.cldLiveStreamingProfile={name:\"cld-live-streaming\",isDefault:!0,config:s.default},o.defaultProfiles=[o.cldDefaultProfile,o.cldLoopingProfile,o.cldAdaptiveStreamProfile,o.cldLiveStreamingProfile]},832:e=>{e.exports=JSON.parse('{\"playerOptions\":{\"fluid\":true,\"controls\":true,\"controlBar\":{\"fullscreenToggle\":false},\"showJumpControls\":true,\"hideContextMenu\":false,\"floatingWhenNotVisible\":\"none\"},\"sourceOptions\":{\"chapters\":true,\"sourceTypes\":[\"hls\"]}}')},704:e=>{e.exports=JSON.parse('{\"playerOptions\":{},\"sourceOptions\":{}}')},877:e=>{e.exports=JSON.parse('{\"playerOptions\":{},\"sourceOptions\":{\"type\":\"live\",\"sourceTypes\":[\"hls\"]}}')},83:e=>{e.exports=JSON.parse('{\"playerOptions\":{\"fluid\":true,\"controls\":false,\"muted\":true,\"floatingWhenNotVisible\":\"none\",\"hideContextMenu\":false,\"autoplay\":true,\"loop\":true},\"sourceOptions\":{}}')}},o={},t=function t(l){var r=o[l];if(void 0!==r)return r.exports;var i=o[l]={exports:{}};return e[l].call(i.exports,i,i.exports,t),i.exports}(607),l=exports;for(var r in t)l[r]=t[r];t.__esModule&&Object.defineProperty(l,\"__esModule\",{value:!0});\n//# sourceMappingURL=index.js.map\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/cloudinary-video-player-profiles/dist/index.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/condition.js":
/*!******************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/condition.js ***!
\******************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _expression_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./expression.js */ \"../node_modules/@cloudinary/url-gen/backwards/expression.js\");\n\n/**\n * Represents a transformation condition.\n * @param {string} conditionStr - a condition in string format\n * @class Condition\n * @example\n * // normally this class is not instantiated directly\n * var tr = cloudinary.Transformation.new()\n * .if().width( \">\", 1000).and().aspectRatio(\"<\", \"3:4\").then()\n * .width(1000)\n * .crop(\"scale\")\n * .else()\n * .width(500)\n * .crop(\"scale\")\n *\n * var tr = cloudinary.Transformation.new()\n * .if(\"w > 1000 and aspectRatio < 3:4\")\n * .width(1000)\n * .crop(\"scale\")\n * .else()\n * .width(500)\n * .crop(\"scale\")\n *\n */\nclass Condition extends _expression_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n constructor(conditionStr) {\n super(conditionStr);\n }\n /**\n * @function Condition#height\n * @param {string} operator the comparison operator (e.g. \"<\", \"lt\")\n * @param {string|number} value the right hand side value\n * @return {Condition} this condition\n */\n height(operator, value) {\n return this.predicate(\"h\", operator, value);\n }\n /**\n * @function Condition#width\n * @param {string} operator the comparison operator (e.g. \"<\", \"lt\")\n * @param {string|number} value the right hand side value\n * @return {Condition} this condition\n */\n width(operator, value) {\n return this.predicate(\"w\", operator, value);\n }\n /**\n * @function Condition#aspectRatio\n * @param {string} operator the comparison operator (e.g. \"<\", \"lt\")\n * @param {string|number} value the right hand side value\n * @return {Condition} this condition\n */\n aspectRatio(operator, value) {\n return this.predicate(\"ar\", operator, value);\n }\n /**\n * @function Condition#pages\n * @param {string} operator the comparison operator (e.g. \"<\", \"lt\")\n * @param {string|number} value the right hand side value\n * @return {Condition} this condition\n */\n pageCount(operator, value) {\n return this.predicate(\"pc\", operator, value);\n }\n /**\n * @function Condition#faces\n * @param {string} operator the comparison operator (e.g. \"<\", \"lt\")\n * @param {string|number} value the right hand side value\n * @return {Condition} this condition\n */\n faceCount(operator, value) {\n return this.predicate(\"fc\", operator, value);\n }\n /**\n * @function Condition#duration\n * @param {string} operator the comparison operator (e.g. \"<\", \"lt\")\n * @param {string|number} value the right hand side value\n * @return {Condition} this condition\n */\n duration(operator, value) {\n return this.predicate(\"du\", operator, value);\n }\n /**\n * @function Condition#initialDuration\n * @param {string} operator the comparison operator (e.g. \"<\", \"lt\")\n * @param {string|number} value the right hand side value\n * @return {Condition} this condition\n */\n initialDuration(operator, value) {\n return this.predicate(\"idu\", operator, value);\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Condition);\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/condition.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/configuration.js":
/*!**********************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/configuration.js ***!
\**********************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ CONFIG_PARAMS: () => (/* binding */ CONFIG_PARAMS),\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _internal_utils_cloneDeep_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../internal/utils/cloneDeep.js */ \"../node_modules/@cloudinary/url-gen/internal/utils/cloneDeep.js\");\n/* harmony import */ var _utils_isObject_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils/isObject.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/isObject.js\");\n\n\n/**\n * Class for defining account configuration options.\n * Depends on 'utils'\n */\n/**\n * Assign values from sources if they are not defined in the destination.\n * Once a value is set it does not change\n * @function Util.defaults\n * @param {Object} destination - the object to assign defaults to\n * @param sources\n * @param {...Object} source - the source object(s) to assign defaults from\n * @return {Object} destination after it was modified\n */\nconst useDefaultValues = (destination, ...sources) => {\n return sources.reduce(function (dest, source) {\n let key, value;\n for (key in source) {\n // @ts-ignore\n value = source[key];\n // @ts-ignore\n if (dest[key] === void 0) {\n // @ts-ignore\n dest[key] = value;\n }\n }\n return dest;\n }, destination);\n};\n/**\n * Class for defining account configuration options.\n * @constructor Configuration\n * @param {Object} options - The account configuration parameters to set.\n * @see <a href=\"https://cloudinary.com/documentation/solution_overview#configuration_parameters\"\n * target=\"_new\">Available configuration options</a>\n */\nclass Configuration {\n constructor(options) {\n this.configuration = options == null ? {} : (0,_internal_utils_cloneDeep_js__WEBPACK_IMPORTED_MODULE_0__.cloneDeep)(options);\n useDefaultValues(this.configuration, DEFAULT_CONFIGURATION_PARAMS);\n }\n /**\n * Initializes the configuration. This method is a convenience method that invokes both\n * {@link Configuration#fromEnvironment|fromEnvironment()} (Node.js environment only)\n * and {@link Configuration#fromDocument|fromDocument()}.\n * It first tries to retrieve the configuration from the environment variable.\n * If not available, it tries from the document meta tags.\n * @function Configuration#init\n * @return {Configuration} returns `this` for chaining\n * @see fromDocument\n * @see fromEnvironment\n */\n init() {\n this.fromEnvironment();\n this.fromDocument();\n return this;\n }\n /**\n * Set a new configuration item\n * @function Configuration#set\n * @param {string} name - the name of the item to set\n * @param {*} value - the value to be set\n * @return {Configuration}\n *\n */\n set(name, value) {\n // @ts-ignore\n this.configuration[name] = value;\n return this;\n }\n /**\n * Get the value of a configuration item\n * @function Configuration#get\n * @param {string} name - the name of the item to set\n * @return {*} the configuration item\n */\n get(name) {\n return this.configuration[name];\n }\n merge(config) {\n Object.assign(this.configuration, (0,_internal_utils_cloneDeep_js__WEBPACK_IMPORTED_MODULE_0__.cloneDeep)(config));\n return this;\n }\n /**\n * Initialize Cloudinary from HTML meta tags.\n * @function Configuration#fromDocument\n * @return {Configuration}\n * @example <meta name=\"cloudinary_cloud_name\" content=\"mycloud\">\n *\n */\n fromDocument() {\n var el, i, len, meta_elements;\n meta_elements = typeof document !== \"undefined\" && document !== null ? document.querySelectorAll('meta[name^=\"cloudinary_\"]') : void 0;\n if (meta_elements) {\n for (i = 0, len = meta_elements.length; i < len; i++) {\n el = meta_elements[i];\n this.configuration[el.getAttribute('name').replace('cloudinary_', '')] = el.getAttribute('content');\n }\n }\n return this;\n }\n /**\n * Initialize Cloudinary from the `CLOUDINARY_URL` environment variable.\n *\n * This function will only run under Node.js environment.\n * @function Configuration#fromEnvironment\n * @requires Node.js\n */\n fromEnvironment() {\n var cloudinary_url, query, uri, uriRegex;\n if (typeof process !== \"undefined\" && process !== null && process.env && process.env.CLOUDINARY_URL) {\n cloudinary_url = process.env.CLOUDINARY_URL;\n uriRegex = /cloudinary:\\/\\/(?:(\\w+)(?:\\:([\\w-]+))?@)?([\\w\\.-]+)(?:\\/([^?]*))?(?:\\?(.+))?/;\n uri = uriRegex.exec(cloudinary_url);\n if (uri) {\n if (uri[3] != null) {\n this.configuration['cloud_name'] = uri[3];\n }\n if (uri[1] != null) {\n this.configuration['api_key'] = uri[1];\n }\n if (uri[2] != null) {\n this.configuration['api_secret'] = uri[2];\n }\n if (uri[4] != null) {\n this.configuration['private_cdn'] = uri[4] != null;\n }\n if (uri[4] != null) {\n this.configuration['secure_distribution'] = uri[4];\n }\n query = uri[5];\n if (query != null) {\n query.split('&').forEach(value => {\n let [k, v] = value.split('=');\n if (v == null) {\n // @ts-ignore\n v = true;\n }\n this.configuration[k] = v;\n });\n }\n }\n }\n return this;\n }\n /**\n * Create or modify the Cloudinary client configuration\n *\n * Warning: `config()` returns the actual internal configuration object. modifying it will change the configuration.\n *\n * This is a backward compatibility method. For new code, use get(), merge() etc.\n * @function Configuration#config\n * @param {hash|string|boolean} new_config\n * @param {string} new_value\n * @returns {*} configuration, or value\n *\n * @see {@link fromEnvironment} for initialization using environment variables\n * @see {@link fromDocument} for initialization using HTML meta tags\n */\n config(new_config, new_value) {\n switch (false) {\n case new_value === void 0:\n this.set(new_config, new_value);\n return this.configuration;\n case typeof new_config != 'string':\n return this.get(new_config);\n case !(0,_utils_isObject_js__WEBPACK_IMPORTED_MODULE_1__.isObject)(new_config):\n this.merge(new_config);\n return this.configuration;\n default:\n // Backward compatibility - return the internal object\n return this.configuration;\n }\n }\n /**\n * Returns a copy of the configuration parameters\n * @function Configuration#toOptions\n * @returns {Object} a key:value collection of the configuration parameters\n */\n toOptions() {\n return (0,_internal_utils_cloneDeep_js__WEBPACK_IMPORTED_MODULE_0__.cloneDeep)(this.configuration);\n }\n}\nconst DEFAULT_CONFIGURATION_PARAMS = {\n responsive_class: 'cld-responsive',\n responsive_use_breakpoints: true,\n round_dpr: true,\n secure: (typeof window !== \"undefined\" && window !== null ? window.location ? window.location.protocol : void 0 : void 0) === 'https:'\n};\nconst CONFIG_PARAMS = [\n \"api_key\",\n \"api_secret\",\n \"callback\",\n \"cdn_subdomain\",\n \"cloud_name\",\n \"cname\",\n \"private_cdn\",\n \"protocol\",\n \"resource_type\",\n \"responsive\",\n \"responsive_class\",\n \"responsive_use_breakpoints\",\n \"responsive_width\",\n \"round_dpr\",\n \"secure\",\n \"secure_cdn_subdomain\",\n \"secure_distribution\",\n \"shorten\",\n \"type\",\n \"upload_preset\",\n \"url_suffix\",\n \"use_root_path\",\n \"version\",\n \"externalLibraries\",\n \"max_timeout_ms\"\n];\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Configuration);\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/configuration.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/consts.js":
/*!***************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/consts.js ***!
\***************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ AKAMAI_SHARED_CDN: () => (/* binding */ AKAMAI_SHARED_CDN),\n/* harmony export */ CF_SHARED_CDN: () => (/* binding */ CF_SHARED_CDN),\n/* harmony export */ LAYER_KEYWORD_PARAMS: () => (/* binding */ LAYER_KEYWORD_PARAMS),\n/* harmony export */ LEGACY_CONDITIONAL_OPERATORS: () => (/* binding */ LEGACY_CONDITIONAL_OPERATORS),\n/* harmony export */ LEGACY_PREDEFINED_VARS: () => (/* binding */ LEGACY_PREDEFINED_VARS),\n/* harmony export */ NUMBER_PATTERN: () => (/* binding */ NUMBER_PATTERN),\n/* harmony export */ OFFSET_ANY_PATTERN: () => (/* binding */ OFFSET_ANY_PATTERN),\n/* harmony export */ OFFSET_ANY_PATTERN_RE: () => (/* binding */ OFFSET_ANY_PATTERN_RE),\n/* harmony export */ OLD_AKAMAI_SHARED_CDN: () => (/* binding */ OLD_AKAMAI_SHARED_CDN),\n/* harmony export */ RANGE_VALUE_RE: () => (/* binding */ RANGE_VALUE_RE),\n/* harmony export */ SHARED_CDN: () => (/* binding */ SHARED_CDN)\n/* harmony export */ });\nconst LEGACY_CONDITIONAL_OPERATORS = {\n \"=\": 'eq',\n \"!=\": 'ne',\n \"<\": 'lt',\n \">\": 'gt',\n \"<=\": 'lte',\n \">=\": 'gte',\n \"&&\": 'and',\n \"||\": 'or',\n \"*\": \"mul\",\n \"/\": \"div\",\n \"+\": \"add\",\n \"-\": \"sub\",\n \"^\": \"pow\"\n};\nconst CF_SHARED_CDN = \"d3jpl91pxevbkh.cloudfront.net\";\nconst OLD_AKAMAI_SHARED_CDN = \"cloudinary-a.akamaihd.net\";\nconst AKAMAI_SHARED_CDN = \"res.cloudinary.com\";\nconst SHARED_CDN = AKAMAI_SHARED_CDN;\nconst LEGACY_PREDEFINED_VARS = {\n \"aspect_ratio\": \"ar\",\n \"aspectRatio\": \"ar\",\n \"current_page\": \"cp\",\n \"currentPage\": \"cp\",\n \"duration\": \"du\",\n \"face_count\": \"fc\",\n \"faceCount\": \"fc\",\n \"height\": \"h\",\n \"initial_aspect_ratio\": \"iar\",\n \"initial_height\": \"ih\",\n \"initial_width\": \"iw\",\n \"initialAspectRatio\": \"iar\",\n \"initialHeight\": \"ih\",\n \"initialWidth\": \"iw\",\n \"initial_duration\": \"idu\",\n \"initialDuration\": \"idu\",\n \"page_count\": \"pc\",\n \"page_x\": \"px\",\n \"page_y\": \"py\",\n \"pageCount\": \"pc\",\n \"pageX\": \"px\",\n \"pageY\": \"py\",\n \"tags\": \"tags\",\n \"width\": \"w\"\n};\nconst NUMBER_PATTERN = \"([0-9]*)\\\\.([0-9]+)|([0-9]+)\";\nconst OFFSET_ANY_PATTERN = `(${NUMBER_PATTERN})([%pP])?`;\nconst RANGE_VALUE_RE = RegExp(`^${OFFSET_ANY_PATTERN}$`);\nconst OFFSET_ANY_PATTERN_RE = RegExp(`(${OFFSET_ANY_PATTERN})\\\\.\\\\.(${OFFSET_ANY_PATTERN})`);\nconst LAYER_KEYWORD_PARAMS = {\n font_weight: \"normal\",\n font_style: \"normal\",\n text_decoration: \"none\",\n text_align: '',\n stroke: \"none\"\n};\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/consts.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/createCloudinaryLegacyURL.js":
/*!**********************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/createCloudinaryLegacyURL.js ***!
\**********************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ createCloudinaryLegacyURL: () => (/* binding */ createCloudinaryLegacyURL)\n/* harmony export */ });\n/* harmony import */ var _generateTransformationString_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./generateTransformationString.js */ \"../node_modules/@cloudinary/url-gen/backwards/generateTransformationString.js\");\n/* harmony import */ var _utils_finalizeResourceType_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/finalizeResourceType.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/finalizeResourceType.js\");\n/* harmony import */ var _utils_finalize_source_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils/finalize_source.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/finalize_source.js\");\n/* harmony import */ var _utils_unsigned_url_prefix_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./utils/unsigned_url_prefix.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/unsigned_url_prefix.js\");\n/* harmony import */ var _internal_utils_cloneDeep_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../internal/utils/cloneDeep.js */ \"../node_modules/@cloudinary/url-gen/internal/utils/cloneDeep.js\");\n\n\n\n\n\nfunction createCloudinaryLegacyURL(public_id, transformationOptions) {\n // Path format\n if (transformationOptions.type === \"fetch\") {\n if (transformationOptions.fetch_format == null) {\n transformationOptions.fetch_format = transformationOptions.format;\n }\n }\n let source_to_sign;\n let type = transformationOptions.type;\n let resource_type = transformationOptions.resource_type || 'image';\n let version = transformationOptions.version;\n const force_version = typeof transformationOptions.force_version === 'boolean' ? transformationOptions.force_version : true;\n const long_url_signature = !!transformationOptions.long_url_signature;\n const format = transformationOptions.format;\n const cloud_name = transformationOptions.cloud_name;\n if (!cloud_name) {\n throw \"cloud_name must be provided in the configuration\";\n }\n const private_cdn = transformationOptions.private_cdn;\n const secure_distribution = transformationOptions.secure_distribution;\n const secure = transformationOptions.secure;\n const cdn_subdomain = transformationOptions.cdn_subdomain;\n const secure_cdn_subdomain = transformationOptions.secure_cdn_subdomain;\n const cname = transformationOptions.cname;\n const shorten = transformationOptions.shorten;\n const sign_url = transformationOptions.sign_url;\n const api_secret = transformationOptions.api_secret;\n const url_suffix = transformationOptions.url_suffix;\n const use_root_path = transformationOptions.use_root_path;\n const auth_token = transformationOptions.auth_token;\n const preloaded = /^(image|raw)\\/([a-z0-9_]+)\\/v(\\d+)\\/([^#]+)$/.exec(public_id);\n if (preloaded) {\n resource_type = preloaded[1];\n type = preloaded[2];\n version = preloaded[3];\n public_id = preloaded[4];\n }\n const original_source = public_id;\n if (public_id == null) {\n return original_source;\n }\n public_id = public_id.toString();\n if (type === null && public_id.match(/^https?:\\//i)) {\n return original_source;\n }\n [resource_type, type] = (0,_utils_finalizeResourceType_js__WEBPACK_IMPORTED_MODULE_0__.finalize_resource_type)(resource_type, type, url_suffix, use_root_path, shorten);\n [public_id, source_to_sign] = (0,_utils_finalize_source_js__WEBPACK_IMPORTED_MODULE_1__.finalize_source)(public_id, format, url_suffix);\n if (version == null && force_version && source_to_sign.indexOf(\"/\") >= 0 && !source_to_sign.match(/^v[0-9]+/) && !source_to_sign.match(/^https?:\\//)) {\n version = 1;\n }\n if (version != null) {\n version = `v${version}`;\n }\n else {\n version = null;\n }\n const transformation = (0,_generateTransformationString_js__WEBPACK_IMPORTED_MODULE_2__.generateTransformationString)((0,_internal_utils_cloneDeep_js__WEBPACK_IMPORTED_MODULE_3__.cloneDeep)(transformationOptions)).replace(/([^:])\\/\\//g, '$1/');\n ;\n if (sign_url && !auth_token) {\n let to_sign = [transformation, source_to_sign].filter(function (part) {\n return (part != null) && part !== '';\n }).join('/');\n try {\n for (let i = 0; to_sign !== decodeURIComponent(to_sign) && i < 10; i++) {\n to_sign = decodeURIComponent(to_sign);\n }\n // eslint-disable-next-line no-empty\n }\n catch (error) {\n }\n // No support for Auth Token\n // const shasum = crypto.createHash(long_url_signature ? 'sha256' : 'sha1');\n // shasum.update(utf8_encode(to_sign + api_secret), 'binary');\n // signature = shasum.digest('base64').replace(/\\//g, '_').replace(/\\+/g, '-').substring(0, long_url_signature ? 32 : 8);\n // signature = `s--${signature}--`;\n }\n const prefix = (0,_utils_unsigned_url_prefix_js__WEBPACK_IMPORTED_MODULE_4__.unsigned_url_prefix)(public_id, cloud_name, private_cdn, cdn_subdomain, secure_cdn_subdomain, cname, secure, secure_distribution);\n const resultUrl = [prefix, resource_type, type, transformation, version, public_id].filter(function (part) {\n return (part != null) && part !== '';\n }).join('/').replace(' ', '%20');\n return resultUrl;\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/createCloudinaryLegacyURL.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/expression.js":
/*!*******************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/expression.js ***!
\*******************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/**\n * Represents a transformation expression.\n * @param {string} expressionStr - An expression in string format.\n * @class Expression\n *\n */\nclass Expression {\n constructor(expressionStr) {\n /**\n * @protected\n * @inner Expression-expressions\n */\n this.expressions = [];\n if (expressionStr != null) {\n this.expressions.push(Expression.normalize(expressionStr));\n }\n }\n /**\n * Convenience constructor method\n * @function Expression.new\n */\n static new(expressionStr) {\n return new this(expressionStr);\n }\n /**\n * Normalize a string expression\n * @function Cloudinary#normalize\n * @param {string} expression a expression, e.g. \"w gt 100\", \"width_gt_100\", \"width > 100\"\n * @return {string} the normalized form of the value expression, e.g. \"w_gt_100\"\n */\n static normalize(expression) {\n var operators, operatorsPattern, operatorsReplaceRE, predefinedVarsPattern, predefinedVarsReplaceRE;\n if (expression == null) {\n return expression;\n }\n expression = String(expression);\n operators = \"\\\\|\\\\||>=|<=|&&|!=|>|=|<|/|-|\\\\+|\\\\*|\\\\^\";\n // operators\n operatorsPattern = \"((\" + operators + \")(?=[ _]))\";\n operatorsReplaceRE = new RegExp(operatorsPattern, \"g\");\n // @ts-ignore\n expression = expression.replace(operatorsReplaceRE, match => OPERATORS[match]);\n // predefined variables\n predefinedVarsPattern = \"(\" + Object.keys(PREDEFINED_VARS).join(\"|\") + \")\";\n predefinedVarsReplaceRE = new RegExp(predefinedVarsPattern, \"g\");\n // @ts-ignore\n expression = expression.replace(predefinedVarsReplaceRE, (match, p1, offset) => (expression[offset - 1] === '$' ? match : PREDEFINED_VARS[match]));\n return expression.replace(/[ _]+/g, '_');\n }\n /**\n * Serialize the expression\n * @return {string} the expression as a string\n */\n serialize() {\n return Expression.normalize(this.expressions.join(\"_\"));\n }\n toString() {\n return this.serialize();\n }\n /**\n * Get the parent transformation of this expression\n * @return Transformation\n */\n getParent() {\n return this.parent;\n }\n /**\n * Set the parent transformation of this expression\n * @param {Transformation} the parent transformation\n * @return {Expression} this expression\n */\n setParent(parent) {\n this.parent = parent;\n return this;\n }\n /**\n * Add a expression\n * @function Expression#predicate\n * @internal\n */\n predicate(name, operator, value) {\n // @ts-ignore\n if (OPERATORS[operator] != null) {\n // @ts-ignore\n operator = OPERATORS[operator];\n }\n this.expressions.push(`${name}_${operator}_${value}`);\n return this;\n }\n /**\n * @function Expression#and\n */\n and() {\n this.expressions.push(\"and\");\n return this;\n }\n /**\n * @function Expression#or\n */\n or() {\n this.expressions.push(\"or\");\n return this;\n }\n /**\n * Conclude expression\n * @function Expression#then\n * @return {Transformation} the transformation this expression is defined for\n */\n then() {\n return this.getParent().if(this.toString());\n }\n /**\n * @function Expression#height\n * @param {string} operator the comparison operator (e.g. \"<\", \"lt\")\n * @param {string|number} value the right hand side value\n * @return {Expression} this expression\n */\n height(operator, value) {\n return this.predicate(\"h\", operator, value);\n }\n /**\n * @function Expression#width\n * @param {string} operator the comparison operator (e.g. \"<\", \"lt\")\n * @param {string|number} value the right hand side value\n * @return {Expression} this expression\n */\n width(operator, value) {\n return this.predicate(\"w\", operator, value);\n }\n /**\n * @function Expression#aspectRatio\n * @param {string} operator the comparison operator (e.g. \"<\", \"lt\")\n * @param {string|number} value the right hand side value\n * @return {Expression} this expression\n */\n aspectRatio(operator, value) {\n return this.predicate(\"ar\", operator, value);\n }\n /**\n * @function Expression#pages\n * @param {string} operator the comparison operator (e.g. \"<\", \"lt\")\n * @param {string|number} value the right hand side value\n * @return {Expression} this expression\n */\n pageCount(operator, value) {\n return this.predicate(\"pc\", operator, value);\n }\n /**\n * @function Expression#faces\n * @param {string} operator the comparison operator (e.g. \"<\", \"lt\")\n * @param {string|number} value the right hand side value\n * @return {Expression} this expression\n */\n faceCount(operator, value) {\n return this.predicate(\"fc\", operator, value);\n }\n value(value) {\n this.expressions.push(value);\n return this;\n }\n /**\n */\n static variable(name, value) {\n return new this(name).value(value);\n }\n /**\n * @returns Expression a new expression with the predefined variable \"width\"\n * @function Expression.width\n */\n static width() {\n return new this(\"width\");\n }\n /**\n * @returns Expression a new expression with the predefined variable \"height\"\n * @function Expression.height\n */\n static height() {\n return new this(\"height\");\n }\n /**\n * @returns Expression a new expression with the predefined variable \"initialWidth\"\n * @function Expression.initialWidth\n */\n static initialWidth() {\n return new this(\"initialWidth\");\n }\n /**\n * @returns Expression a new expression with the predefined variable \"initialHeight\"\n * @function Expression.initialHeight\n */\n static initialHeight() {\n return new this(\"initialHeight\");\n }\n /**\n * @returns Expression a new expression with the predefined variable \"aspectRatio\"\n * @function Expression.aspectRatio\n */\n static aspectRatio() {\n return new this(\"aspectRatio\");\n }\n /**\n * @returns Expression a new expression with the predefined variable \"initialAspectRatio\"\n * @function Expression.initialAspectRatio\n */\n static initialAspectRatio() {\n return new this(\"initialAspectRatio\");\n }\n /**\n * @returns Expression a new expression with the predefined variable \"pageCount\"\n * @function Expression.pageCount\n */\n static pageCount() {\n return new this(\"pageCount\");\n }\n /**\n * @returns Expression new expression with the predefined variable \"faceCount\"\n * @function Expression.faceCount\n */\n static faceCount() {\n return new this(\"faceCount\");\n }\n /**\n * @returns Expression a new expression with the predefined variable \"currentPage\"\n * @function Expression.currentPage\n */\n static currentPage() {\n return new this(\"currentPage\");\n }\n /**\n * @returns Expression a new expression with the predefined variable \"tags\"\n * @function Expression.tags\n */\n static tags() {\n return new this(\"tags\");\n }\n /**\n * @returns Expression a new expression with the predefined variable \"pageX\"\n * @function Expression.pageX\n */\n static pageX() {\n return new this(\"pageX\");\n }\n /**\n * @returns Expression a new expression with the predefined variable \"pageY\"\n * @function Expression.pageY\n */\n static pageY() {\n return new this(\"pageY\");\n }\n}\n/**\n * @internal\n */\nconst OPERATORS = {\n \"=\": 'eq',\n \"!=\": 'ne',\n \"<\": 'lt',\n \">\": 'gt',\n \"<=\": 'lte',\n \">=\": 'gte',\n \"&&\": 'and',\n \"||\": 'or',\n \"*\": \"mul\",\n \"/\": \"div\",\n \"+\": \"add\",\n \"-\": \"sub\",\n \"^\": \"pow\",\n};\n/**\n * @internal\n */\nconst PREDEFINED_VARS = {\n \"aspect_ratio\": \"ar\",\n \"aspectRatio\": \"ar\",\n \"current_page\": \"cp\",\n \"currentPage\": \"cp\",\n \"preview:duration\": \"preview:duration\",\n \"duration\": \"du\",\n \"face_count\": \"fc\",\n \"faceCount\": \"fc\",\n \"height\": \"h\",\n \"initial_aspect_ratio\": \"iar\",\n \"initial_duration\": \"idu\",\n \"initial_height\": \"ih\",\n \"initial_width\": \"iw\",\n \"initialAspectRatio\": \"iar\",\n \"initialDuration\": \"idu\",\n \"initialHeight\": \"ih\",\n \"initialWidth\": \"iw\",\n \"page_count\": \"pc\",\n \"page_x\": \"px\",\n \"page_y\": \"py\",\n \"pageCount\": \"pc\",\n \"pageX\": \"px\",\n \"pageY\": \"py\",\n \"tags\": \"tags\",\n \"width\": \"w\"\n};\n/**\n * @internal\n */\nconst BOUNDRY = \"[ _]+\";\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Expression);\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/expression.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/generateTransformationString.js":
/*!*************************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/generateTransformationString.js ***!
\*************************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ generateTransformationString: () => (/* binding */ generateTransformationString),\n/* harmony export */ transformationStringFromObject: () => (/* binding */ transformationStringFromObject)\n/* harmony export */ });\n/* harmony import */ var _transformationProcessing_processLayer_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./transformationProcessing/processLayer.js */ \"../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processLayer.js\");\n/* harmony import */ var _transformationProcessing_processIf_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./transformationProcessing/processIf.js */ \"../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processIf.js\");\n/* harmony import */ var _utils_toArray_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils/toArray.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/toArray.js\");\n/* harmony import */ var _transformationProcessing_processRadius_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./transformationProcessing/processRadius.js */ \"../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processRadius.js\");\n/* harmony import */ var _utils_isObject_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./utils/isObject.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/isObject.js\");\n/* harmony import */ var _transformationProcessing_processCustomFunction_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./transformationProcessing/processCustomFunction.js */ \"../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processCustomFunction.js\");\n/* harmony import */ var _transformationProcessing_processCustomPreFunction_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./transformationProcessing/processCustomPreFunction.js */ \"../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processCustomPreFunction.js\");\n/* harmony import */ var _utils_splitRange_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./utils/splitRange.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/splitRange.js\");\n/* harmony import */ var _utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./utils/legacyNormalizeExpression.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/legacyNormalizeExpression.js\");\n/* harmony import */ var _utils_norm_range_values_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./utils/norm_range_values.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/norm_range_values.js\");\n/* harmony import */ var _transformationProcessing_processVideoParams_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./transformationProcessing/processVideoParams.js */ \"../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processVideoParams.js\");\n/* harmony import */ var _transformation_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./transformation.js */ \"../node_modules/@cloudinary/url-gen/backwards/transformation.js\");\n/* harmony import */ var _transformationProcessing_processDpr_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./transformationProcessing/processDpr.js */ \"../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processDpr.js\");\n/* harmony import */ var _utils_isNumberLike_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./utils/isNumberLike.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/isNumberLike.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * Things dropped\n * - responsive_width\n * - config().dpr\n * - SSL Detected\n * - Provisioning API\n * - Magical configuration auto-mapping (everything has to be explicit)\n * - Signatures\n * - Secure is default true\n * @param transformationOptions\n */\nfunction generateTransformationString(transformationOptions) {\n if (typeof transformationOptions === 'string') {\n return transformationOptions;\n }\n if (transformationOptions instanceof _transformation_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"]) {\n return transformationOptions.toString();\n }\n if (Array.isArray(transformationOptions)) {\n return transformationOptions\n .map((singleTransformation) => {\n return generateTransformationString(singleTransformation);\n }).filter((a) => { return a; }).join('/');\n }\n // let responsive_width = consumeOption(transformationOptions, \"responsive_width\", config().responsive_width);\n let width;\n let height;\n const size = transformationOptions.size;\n const hasLayer = transformationOptions.overlay || transformationOptions.underlay;\n const crop = transformationOptions.crop;\n const angle = (0,_utils_toArray_js__WEBPACK_IMPORTED_MODULE_1__.toArray)(transformationOptions.angle).join(\".\");\n const background = (transformationOptions.background || '').replace(/^#/, \"rgb:\");\n const color = (transformationOptions.color || '').replace(/^#/, \"rgb:\");\n const flags = ((0,_utils_toArray_js__WEBPACK_IMPORTED_MODULE_1__.toArray)(transformationOptions.flags || [])).join('.');\n const dpr = transformationOptions.dpr === undefined ? transformationOptions.dpr : (0,_transformationProcessing_processDpr_js__WEBPACK_IMPORTED_MODULE_2__.processDpr)(transformationOptions.dpr);\n const overlay = (0,_transformationProcessing_processLayer_js__WEBPACK_IMPORTED_MODULE_3__.processLayer)(transformationOptions.overlay);\n const radius = (0,_transformationProcessing_processRadius_js__WEBPACK_IMPORTED_MODULE_4__.processRadius)(transformationOptions.radius);\n const underlay = (0,_transformationProcessing_processLayer_js__WEBPACK_IMPORTED_MODULE_3__.processLayer)(transformationOptions.underlay);\n const ifValue = (0,_transformationProcessing_processIf_js__WEBPACK_IMPORTED_MODULE_5__.process_if)(transformationOptions.if);\n const custom_function = (0,_transformationProcessing_processCustomFunction_js__WEBPACK_IMPORTED_MODULE_6__.processCustomFunction)(transformationOptions.custom_function);\n const custom_pre_function = (0,_transformationProcessing_processCustomPreFunction_js__WEBPACK_IMPORTED_MODULE_7__.processCustomPreFunction)(transformationOptions.custom_pre_function);\n // These will change down the line, heads up!\n let fps = transformationOptions.fps;\n let namedTransformations = [];\n let childTransformations = (0,_utils_toArray_js__WEBPACK_IMPORTED_MODULE_1__.toArray)(transformationOptions.transformation || []);\n let effect = transformationOptions.effect;\n // TODO, Do we need this?\n const no_html_sizes = hasLayer || angle || crop === \"fit\" || crop === \"limit\";\n if (size) {\n const [sizeWidth, sizeHeight] = size.split(\"x\");\n width = sizeWidth;\n height = sizeHeight;\n }\n else {\n width = transformationOptions.width;\n height = transformationOptions.height;\n }\n if (width && (width.toString().indexOf(\"auto\") === 0 || no_html_sizes || parseFloat(width.toString()) < 1)) {\n delete transformationOptions.width;\n }\n if (height && (no_html_sizes || parseFloat(height.toString()) < 1)) {\n delete transformationOptions.height;\n }\n // Is any child transformation an object?\n const isAnyChildAnObject = childTransformations.some((transformation) => typeof transformation === 'object');\n // If array of objects, or array of strings?\n if (isAnyChildAnObject) {\n childTransformations = childTransformations.map((transformation) => {\n if ((0,_utils_isObject_js__WEBPACK_IMPORTED_MODULE_8__.isObject)(transformation)) {\n return generateTransformationString(transformation);\n }\n else {\n return generateTransformationString({ transformation });\n }\n }).filter((a) => a);\n }\n else {\n namedTransformations = childTransformations.join(\".\");\n childTransformations = []; // Reset child transfomrations\n }\n if (Array.isArray(effect)) {\n effect = effect.join(\":\");\n }\n else if ((0,_utils_isObject_js__WEBPACK_IMPORTED_MODULE_8__.isObject)(effect)) {\n effect = Object.entries(effect).map(([key, value]) => `${key}:${value}`);\n }\n let border = transformationOptions.border;\n if ((0,_utils_isObject_js__WEBPACK_IMPORTED_MODULE_8__.isObject)(border)) {\n border = `${border.width != null ? border.width : 2}px_solid_${(border.color != null ? border.color : \"black\").replace(/^#/, 'rgb:')}`;\n }\n else {\n // @ts-ignore\n if (/^\\d+$/.exec(border)) { // fallback to html border attributes\n transformationOptions.border = border;\n border = void 0;\n }\n }\n if (Array.isArray(fps)) {\n fps = fps.join('-');\n }\n // ocr(value) {\n // return this.param(value, \"ocr\", \"ocr\");\n // }\n const urlParams = {\n a: (0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(angle),\n ar: (0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(transformationOptions.aspect_ratio),\n b: background,\n bo: border,\n c: crop,\n co: color,\n dpr: (0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(dpr),\n e: (0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(effect),\n fl: flags,\n fn: custom_function || custom_pre_function,\n fps: fps,\n h: (0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(height),\n ki: (0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(transformationOptions.keyframe_interval),\n l: overlay,\n o: (0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(transformationOptions.opacity),\n q: (0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(transformationOptions.quality),\n r: radius,\n t: namedTransformations,\n u: underlay,\n w: (0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(width),\n x: (0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(transformationOptions.x),\n y: (0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(transformationOptions.y),\n z: (0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(transformationOptions.zoom),\n ac: transformationOptions.audio_codec,\n af: transformationOptions.audio_frequency,\n br: transformationOptions.bit_rate,\n cs: transformationOptions.color_space,\n d: transformationOptions.default_image,\n dl: transformationOptions.delay,\n dn: transformationOptions.density,\n du: (0,_utils_norm_range_values_js__WEBPACK_IMPORTED_MODULE_10__.normRangeValues)(transformationOptions.duration),\n eo: (0,_utils_norm_range_values_js__WEBPACK_IMPORTED_MODULE_10__.normRangeValues)(transformationOptions.end_offset || (0,_utils_isNumberLike_js__WEBPACK_IMPORTED_MODULE_11__.isNumberLike)(transformationOptions.end_offset) ? transformationOptions.end_offset : (0,_utils_splitRange_js__WEBPACK_IMPORTED_MODULE_12__.splitRange)(transformationOptions.offset)[1]),\n f: transformationOptions.fetch_format,\n g: transformationOptions.gravity,\n pg: transformationOptions.page,\n p: transformationOptions.prefix,\n so: (0,_utils_norm_range_values_js__WEBPACK_IMPORTED_MODULE_10__.normRangeValues)(transformationOptions.start_offset || (0,_utils_isNumberLike_js__WEBPACK_IMPORTED_MODULE_11__.isNumberLike)(transformationOptions.start_offset) ? transformationOptions.start_offset : (0,_utils_splitRange_js__WEBPACK_IMPORTED_MODULE_12__.splitRange)(transformationOptions.offset)[0]),\n sp: transformationOptions.streaming_profile,\n vc: (0,_transformationProcessing_processVideoParams_js__WEBPACK_IMPORTED_MODULE_13__.processVideoParams)(transformationOptions.video_codec),\n vs: transformationOptions.video_sampling\n };\n // We can accept variables in here transformationOptions, or in here transformationOptions.variables\n const variables = Object.entries(transformationOptions)\n .filter(([key, value]) => key.startsWith('$'))\n .map(([key, value]) => {\n // delete transformationOptions[key]; // Delete the variables, so we don't add them twice\n return `${key}_${(0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(value)}`;\n }).sort().concat(\n // @ts-ignore\n (transformationOptions.variables || []).map(([name, value]) => `${name}_${(0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_9__.legacyNormalizeExpression)(value)}`)).join(',');\n // Clean up!\n const urlImageTransfomrations = Object.entries(urlParams)\n .filter(([key, value]) => {\n if (typeof value === 'undefined' || value === null) {\n return false;\n }\n if (typeof value === 'string' && value.length === 0) {\n return false;\n }\n if (Array.isArray(value) && value.length === 0) {\n return false;\n }\n return true;\n })\n .map(([key, value]) => `${key}_${value}`)\n .sort()\n .join(',');\n const finalTransformationString = [\n ifValue,\n variables,\n urlImageTransfomrations,\n transformationOptions.raw_transformation\n ].filter((a) => a).join(\",\");\n if (finalTransformationString) {\n childTransformations.push(finalTransformationString);\n }\n // console.log(childTransformations);\n return childTransformations.join(\"/\");\n}\nconst transformationStringFromObject = generateTransformationString;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/generateTransformationString.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/legacyLayer/fetchlayer.js":
/*!*******************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/legacyLayer/fetchlayer.js ***!
\*******************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _layer_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./layer.js */ \"../node_modules/@cloudinary/url-gen/backwards/legacyLayer/layer.js\");\n/* harmony import */ var _internal_utils_dataStructureUtils_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../internal/utils/dataStructureUtils.js */ \"../node_modules/@cloudinary/url-gen/internal/utils/dataStructureUtils.js\");\n/* harmony import */ var _internal_utils_base64Encode_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../internal/utils/base64Encode.js */ \"../node_modules/@cloudinary/url-gen/internal/utils/base64Encode.js\");\n\n\n\nclass FetchLayer extends _layer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n /**\n * @class FetchLayer\n * @classdesc Creates an image layer using a remote URL.\n * @param {Object|string} options - layer parameters or a url\n * @param {string} options.url the url of the image to fetch\n */\n constructor(options) {\n super(options);\n if ((0,_internal_utils_dataStructureUtils_js__WEBPACK_IMPORTED_MODULE_1__.isString)(options)) {\n this.options.url = options;\n }\n else if (options != null ? options.url : void 0) {\n this.options.url = options.url;\n }\n }\n url(url) {\n this.options.url = url;\n return this;\n }\n /**\n * generate the string representation of the layer\n * @function FetchLayer#toString\n * @return {String}\n */\n toString() {\n return `fetch:${(0,_internal_utils_base64Encode_js__WEBPACK_IMPORTED_MODULE_2__.base64Encode)(this.options.url)}`;\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (FetchLayer);\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/legacyLayer/fetchlayer.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/legacyLayer/layer.js":
/*!**************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/legacyLayer/layer.js ***!
\**************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _utils_snakeCase_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils/snakeCase.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/snakeCase.js\");\n\nclass Layer {\n /**\n * Layer\n * @constructor Layer\n * @param {Object} options - layer parameters\n */\n constructor(options) {\n this.options = {};\n if (options != null) {\n [\"resourceType\", \"type\", \"publicId\", \"format\"].forEach((key) => {\n var ref;\n // @ts-ignore\n return this.options[key] = (ref = options[key]) != null ? ref : options[(0,_utils_snakeCase_js__WEBPACK_IMPORTED_MODULE_0__.snakeCase)(key)];\n });\n }\n }\n resourceType(value) {\n this.options.resourceType = value;\n return this;\n }\n type(value) {\n this.options.type = value;\n return this;\n }\n publicId(value) {\n this.options.publicId = value;\n return this;\n }\n /**\n * Get the public ID, formatted for layer parameter\n * @function Layer#getPublicId\n * @return {String} public ID\n */\n getPublicId() {\n var ref;\n return (ref = this.options.publicId) != null ? ref.replace(/\\//g, \":\") : void 0;\n }\n /**\n * Get the public ID, with format if present\n * @function Layer#getFullPublicId\n * @return {String} public ID\n */\n getFullPublicId() {\n if (this.options.format != null) {\n return this.getPublicId() + \".\" + this.options.format;\n }\n else {\n return this.getPublicId();\n }\n }\n format(value) {\n this.options.format = value;\n return this;\n }\n /**\n * generate the string representation of the layer\n * @function Layer#toString\n */\n toString() {\n let components = [];\n if (this.options.publicId == null) {\n throw \"Must supply publicId\";\n }\n if (!(this.options.resourceType === \"image\")) {\n components.push(this.options.resourceType);\n }\n if (!(this.options.type === \"upload\")) {\n components.push(this.options.type);\n }\n components.push(this.getFullPublicId());\n return components.filter(x => !!x).join(\":\");\n }\n clone() {\n return new Layer(this.options);\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Layer);\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/legacyLayer/layer.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/legacyLayer/subtitleslayer.js":
/*!***********************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/legacyLayer/subtitleslayer.js ***!
\***********************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _textlayer_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./textlayer.js */ \"../node_modules/@cloudinary/url-gen/backwards/legacyLayer/textlayer.js\");\n\nclass SubtitlesLayer extends _textlayer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n /**\n * Represent a subtitles layer\n * @constructor SubtitlesLayer\n * @param {Object} options - layer parameters\n */\n constructor(options) {\n super(options);\n this.options.resourceType = \"subtitles\";\n }\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (SubtitlesLayer);\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/legacyLayer/subtitleslayer.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/legacyLayer/textlayer.js":
/*!******************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/legacyLayer/textlayer.js ***!
\******************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _layer_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./layer.js */ \"../node_modules/@cloudinary/url-gen/backwards/legacyLayer/layer.js\");\n/* harmony import */ var _utils_snakeCase_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/snakeCase.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/snakeCase.js\");\n/* harmony import */ var _utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utils/isEmpty.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/isEmpty.js\");\n/* harmony import */ var _utils_smartEscape_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../utils/smartEscape.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/smartEscape.js\");\n/* harmony import */ var _utils_isNumberLike_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../utils/isNumberLike.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/isNumberLike.js\");\n\n\n\n\n\nclass TextLayer extends _layer_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n /**\n * @constructor TextLayer\n * @param {Object} options - layer parameters\n */\n constructor(options) {\n let keys;\n super(options);\n keys = [\"resourceType\", \"resourceType\", \"fontFamily\", \"fontSize\", \"fontWeight\", \"fontStyle\", \"textDecoration\", \"textAlign\", \"stroke\", \"letterSpacing\", \"lineSpacing\", \"fontHinting\", \"fontAntialiasing\", \"text\"];\n if (options != null) {\n keys.forEach((key) => {\n var ref;\n // @ts-ignore\n return this.options[key] = (ref = options[key]) != null ? ref : options[(0,_utils_snakeCase_js__WEBPACK_IMPORTED_MODULE_1__.snakeCase)(key)];\n });\n }\n this.options.resourceType = \"text\";\n }\n //@ts-ignore\n resourceType(resourceType) {\n throw \"Cannot modify resourceType for text layers\";\n }\n //@ts-ignore\n type(type) {\n throw \"Cannot modify type for text layers\";\n }\n format(format) {\n throw \"Cannot modify format for text layers\";\n }\n fontFamily(fontFamily) {\n this.options.fontFamily = fontFamily;\n return this;\n }\n fontSize(fontSize) {\n this.options.fontSize = fontSize;\n return this;\n }\n fontWeight(fontWeight) {\n this.options.fontWeight = fontWeight;\n return this;\n }\n fontStyle(fontStyle) {\n this.options.fontStyle = fontStyle;\n return this;\n }\n textDecoration(textDecoration) {\n this.options.textDecoration = textDecoration;\n return this;\n }\n textAlign(textAlign) {\n this.options.textAlign = textAlign;\n return this;\n }\n stroke(stroke) {\n this.options.stroke = stroke;\n return this;\n }\n letterSpacing(letterSpacing) {\n this.options.letterSpacing = letterSpacing;\n return this;\n }\n lineSpacing(lineSpacing) {\n this.options.lineSpacing = lineSpacing;\n return this;\n }\n fontHinting(fontHinting) {\n this.options.fontHinting = fontHinting;\n return this;\n }\n fontAntialiasing(fontAntialiasing) {\n this.options.fontAntialiasing = fontAntialiasing;\n return this;\n }\n text(text) {\n this.options.text = text;\n return this;\n }\n /**\n * generate the string representation of the layer\n * @function TextLayer#toString\n * @return {String}\n */\n toString() {\n var components, hasPublicId, hasStyle, publicId, re, res, start, style, text, textSource;\n style = this.textStyleIdentifier();\n if (this.options.publicId != null) {\n publicId = this.getFullPublicId();\n }\n if (this.options.text != null) {\n hasPublicId = !(0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_2__.isEmpty)(publicId);\n hasStyle = !(0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_2__.isEmpty)(style);\n if (hasPublicId && hasStyle || !hasPublicId && !hasStyle) {\n throw \"Must supply either style parameters or a public_id when providing text parameter in a text overlay/underlay, but not both!\";\n }\n re = /\\$\\([a-zA-Z]\\w*\\)/g;\n start = 0;\n // textSource = text.replace(new RegExp(\"[,/]\", 'g'), (c)-> \"%#{c.charCodeAt(0).toString(16).toUpperCase()}\")\n textSource = (0,_utils_smartEscape_js__WEBPACK_IMPORTED_MODULE_3__.smartEscape)(this.options.text, /[,\\/]/g);\n text = \"\";\n while (res = re.exec(textSource)) {\n text += (0,_utils_smartEscape_js__WEBPACK_IMPORTED_MODULE_3__.smartEscape)(textSource.slice(start, res.index));\n text += res[0];\n start = res.index + res[0].length;\n }\n text += (0,_utils_smartEscape_js__WEBPACK_IMPORTED_MODULE_3__.smartEscape)(textSource.slice(start));\n }\n components = [this.options.resourceType, style, publicId, text];\n return (components).filter(x => !!x).join(\":\");\n }\n textStyleIdentifier() {\n var components;\n components = [];\n if (this.options.fontWeight !== \"normal\") {\n components.push(this.options.fontWeight);\n }\n if (this.options.fontStyle !== \"normal\") {\n components.push(this.options.fontStyle);\n }\n if (this.options.textDecoration !== \"none\") {\n components.push(this.options.textDecoration);\n }\n components.push(this.options.textAlign);\n if (this.options.stroke !== \"none\") {\n components.push(this.options.stroke);\n }\n if (!((0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_2__.isEmpty)(this.options.letterSpacing) && !(0,_utils_isNumberLike_js__WEBPACK_IMPORTED_MODULE_4__.isNumberLike)(this.options.letterSpacing))) {\n components.push(\"letter_spacing_\" + this.options.letterSpacing);\n }\n if (!((0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_2__.isEmpty)(this.options.lineSpacing) && !(0,_utils_isNumberLike_js__WEBPACK_IMPORTED_MODULE_4__.isNumberLike)(this.options.lineSpacing))) {\n components.push(\"line_spacing_\" + this.options.lineSpacing);\n }\n if (!((0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_2__.isEmpty)(this.options.fontAntialiasing))) {\n components.push(\"antialias_\" + this.options.fontAntialiasing);\n }\n if (!((0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_2__.isEmpty)(this.options.fontHinting))) {\n components.push(\"hinting_\" + this.options.fontHinting);\n }\n if (!(0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_2__.isEmpty)(components.filter(x => !!x))) {\n if ((0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_2__.isEmpty)(this.options.fontFamily)) {\n throw `Must supply fontFamily. ${components}`;\n }\n if ((0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_2__.isEmpty)(this.options.fontSize) && !(0,_utils_isNumberLike_js__WEBPACK_IMPORTED_MODULE_4__.isNumberLike)(this.options.fontSize)) {\n throw \"Must supply fontSize.\";\n }\n }\n components.unshift(this.options.fontFamily, this.options.fontSize);\n components = components.filter(x => !!x).join(\"_\");\n return components;\n }\n}\n;\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (TextLayer);\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/legacyLayer/textlayer.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/transformation.js":
/*!***********************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/transformation.js ***!
\***********************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ URL_KEYS: () => (/* binding */ URL_KEYS),\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _condition_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./condition.js */ \"../node_modules/@cloudinary/url-gen/backwards/condition.js\");\n/* harmony import */ var _configuration_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./configuration.js */ \"../node_modules/@cloudinary/url-gen/backwards/configuration.js\");\n/* harmony import */ var _internal_utils_cloneDeep_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../internal/utils/cloneDeep.js */ \"../node_modules/@cloudinary/url-gen/internal/utils/cloneDeep.js\");\n/* harmony import */ var _utils_legacyBaseUtil_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils/legacyBaseUtil.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/legacyBaseUtil.js\");\n/* harmony import */ var _utils_snakeCase_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./utils/snakeCase.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/snakeCase.js\");\n/* harmony import */ var _expression_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./expression.js */ \"../node_modules/@cloudinary/url-gen/backwards/expression.js\");\n/* harmony import */ var _legacyLayer_layer_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./legacyLayer/layer.js */ \"../node_modules/@cloudinary/url-gen/backwards/legacyLayer/layer.js\");\n/* harmony import */ var _legacyLayer_textlayer_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./legacyLayer/textlayer.js */ \"../node_modules/@cloudinary/url-gen/backwards/legacyLayer/textlayer.js\");\n/* harmony import */ var _legacyLayer_subtitleslayer_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./legacyLayer/subtitleslayer.js */ \"../node_modules/@cloudinary/url-gen/backwards/legacyLayer/subtitleslayer.js\");\n/* harmony import */ var _legacyLayer_fetchlayer_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./legacyLayer/fetchlayer.js */ \"../node_modules/@cloudinary/url-gen/backwards/legacyLayer/fetchlayer.js\");\n/* harmony import */ var _utils_isObject_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils/isObject.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/isObject.js\");\n/* harmony import */ var _internal_utils_dataStructureUtils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../internal/utils/dataStructureUtils.js */ \"../node_modules/@cloudinary/url-gen/internal/utils/dataStructureUtils.js\");\n/* harmony import */ var _utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./utils/isEmpty.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/isEmpty.js\");\n/* harmony import */ var _utils_isFunction_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./utils/isFunction.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/isFunction.js\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/**\n * A list of keys used by the url() function.\n * @private\n */\nconst URL_KEYS = [\n 'accessibility',\n 'api_secret',\n 'auth_token',\n 'cdn_subdomain',\n 'cloud_name',\n 'cname',\n 'format',\n 'placeholder',\n 'private_cdn',\n 'resource_type',\n 'secure',\n 'secure_cdn_subdomain',\n 'secure_distribution',\n 'shorten',\n 'sign_url',\n 'signature',\n 'ssl_detected',\n 'type',\n 'url_suffix',\n 'use_root_path',\n 'version'\n];\n/**\n * Assign key, value to target, when value is not null.<br>\n * This function mutates the target!\n * @param {object} target the object to assign the values to\n * @param {object} sources one or more objects to get values from\n * @returns {object} the target after the assignment\n */\nfunction assignNotNull(target, ...sources) {\n sources.forEach(source => {\n Object.keys(source).forEach(key => {\n // @ts-ignore\n if (source[key] != null) {\n // @ts-ignore\n target[key] = source[key];\n }\n });\n });\n return target;\n}\n/**\n * Return true if all items in list are strings\n * @function Util.allString\n * @param {Array} list - an array of items\n */\nconst allStrings = function (list) {\n return list.length && list.every(_internal_utils_dataStructureUtils_js__WEBPACK_IMPORTED_MODULE_0__.isString);\n};\n/**\n * Transformation parameters\n * Depends on 'util', 'transformation'\n */\nclass Param {\n /**\n * Represents a single parameter.\n * @class Param\n * @param {string} name - The name of the parameter in snake_case\n * @param {string} shortName - The name of the serialized form of the parameter.\n * If a value is not provided, the parameter will not be serialized.\n * @param {function} [process=Util.identity ] - Manipulate origValue when value is called\n * @ignore\n */\n constructor(name, shortName, process = _utils_legacyBaseUtil_js__WEBPACK_IMPORTED_MODULE_1__.identity) {\n /**\n * The name of the parameter in snake_case\n * @member {string} Param#name\n */\n this.name = name;\n /**\n * The name of the serialized form of the parameter\n * @member {string} Param#shortName\n */\n this.shortName = shortName;\n /**\n * Manipulate origValue when value is called\n * @member {function} Param#process\n */\n this.process = process;\n }\n /**\n * Set a (unprocessed) value for this parameter\n * @function Param#set\n * @param {*} origValue - the value of the parameter\n * @return {Param} self for chaining\n */\n set(origValue) {\n this.origValue = origValue;\n return this;\n }\n /**\n * Generate the serialized form of the parameter\n * @function Param#serialize\n * @return {string} the serialized form of the parameter\n */\n serialize() {\n var val, valid;\n val = this.value();\n valid = Array.isArray(val) || (0,_utils_isObject_js__WEBPACK_IMPORTED_MODULE_2__.isObject)(val) || (0,_internal_utils_dataStructureUtils_js__WEBPACK_IMPORTED_MODULE_0__.isString)(val) ? !(0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_3__.isEmpty)(val) : val != null;\n if ((this.shortName != null) && valid) {\n return `${this.shortName}_${val}`;\n }\n else {\n return '';\n }\n }\n /**\n * Return the processed value of the parameter\n * @function Param#value\n */\n value() {\n return this.process(this.origValue);\n }\n static norm_color(value) {\n return value != null ? value.replace(/^#/, 'rgb:') : void 0;\n }\n static build_array(arg) {\n if (arg == null) {\n return [];\n }\n else if (Array.isArray(arg)) {\n return arg;\n }\n else {\n return [arg];\n }\n }\n /**\n * Covert value to video codec string.\n *\n * If the parameter is an object,\n * @param {(string|Object)} param - the video codec as either a String or a Hash\n * @return {string} the video codec string in the format codec:profile:level\n * @example\n * vc_[ :profile : [level]]\n * or\n { codec: 'h264', profile: 'basic', level: '3.1' }\n * @ignore\n */\n static process_video_params(param) {\n var video;\n switch (param.constructor) {\n case Object:\n video = \"\";\n if ('codec' in param) {\n video = param.codec;\n if ('profile' in param) {\n video += \":\" + param.profile;\n if ('level' in param) {\n video += \":\" + param.level;\n }\n }\n }\n return video;\n case String:\n return param;\n default:\n return null;\n }\n }\n}\nclass ArrayParam extends Param {\n /**\n * A parameter that represents an array.\n * @param {string} name - The name of the parameter in snake_case.\n * @param {string} shortName - The name of the serialized form of the parameter\n * If a value is not provided, the parameter will not be serialized.\n * @param {string} [sep='.'] - The separator to use when joining the array elements together\n * @param {function} [process=Util.identity ] - Manipulate origValue when value is called\n * @class ArrayParam\n * @extends Param\n * @ignore\n */\n constructor(name, shortName, sep = '.', process = undefined) {\n super(name, shortName, process);\n this.sep = sep;\n }\n serialize() {\n if (this.shortName != null) {\n let arrayValue = this.value();\n if ((0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_3__.isEmpty)(arrayValue)) {\n return '';\n }\n else if ((0,_internal_utils_dataStructureUtils_js__WEBPACK_IMPORTED_MODULE_0__.isString)(arrayValue)) {\n return `${this.shortName}_${arrayValue}`;\n }\n else {\n let flat = arrayValue.map((t) => (0,_utils_isFunction_js__WEBPACK_IMPORTED_MODULE_4__.isFunction)(t.serialize) ? t.serialize() : t).join(this.sep);\n return `${this.shortName}_${flat}`;\n }\n }\n else {\n return '';\n }\n }\n value() {\n if (Array.isArray(this.origValue)) {\n return this.origValue.map(v => this.process(v));\n }\n else {\n return this.process(this.origValue);\n }\n }\n set(origValue) {\n if ((origValue == null) || Array.isArray(origValue)) {\n return super.set(origValue);\n }\n else {\n return super.set([origValue]);\n }\n }\n}\nclass TransformationParam extends Param {\n /**\n * A parameter that represents a transformation\n * @param {string} name - The name of the parameter in snake_case\n * @param {string} [shortName='t'] - The name of the serialized form of the parameter\n * @param {string} [sep='.'] - The separator to use when joining the array elements together\n * @param {function} [process=Util.identity ] - Manipulate origValue when value is called\n * @class TransformationParam\n * @extends Param\n * @ignore\n */\n constructor(name, shortName = \"t\", sep = '.', process = undefined) {\n super(name, shortName, process);\n this.sep = sep;\n }\n /**\n * Generate string representations of the transformation.\n * @returns {*} Returns either the transformation as a string, or an array of string representations.\n */\n serialize() {\n let result = '';\n const val = this.value();\n if ((0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_3__.isEmpty)(val)) {\n return result;\n }\n // val is an array of strings so join them\n if (allStrings(val)) {\n const joined = val.join(this.sep); // creates t1.t2.t3 in case multiple named transformations were configured\n if (!(0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_3__.isEmpty)(joined)) {\n // in case options.transformation was not set with an empty string (val != ['']);\n result = `${this.shortName}_${joined}`;\n }\n }\n else { // Convert val to an array of strings\n result = val.map((t) => {\n if ((0,_internal_utils_dataStructureUtils_js__WEBPACK_IMPORTED_MODULE_0__.isString)(t) && !(0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_3__.isEmpty)(t)) {\n return `${this.shortName}_${t}`;\n }\n if ((0,_utils_isFunction_js__WEBPACK_IMPORTED_MODULE_4__.isFunction)(t.serialize)) {\n return t.serialize();\n }\n if ((0,_utils_isObject_js__WEBPACK_IMPORTED_MODULE_2__.isObject)(t) && !(0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_3__.isEmpty)(t)) {\n return new Transformation(t).serialize();\n }\n return undefined;\n }).filter((t) => t);\n }\n return result;\n }\n set(origValue1) {\n this.origValue = origValue1;\n if (Array.isArray(this.origValue)) {\n return super.set(this.origValue);\n }\n else {\n return super.set([this.origValue]);\n }\n }\n}\nconst number_pattern = \"([0-9]*)\\\\.([0-9]+)|([0-9]+)\";\nconst offset_any_pattern = \"(\" + number_pattern + \")([%pP])?\";\nclass RangeParam extends Param {\n /**\n * A parameter that represents a range\n * @param {string} name - The name of the parameter in snake_case\n * @param {string} shortName - The name of the serialized form of the parameter\n * If a value is not provided, the parameter will not be serialized.\n * @param {function} [process=norm_range_value ] - Manipulate origValue when value is called\n * @class RangeParam\n * @extends Param\n * @ignore\n */\n constructor(name, shortName, process = RangeParam.norm_range_value) {\n super(name, shortName, process);\n }\n static norm_range_value(value) {\n let offset = String(value).match(new RegExp('^' + offset_any_pattern + '$'));\n if (offset) {\n let modifier = offset[5] != null ? 'p' : '';\n value = (offset[1] || offset[4]) + modifier;\n }\n return value;\n }\n}\nclass RawParam extends Param {\n constructor(name, shortName, process = _utils_legacyBaseUtil_js__WEBPACK_IMPORTED_MODULE_1__.identity) {\n super(name, shortName, process);\n }\n serialize() {\n return this.value();\n }\n}\nclass LayerParam extends Param {\n // Parse layer options\n // @return [string] layer transformation string\n // @private\n value() {\n if (this.origValue == null) {\n return '';\n }\n let result;\n if (this.origValue instanceof _legacyLayer_layer_js__WEBPACK_IMPORTED_MODULE_5__[\"default\"]) {\n result = this.origValue;\n }\n else if ((0,_utils_isObject_js__WEBPACK_IMPORTED_MODULE_2__.isObject)(this.origValue)) {\n let layerOptions = (0,_utils_legacyBaseUtil_js__WEBPACK_IMPORTED_MODULE_1__.withCamelCaseKeys)(this.origValue);\n // @ts-ignore\n if (layerOptions.resourceType === \"text\" || (layerOptions.text != null)) {\n result = new _legacyLayer_textlayer_js__WEBPACK_IMPORTED_MODULE_6__[\"default\"](layerOptions);\n }\n else { // @ts-ignore\n if (layerOptions.resourceType === \"subtitles\") {\n result = new _legacyLayer_subtitleslayer_js__WEBPACK_IMPORTED_MODULE_7__[\"default\"](layerOptions);\n }\n else { // @ts-ignore\n if (layerOptions.resourceType === \"fetch\" || (layerOptions.url != null)) {\n result = new _legacyLayer_fetchlayer_js__WEBPACK_IMPORTED_MODULE_8__[\"default\"](layerOptions);\n }\n else {\n result = new _legacyLayer_layer_js__WEBPACK_IMPORTED_MODULE_5__[\"default\"](layerOptions);\n }\n }\n }\n }\n else if ((0,_internal_utils_dataStructureUtils_js__WEBPACK_IMPORTED_MODULE_0__.isString)(this.origValue)) {\n if (/^fetch:.+/.test(this.origValue)) {\n result = new _legacyLayer_fetchlayer_js__WEBPACK_IMPORTED_MODULE_8__[\"default\"](this.origValue.substr(6));\n }\n else {\n result = this.origValue;\n }\n }\n else {\n result = '';\n }\n return result.toString();\n }\n static textStyle(layer) {\n return (new _legacyLayer_textlayer_js__WEBPACK_IMPORTED_MODULE_6__[\"default\"](layer)).textStyleIdentifier();\n }\n}\n/**\n * TransformationBase\n * Depends on 'configuration', 'parameters','util'\n * @internal\n */\nclass TransformationBase {\n /**\n * The base class for transformations.\n * Members of this class are documented as belonging to the {@link Transformation} class for convenience.\n * @class TransformationBase\n */\n constructor(options) {\n /** @private */\n /** @private */\n let parent;\n let trans;\n parent = void 0;\n trans = {};\n /**\n * Return an options object that can be used to create an identical Transformation\n * @function Transformation#toOptions\n * @return {Object} Returns a plain object representing this transformation\n */\n this.toOptions = (withChain) => {\n let opt = {};\n if (withChain == null) {\n withChain = true;\n }\n // @ts-ignore\n Object.keys(trans).forEach(key => opt[key] = trans[key].origValue);\n assignNotNull(opt, this.otherOptions);\n if (withChain && !(0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_3__.isEmpty)(this.chained)) {\n let list = this.chained.map((tr) => tr.toOptions());\n list.push(opt);\n opt = {};\n assignNotNull(opt, this.otherOptions);\n // @ts-ignore\n opt.transformation = list;\n }\n return opt;\n };\n /**\n * Set a parent for this object for chaining purposes.\n *\n * @function Transformation#setParent\n * @param {Object} object - the parent to be assigned to\n * @returns {Transformation} Returns this instance for chaining purposes.\n */\n this.setParent = (object) => {\n parent = object;\n if (object != null) {\n // @ts-ignore\n this.fromOptions(typeof object.toOptions === \"function\" ? object.toOptions() : void 0);\n }\n return this;\n };\n /**\n * Returns the parent of this object in the chain\n * @function Transformation#getParent\n * @protected\n * @return {Object} Returns the parent of this object if there is any\n */\n this.getParent = () => {\n return parent;\n };\n // Helper methods to create parameter methods\n // These methods are defined here because they access `trans` which is\n // a private member of `TransformationBase`\n /** @protected */\n this.param = (value, name, abbr, defaultValue, process) => {\n if (process == null) {\n if ((0,_utils_isFunction_js__WEBPACK_IMPORTED_MODULE_4__.isFunction)(defaultValue)) {\n process = defaultValue;\n }\n else {\n process = _utils_legacyBaseUtil_js__WEBPACK_IMPORTED_MODULE_1__.identity;\n }\n }\n // @ts-ignore\n trans[name] = new Param(name, abbr, process).set(value);\n return this;\n };\n /** @protected */\n this.rawParam = function (value, name, abbr, defaultValue, process) {\n process = lastArgCallback(arguments);\n // @ts-ignore\n trans[name] = new RawParam(name, abbr, process).set(value);\n return this;\n };\n /** @protected */\n this.rangeParam = function (value, name, abbr, defaultValue, process) {\n process = lastArgCallback(arguments);\n // @ts-ignore\n trans[name] = new RangeParam(name, abbr, process).set(value);\n return this;\n };\n /** @protected */\n this.arrayParam = function (value, name, abbr, sep = \":\", defaultValue = [], process = undefined) {\n process = lastArgCallback(arguments);\n // @ts-ignore\n trans[name] = new ArrayParam(name, abbr, sep, process).set(value);\n return this;\n };\n /** @protected */\n this.transformationParam = function (value, name, abbr, sep = \".\", defaultValue = undefined, process = undefined) {\n process = lastArgCallback(arguments);\n // @ts-ignore\n trans[name] = new TransformationParam(name, abbr, sep, process).set(value);\n return this;\n };\n this.layerParam = function (value, name, abbr) {\n // @ts-ignore\n trans[name] = new LayerParam(name, abbr).set(value);\n return this;\n };\n // End Helper methods\n /**\n * Get the value associated with the given name.\n * Get the value associated with the given name.\n * @function Transformation#getValue\n * @param {string} name - the name of the parameter\n * @return {*} the processed value associated with the given name\n * @description Use {@link get}.origValue for the value originally provided for the parameter\n */\n this.getValue = function (name) {\n // @ts-ignore\n let value = trans[name] && trans[name].value();\n return value != null ? value : this.otherOptions[name];\n };\n /**\n * Get the parameter object for the given parameter name\n * @function Transformation#get\n * @param {string} name the name of the transformation parameter\n * @returns {Param} the param object for the given name, or undefined\n */\n this.get = function (name) {\n // @ts-ignore\n return trans[name];\n };\n /**\n * Remove a transformation option from the transformation.\n * @function Transformation#remove\n * @param {string} name - the name of the option to remove\n * @return {*} Returns the option that was removed or null if no option by that name was found. The type of the\n * returned value depends on the value.\n */\n this.remove = function (name) {\n var temp;\n switch (false) {\n // @ts-ignore\n case trans[name] == null:\n // @ts-ignore\n temp = trans[name];\n // @ts-ignore\n delete trans[name];\n return temp.origValue;\n case this.otherOptions[name] == null:\n temp = this.otherOptions[name];\n delete this.otherOptions[name];\n return temp;\n default:\n return null;\n }\n };\n /**\n * Return an array of all the keys (option names) in the transformation.\n * @return {Array<string>} the keys in snakeCase format\n */\n this.keys = function () {\n var key;\n return ((function () {\n var results;\n results = [];\n for (key in trans) {\n if (key != null) {\n results.push(key.match(VAR_NAME_RE) ? key : (0,_utils_snakeCase_js__WEBPACK_IMPORTED_MODULE_9__.snakeCase)(key));\n }\n }\n return results;\n })()).sort();\n };\n /**\n * Returns a plain object representation of the transformation. Values are processed.\n * @function Transformation#toPlainObject\n * @return {Object} the transformation options as plain object\n */\n this.toPlainObject = function () {\n var hash, key, list;\n hash = {};\n for (key in trans) {\n // @ts-ignore\n hash[key] = trans[key].value();\n // @ts-ignore\n if ((0,_utils_isObject_js__WEBPACK_IMPORTED_MODULE_2__.isObject)(hash[key])) {\n // @ts-ignore\n hash[key] = (0,_internal_utils_cloneDeep_js__WEBPACK_IMPORTED_MODULE_10__.cloneDeep)(hash[key]);\n }\n }\n if (!(0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_3__.isEmpty)(this.chained)) {\n list = this.chained.map((tr) => tr.toPlainObject());\n list.push(hash);\n hash = {\n transformation: list\n };\n }\n return hash;\n };\n /**\n * Complete the current transformation and chain to a new one.\n * In the URL, transformations are chained together by slashes.\n * @function Transformation#chain\n * @return {Transformation} Returns this transformation for chaining\n * @example\n * var tr = cloudinary.Transformation.new();\n * tr.width(10).crop('fit').chain().angle(15).serialize()\n * // produces \"c_fit,w_10/a_15\"\n */\n this.chain = function () {\n var names, tr;\n names = Object.getOwnPropertyNames(trans);\n if (names.length !== 0) {\n tr = new this.constructor(this.toOptions(false));\n this.resetTransformations();\n this.chained.push(tr);\n }\n return this;\n };\n this.resetTransformations = function () {\n trans = {};\n return this;\n };\n this.otherOptions = {};\n this.chained = [];\n this.fromOptions(options);\n }\n /**\n * Merge the provided options with own's options\n * @param {Object} [options={}] key-value list of options\n * @returns {Transformation} Returns this instance for chaining\n */\n fromOptions(options = {}) {\n if (options instanceof TransformationBase) {\n this.fromTransformation(options);\n }\n else {\n if ((0,_internal_utils_dataStructureUtils_js__WEBPACK_IMPORTED_MODULE_0__.isString)(options) || Array.isArray(options)) {\n options = {\n transformation: options\n };\n }\n options = (0,_internal_utils_cloneDeep_js__WEBPACK_IMPORTED_MODULE_10__.cloneDeep)(options);\n // Handling of \"if\" statements precedes other options as it creates a chained transformation\n // @ts-ignore\n if (options[\"if\"]) {\n // @ts-ignore\n this.set(\"if\", options[\"if\"]);\n // @ts-ignore\n delete options[\"if\"];\n }\n for (let key in options) {\n // @ts-ignore\n let opt = options[key];\n if (opt != null) {\n if (key.match(VAR_NAME_RE)) {\n if (key !== '$attr') {\n this.set('variable', key, opt);\n }\n }\n else {\n this.set(key, opt);\n }\n }\n }\n }\n return this;\n }\n fromTransformation(other) {\n if (other instanceof TransformationBase) {\n other.keys().forEach(key => this.set(key, other.get(key).origValue));\n }\n return this;\n }\n /**\n * Set a parameter.\n * The parameter name `key` is converted to\n * @param {string} key - the name of the parameter\n * @param {*} values - the value of the parameter\n * @returns {Transformation} Returns this instance for chaining\n */\n set(key, ...values) {\n let camelKey;\n camelKey = (0,_utils_legacyBaseUtil_js__WEBPACK_IMPORTED_MODULE_1__.camelCase)(key);\n if ((0,_utils_legacyBaseUtil_js__WEBPACK_IMPORTED_MODULE_1__.contains)(methods, camelKey)) {\n // @ts-ignore\n this[camelKey].apply(this, values);\n }\n else {\n this.otherOptions[key] = values[0];\n }\n return this;\n }\n hasLayer() {\n return this.getValue(\"overlay\") || this.getValue(\"underlay\");\n }\n /**\n * Generate a string representation of the transformation.\n * @function Transformation#serialize\n * @return {string} Returns the transformation as a string\n */\n serialize() {\n var ifParam, j, len, paramList, ref, ref1, ref2, ref3, ref4, resultArray, t, transformationList, transformationString, transformations, value, variables, vars;\n resultArray = this.chained.map((tr) => tr.serialize());\n paramList = this.keys();\n transformations = (ref = this.get(\"transformation\")) != null ? ref.serialize() : void 0;\n ifParam = (ref1 = this.get(\"if\")) != null ? ref1.serialize() : void 0;\n variables = processVar((ref2 = this.get(\"variables\")) != null ? ref2.value() : void 0);\n paramList = (0,_utils_legacyBaseUtil_js__WEBPACK_IMPORTED_MODULE_1__.difference)(paramList, [\"transformation\", \"if\", \"variables\"]);\n vars = [];\n transformationList = [];\n for (j = 0, len = paramList.length; j < len; j++) {\n t = paramList[j];\n if (t.match(VAR_NAME_RE)) {\n vars.push(t + \"_\" + _expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize((ref3 = this.get(t)) != null ? ref3.value() : void 0));\n }\n else {\n transformationList.push((ref4 = this.get(t)) != null ? ref4.serialize() : void 0);\n }\n }\n switch (false) {\n case !(0,_internal_utils_dataStructureUtils_js__WEBPACK_IMPORTED_MODULE_0__.isString)(transformations):\n transformationList.push(transformations);\n break;\n case !Array.isArray(transformations):\n resultArray = resultArray.concat(transformations);\n }\n transformationList = (function () {\n var k, len1, results;\n results = [];\n for (k = 0, len1 = transformationList.length; k < len1; k++) {\n value = transformationList[k];\n if (Array.isArray(value) && !(0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_3__.isEmpty)(value) || !Array.isArray(value) && value) {\n results.push(value);\n }\n }\n return results;\n })();\n transformationList = vars.sort().concat(variables).concat(transformationList.sort());\n if (ifParam === \"if_end\") {\n transformationList.push(ifParam);\n }\n else if (!(0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_3__.isEmpty)(ifParam)) {\n transformationList.unshift(ifParam);\n }\n transformationString = (transformationList).filter(x => !!x).join(param_separator);\n if (!(0,_utils_isEmpty_js__WEBPACK_IMPORTED_MODULE_3__.isEmpty)(transformationString)) {\n resultArray.push(transformationString);\n }\n return (resultArray).filter((x) => !!x).join(trans_separator);\n }\n /**\n * Provide a list of all the valid transformation option names\n * @function Transformation#listNames\n * @private\n * @return {Array<string>} a array of all the valid option names\n */\n static listNames() {\n return methods;\n }\n /**\n * Returns the attributes for an HTML tag.\n * @function Cloudinary.toHtmlAttributes\n * @return PlainObject\n */\n toHtmlAttributes() {\n let attrName, height, options, ref2, ref3, value, width;\n options = {};\n let snakeCaseKey;\n Object.keys(this.otherOptions).forEach(key => {\n value = this.otherOptions[key];\n snakeCaseKey = (0,_utils_snakeCase_js__WEBPACK_IMPORTED_MODULE_9__.snakeCase)(key);\n if (!(0,_utils_legacyBaseUtil_js__WEBPACK_IMPORTED_MODULE_1__.contains)(PARAM_NAMES, snakeCaseKey) && !(0,_utils_legacyBaseUtil_js__WEBPACK_IMPORTED_MODULE_1__.contains)(URL_KEYS, snakeCaseKey)) {\n attrName = /^html_/.test(key) ? key.slice(5) : key;\n options[attrName] = value;\n }\n });\n // convert all \"html_key\" to \"key\" with the same value\n this.keys().forEach(key => {\n if (/^html_/.test(key)) {\n options[(0,_utils_legacyBaseUtil_js__WEBPACK_IMPORTED_MODULE_1__.camelCase)(key.slice(5))] = this.getValue(key);\n }\n });\n if (!(this.hasLayer() || this.getValue(\"angle\") || (0,_utils_legacyBaseUtil_js__WEBPACK_IMPORTED_MODULE_1__.contains)([\"fit\", \"limit\", \"lfill\"], this.getValue(\"crop\")))) {\n width = (ref2 = this.get(\"width\")) != null ? ref2.origValue : void 0;\n height = (ref3 = this.get(\"height\")) != null ? ref3.origValue : void 0;\n if (parseFloat(width) >= 1.0) {\n if (options.width == null) {\n options.width = width;\n }\n }\n if (parseFloat(height) >= 1.0) {\n if (options.height == null) {\n options.height = height;\n }\n }\n }\n return options;\n }\n static isValidParamName(name) {\n return methods.indexOf((0,_utils_legacyBaseUtil_js__WEBPACK_IMPORTED_MODULE_1__.camelCase)(name)) >= 0;\n }\n /**\n * Delegate to the parent (up the call chain) to produce HTML\n * @function Transformation#toHtml\n * @return {string} HTML representation of the parent if possible.\n * @example\n * tag = cloudinary.ImageTag.new(\"sample\", {cloud_name: \"demo\"})\n * // ImageTag {name: \"img\", publicId: \"sample\"}\n * tag.toHtml()\n * // <img src=\"http://res.cloudinary.com/demo/image/upload/sample\">\n * tag.transformation().crop(\"fit\").width(300).toHtml()\n * // <img src=\"http://res.cloudinary.com/demo/image/upload/c_fit,w_300/sample\">\n */\n toHtml() {\n var ref;\n return (ref = this.getParent()) != null ? typeof ref.toHtml === \"function\" ? ref.toHtml() : void 0 : void 0;\n }\n toString() {\n return this.serialize();\n }\n clone() {\n return new TransformationBase(this.toOptions(true));\n }\n}\nconst VAR_NAME_RE = /^\\$[a-zA-Z0-9]+$/;\nconst trans_separator = '/';\nconst param_separator = ',';\nfunction lastArgCallback(args) {\n var callback;\n callback = args != null ? args[args.length - 1] : void 0;\n if ((0,_utils_isFunction_js__WEBPACK_IMPORTED_MODULE_4__.isFunction)(callback)) {\n return callback;\n }\n else {\n return void 0;\n }\n}\nfunction processVar(varArray) {\n var j, len, name, results, v;\n if (Array.isArray(varArray)) {\n results = [];\n for (j = 0, len = varArray.length; j < len; j++) {\n [name, v] = varArray[j];\n results.push(`${name}_${_expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize(v)}`);\n }\n return results;\n }\n else {\n return varArray;\n }\n}\n// @ts-ignore\nfunction processCustomFunction({ function_type, source }) {\n if (function_type === 'remote') {\n return [function_type, btoa(source)].join(\":\");\n }\n else if (function_type === 'wasm') {\n return [function_type, source].join(\":\");\n }\n}\n/**\n * Transformation Class methods.\n * This is a list of the parameters defined in Transformation.\n * Values are camelCased.\n * @const Transformation.methods\n * @private\n * @ignore\n * @type {Array<string>}\n */\n/**\n * Parameters that are filtered out before passing the options to an HTML tag.\n *\n * The list of parameters is a combination of `Transformation::methods` and `Configuration::CONFIG_PARAMS`\n * @const {Array<string>} Transformation.PARAM_NAMES\n * @private\n * @ignore\n * @see toHtmlAttributes\n */\nclass Transformation extends TransformationBase {\n /**\n * Represents a single transformation.\n * @class Transformation\n * @example\n * t = new cloudinary.Transformation();\n * t.angle(20).crop(\"scale\").width(\"auto\");\n *\n * // or\n *\n * t = new cloudinary.Transformation( {angle: 20, crop: \"scale\", width: \"auto\"});\n * @see <a href=\"https://cloudinary.com/documentation/image_transformation_reference\"\n * target=\"_blank\">Available image transformations</a>\n * @see <a href=\"https://cloudinary.com/documentation/video_transformation_reference\"\n * target=\"_blank\">Available video transformations</a>\n */\n constructor(options) {\n super(options);\n }\n /**\n * Convenience constructor\n * @param {Object} options\n * @return {Transformation}\n * @example cl = cloudinary.Transformation.new( {angle: 20, crop: \"scale\", width: \"auto\"})\n */\n static new(options) {\n return new Transformation(options);\n }\n /*\n Transformation Parameters\n */\n angle(value) {\n this.arrayParam(value, \"angle\", \"a\", \".\", _expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize);\n return this;\n }\n audioCodec(value) {\n this.param(value, \"audio_codec\", \"ac\");\n return this;\n }\n audioFrequency(value) {\n this.param(value, \"audio_frequency\", \"af\");\n return this;\n }\n aspectRatio(value) {\n this.param(value, \"aspect_ratio\", \"ar\", _expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize);\n return this;\n }\n background(value) {\n this.param(value, \"background\", \"b\", Param.norm_color);\n return this;\n }\n bitRate(value) {\n this.param(value, \"bit_rate\", \"br\");\n return this;\n }\n border(value) {\n return this.param(value, \"border\", \"bo\", (border) => {\n if ((0,_utils_isObject_js__WEBPACK_IMPORTED_MODULE_2__.isObject)(border)) {\n border = Object.assign({}, {\n color: \"black\",\n width: 2\n }, border);\n return `${border.width}px_solid_${Param.norm_color(border.color)}`;\n }\n else {\n return border;\n }\n });\n }\n color(value) {\n this.param(value, \"color\", \"co\", Param.norm_color);\n return this;\n }\n colorSpace(value) {\n this.param(value, \"color_space\", \"cs\");\n return this;\n }\n crop(value) {\n this.param(value, \"crop\", \"c\");\n return this;\n }\n customFunction(value) {\n return this.param(value, \"custom_function\", \"fn\", () => {\n return processCustomFunction(value);\n });\n }\n customPreFunction(value) {\n if (this.get('custom_function')) {\n return;\n }\n return this.rawParam(value, \"custom_function\", \"\", () => {\n value = processCustomFunction(value);\n return value ? `fn_pre:${value}` : value;\n });\n }\n defaultImage(value) {\n this.param(value, \"default_image\", \"d\");\n return this;\n }\n delay(value) {\n this.param(value, \"delay\", \"dl\");\n return this;\n }\n density(value) {\n this.param(value, \"density\", \"dn\");\n return this;\n }\n duration(value) {\n this.rangeParam(value, \"duration\", \"du\");\n return this;\n }\n dpr(value) {\n return this.param(value, \"dpr\", \"dpr\", (dpr) => {\n dpr = dpr.toString();\n if (dpr != null ? dpr.match(/^\\d+$/) : void 0) {\n return dpr + \".0\";\n }\n else {\n return _expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize(dpr);\n }\n });\n }\n effect(value) {\n this.arrayParam(value, \"effect\", \"e\", \":\", _expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize);\n return this;\n }\n else() {\n return this.if('else');\n }\n endIf() {\n return this.if('end');\n }\n endOffset(value) {\n this.rangeParam(value, \"end_offset\", \"eo\");\n return this;\n }\n fallbackContent(value) {\n this.param(value, \"fallback_content\");\n return this;\n }\n fetchFormat(value) {\n this.param(value, \"fetch_format\", \"f\");\n return this;\n }\n format(value) {\n this.param(value, \"format\");\n return this;\n }\n flags(value) {\n this.arrayParam(value, \"flags\", \"fl\", \".\");\n return this;\n }\n gravity(value) {\n this.param(value, \"gravity\", \"g\");\n return this;\n }\n fps(value) {\n return this.param(value, \"fps\", \"fps\", (fps) => {\n if ((0,_internal_utils_dataStructureUtils_js__WEBPACK_IMPORTED_MODULE_0__.isString)(fps)) {\n return fps;\n }\n else if (Array.isArray(fps)) {\n return fps.join(\"-\");\n }\n else {\n return fps;\n }\n });\n }\n height(value) {\n return this.param(value, \"height\", \"h\", () => {\n if (this.getValue(\"crop\") || this.getValue(\"overlay\") || this.getValue(\"underlay\")) {\n return _expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize(value);\n }\n else {\n return null;\n }\n });\n }\n htmlHeight(value) {\n this.param(value, \"html_height\");\n return this;\n }\n htmlWidth(value) {\n this.param(value, \"html_width\");\n return this;\n }\n if(value = \"\") {\n var i, ifVal, j, ref, trIf, trRest;\n switch (value) {\n case \"else\":\n this.chain();\n return this.param(value, \"if\", \"if\");\n case \"end\":\n this.chain();\n for (i = j = ref = this.chained.length - 1; j >= 0; i = j += -1) {\n ifVal = this.chained[i].getValue(\"if\");\n if (ifVal === \"end\") {\n break;\n }\n else if (ifVal != null) {\n trIf = Transformation.new().if(ifVal);\n this.chained[i].remove(\"if\");\n trRest = this.chained[i];\n this.chained[i] = Transformation.new().transformation([trIf, trRest]);\n if (ifVal !== \"else\") {\n break;\n }\n }\n }\n return this.param(value, \"if\", \"if\");\n case \"\":\n return _condition_js__WEBPACK_IMPORTED_MODULE_12__[\"default\"].new().setParent(this);\n default:\n return this.param(value, \"if\", \"if\", (value) => {\n return _condition_js__WEBPACK_IMPORTED_MODULE_12__[\"default\"].new(value).toString();\n });\n }\n }\n keyframeInterval(value) {\n this.param(value, \"keyframe_interval\", \"ki\");\n return this;\n }\n ocr(value) {\n this.param(value, \"ocr\", \"ocr\");\n return this;\n }\n offset(value) {\n var end_o, start_o;\n [start_o, end_o] = ((0,_utils_isFunction_js__WEBPACK_IMPORTED_MODULE_4__.isFunction)(value != null ? value.split : void 0)) ? value.split('..') : Array.isArray(value) ? value : [null, null];\n if (start_o != null) {\n this.startOffset(start_o);\n }\n if (end_o != null) {\n return this.endOffset(end_o);\n }\n }\n opacity(value) {\n this.param(value, \"opacity\", \"o\", _expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize);\n return this;\n }\n overlay(value) {\n this.layerParam(value, \"overlay\", \"l\");\n return this;\n }\n page(value) {\n this.param(value, \"page\", \"pg\");\n return this;\n }\n poster(value) {\n this.param(value, \"poster\");\n return this;\n }\n prefix(value) {\n this.param(value, \"prefix\", \"p\");\n return this;\n }\n quality(value) {\n this.param(value, \"quality\", \"q\", _expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize);\n return this;\n }\n radius(value) {\n this.arrayParam(value, \"radius\", \"r\", \":\", _expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize);\n return this;\n }\n rawTransformation(value) {\n this.rawParam(value, \"raw_transformation\");\n return this;\n }\n size(value) {\n let height, width;\n if ((0,_utils_isFunction_js__WEBPACK_IMPORTED_MODULE_4__.isFunction)(value != null ? value.split : void 0)) {\n [width, height] = value.split('x');\n this.width(width);\n return this.height(height);\n }\n }\n sourceTypes(value) {\n this.param(value, \"source_types\");\n return this;\n }\n sourceTransformation(value) {\n return this.param(value, \"source_transformation\");\n }\n startOffset(value) {\n this.rangeParam(value, \"start_offset\", \"so\");\n return this;\n }\n streamingProfile(value) {\n this.param(value, \"streaming_profile\", \"sp\");\n return this;\n }\n transformation(value) {\n this.transformationParam(value, \"transformation\", \"t\");\n return this;\n }\n underlay(value) {\n this.layerParam(value, \"underlay\", \"u\");\n return this;\n }\n variable(name, value) {\n this.param(value, name, name);\n return this;\n }\n variables(values) {\n this.arrayParam(values, \"variables\");\n return this;\n }\n videoCodec(value) {\n this.param(value, \"video_codec\", \"vc\", Param.process_video_params);\n return this;\n }\n videoSampling(value) {\n this.param(value, \"video_sampling\", \"vs\");\n return this;\n }\n width(value) {\n this.param(value, \"width\", \"w\", () => {\n if (this.getValue(\"crop\") || this.getValue(\"overlay\") || this.getValue(\"underlay\")) {\n return _expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize(value);\n }\n else {\n return null;\n }\n });\n return this;\n }\n x(value) {\n this.param(value, \"x\", \"x\", _expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize);\n return this;\n }\n y(value) {\n this.param(value, \"y\", \"y\", _expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize);\n return this;\n }\n zoom(value) {\n this.param(value, \"zoom\", \"z\", _expression_js__WEBPACK_IMPORTED_MODULE_11__[\"default\"].normalize);\n return this;\n }\n}\n/**\n * Transformation Class methods.\n * This is a list of the parameters defined in Transformation.\n * Values are camelCased.\n */\nconst methods = [\n \"angle\",\n \"audioCodec\",\n \"audioFrequency\",\n \"aspectRatio\",\n \"background\",\n \"bitRate\",\n \"border\",\n \"color\",\n \"colorSpace\",\n \"crop\",\n \"customFunction\",\n \"customPreFunction\",\n \"defaultImage\",\n \"delay\",\n \"density\",\n \"duration\",\n \"dpr\",\n \"effect\",\n \"else\",\n \"endIf\",\n \"endOffset\",\n \"fallbackContent\",\n \"fetchFormat\",\n \"format\",\n \"flags\",\n \"gravity\",\n \"fps\",\n \"height\",\n \"htmlHeight\",\n \"htmlWidth\",\n \"if\",\n \"keyframeInterval\",\n \"ocr\",\n \"offset\",\n \"opacity\",\n \"overlay\",\n \"page\",\n \"poster\",\n \"prefix\",\n \"quality\",\n \"radius\",\n \"rawTransformation\",\n \"size\",\n \"sourceTypes\",\n \"sourceTransformation\",\n \"startOffset\",\n \"streamingProfile\",\n \"transformation\",\n \"underlay\",\n \"variable\",\n \"variables\",\n \"videoCodec\",\n \"videoSampling\",\n \"width\",\n \"x\",\n \"y\",\n \"zoom\"\n];\n/**\n * Parameters that are filtered out before passing the options to an HTML tag.\n *\n * The list of parameters is a combination of `Transformation::methods` and `Configuration::CONFIG_PARAMS`\n */\nconst PARAM_NAMES = methods.map(_utils_snakeCase_js__WEBPACK_IMPORTED_MODULE_9__.snakeCase).concat(_configuration_js__WEBPACK_IMPORTED_MODULE_13__.CONFIG_PARAMS);\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Transformation);\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/transformation.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processCustomFunction.js":
/*!*******************************************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processCustomFunction.js ***!
\*******************************************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ processCustomFunction: () => (/* binding */ processCustomFunction)\n/* harmony export */ });\n/* harmony import */ var _internal_utils_base64Encode_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../internal/utils/base64Encode.js */ \"../node_modules/@cloudinary/url-gen/internal/utils/base64Encode.js\");\n/* harmony import */ var _utils_isObject_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils/isObject.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/isObject.js\");\n\n\n/**\n * Parse custom_function options\n * @private\n * @param {object|*} customFunction a custom function object containing function_type and source values\n * @return {string|*} custom_function transformation string\n */\nfunction processCustomFunction(customFunction) {\n if (!(0,_utils_isObject_js__WEBPACK_IMPORTED_MODULE_0__.isObject)(customFunction)) {\n return customFunction;\n }\n if (customFunction.function_type === \"remote\") {\n const encodedSource = (0,_internal_utils_base64Encode_js__WEBPACK_IMPORTED_MODULE_1__.base64Encode)(customFunction.source)\n .replace(/\\+/g, '-') // Convert '+' to '-'\n .replace(/\\//g, '_') // Convert '/' to '_'\n .replace(/=+$/, ''); // Remove ending '='\n return [customFunction.function_type, encodedSource].join(\":\");\n }\n return [customFunction.function_type, customFunction.source].join(\":\");\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processCustomFunction.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processCustomPreFunction.js":
/*!**********************************************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processCustomPreFunction.js ***!
\**********************************************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ processCustomPreFunction: () => (/* binding */ processCustomPreFunction)\n/* harmony export */ });\n/* harmony import */ var _processCustomFunction_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./processCustomFunction.js */ \"../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processCustomFunction.js\");\n\n/**\n * Parse custom_pre_function options\n * @private\n * @param {object|*} customPreFunction a custom function object containing function_type and source values\n * @return {string|*} custom_pre_function transformation string\n */\nfunction processCustomPreFunction(customPreFunction) {\n const result = (0,_processCustomFunction_js__WEBPACK_IMPORTED_MODULE_0__.processCustomFunction)(customPreFunction);\n return typeof result === 'string' ? `pre:${result}` : null;\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processCustomPreFunction.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processDpr.js":
/*!********************************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processDpr.js ***!
\********************************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ processDpr: () => (/* binding */ processDpr)\n/* harmony export */ });\n/* harmony import */ var _expression_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../expression.js */ \"../node_modules/@cloudinary/url-gen/backwards/expression.js\");\n\n/**\n * Process DPR value. If input is 1 returns 1.0\n * @param value\n */\nfunction processDpr(value) {\n let dpr = value.toString();\n if (dpr != null ? dpr.match(/^\\d+$/) : void 0) {\n return dpr + \".0\";\n }\n else {\n return _expression_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].normalize(dpr);\n }\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processDpr.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processIf.js":
/*!*******************************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processIf.js ***!
\*******************************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ process_if: () => (/* binding */ process_if)\n/* harmony export */ });\n/* harmony import */ var _utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils/legacyNormalizeExpression.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/legacyNormalizeExpression.js\");\n\n/**\n * Parse \"if\" parameter\n * Translates the condition if provided.\n * @private\n * @return {string} \"if_\" + ifValue\n */\nfunction process_if(ifValue) {\n return ifValue ? \"if_\" + (0,_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_0__.legacyNormalizeExpression)(ifValue) : ifValue;\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processIf.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processLayer.js":
/*!**********************************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processLayer.js ***!
\**********************************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ processLayer: () => (/* binding */ processLayer),\n/* harmony export */ textStyle: () => (/* binding */ textStyle)\n/* harmony export */ });\n/* harmony import */ var _utils_isObject_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../utils/isObject.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/isObject.js\");\n/* harmony import */ var _internal_utils_base64Encode_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../internal/utils/base64Encode.js */ \"../node_modules/@cloudinary/url-gen/internal/utils/base64Encode.js\");\n/* harmony import */ var _consts_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../consts.js */ \"../node_modules/@cloudinary/url-gen/backwards/consts.js\");\n/* harmony import */ var _utils_smartEscape_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../utils/smartEscape.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/smartEscape.js\");\n/* harmony import */ var _legacyLayer_textlayer_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../legacyLayer/textlayer.js */ \"../node_modules/@cloudinary/url-gen/backwards/legacyLayer/textlayer.js\");\n/* harmony import */ var _legacyLayer_layer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../legacyLayer/layer.js */ \"../node_modules/@cloudinary/url-gen/backwards/legacyLayer/layer.js\");\n/**\n * Parse layer options\n * @private\n * @param {object|*} layer The layer to parse.\n * @return {string} layer transformation string\n */\n\n\n\n\n\n\nfunction textStyle(layer) {\n const keywords = [];\n let style = \"\";\n Object.keys(_consts_js__WEBPACK_IMPORTED_MODULE_0__.LAYER_KEYWORD_PARAMS).forEach((attr) => {\n let default_value = _consts_js__WEBPACK_IMPORTED_MODULE_0__.LAYER_KEYWORD_PARAMS[attr];\n let attr_value = layer[attr] || default_value;\n if (attr_value !== default_value) {\n keywords.push(attr_value);\n }\n });\n Object.keys(layer).forEach((attr) => {\n if (attr === \"letter_spacing\" || attr === \"line_spacing\") {\n keywords.push(`${attr}_${layer[attr]}`);\n }\n if (attr === \"font_hinting\") {\n keywords.push(`${attr.split(\"_\").pop()}_${layer[attr]}`);\n }\n if (attr === \"font_antialiasing\") {\n keywords.push(`antialias_${layer[attr]}`);\n }\n });\n if (layer.hasOwnProperty(\"font_size\" || 0) || !keywords || keywords.length === 0) {\n if (!layer.font_size)\n throw `Must supply font_size for text in overlay/underlay`;\n if (!layer.font_family)\n throw `Must supply font_family for text in overlay/underlay`;\n keywords.unshift(layer.font_size);\n keywords.unshift(layer.font_family);\n style = keywords.filter((a) => a).join(\"_\");\n }\n return style;\n}\nfunction processLayer(layer) {\n if (layer instanceof _legacyLayer_textlayer_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"] || layer instanceof _legacyLayer_layer_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"]) {\n return layer.toString();\n }\n let result = '';\n if ((0,_utils_isObject_js__WEBPACK_IMPORTED_MODULE_3__.isObject)(layer)) {\n if (layer.resource_type === \"fetch\" || (layer.url != null)) {\n result = `fetch:${(0,_internal_utils_base64Encode_js__WEBPACK_IMPORTED_MODULE_4__.base64Encode)(layer.url)}`;\n }\n else {\n let public_id = layer.public_id;\n let format = layer.format;\n let resource_type = layer.resource_type || \"image\";\n let type = layer.type || \"upload\";\n let text = layer.text;\n let style = null;\n let components = [];\n const noPublicId = !public_id || public_id.length === 0;\n if (!noPublicId) {\n public_id = public_id.replace(new RegExp(\"/\", 'g'), \":\");\n if (format != null) {\n public_id = `${public_id}.${format}`;\n }\n }\n if ((!text || text.length === 0) && resource_type !== \"text\") {\n if (noPublicId) {\n throw \"Must supply public_id for resource_type layer_parameter\";\n }\n if (resource_type === \"subtitles\") {\n style = textStyle(layer);\n }\n }\n else {\n resource_type = \"text\";\n type = null;\n // type is ignored for text layers\n style = textStyle(layer);\n if (text && text.length >= 0) {\n const noStyle = !style;\n if (!(noPublicId || noStyle) || (noPublicId && noStyle)) {\n throw \"Must supply either style parameters or a public_id when providing text parameter in a text overlay/underlay\";\n }\n let re = /\\$\\([a-zA-Z]\\w*\\)/g;\n let start = 0;\n let textSource = (0,_utils_smartEscape_js__WEBPACK_IMPORTED_MODULE_5__.smartEscape)(decodeURIComponent(text), /[,\\/]/g);\n text = \"\";\n for (let res = re.exec(textSource); res; res = re.exec(textSource)) {\n text += (0,_utils_smartEscape_js__WEBPACK_IMPORTED_MODULE_5__.smartEscape)(textSource.slice(start, res.index));\n text += res[0];\n start = res.index + res[0].length;\n }\n text += encodeURIComponent(textSource.slice(start));\n }\n }\n if (resource_type !== \"image\") {\n components.push(resource_type);\n }\n if (type !== \"upload\") {\n components.push(type);\n }\n components.push(style);\n components.push(public_id);\n components.push(text);\n result = components.filter((a) => a).join(\":\");\n }\n }\n else if (/^fetch:.+/.test(layer)) {\n result = `fetch:${(0,_internal_utils_base64Encode_js__WEBPACK_IMPORTED_MODULE_4__.base64Encode)(layer.substr(6))}`;\n }\n else {\n result = layer;\n }\n return result;\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processLayer.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processRadius.js":
/*!***********************************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processRadius.js ***!
\***********************************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ processRadius: () => (/* binding */ processRadius)\n/* harmony export */ });\n/* harmony import */ var _utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils/legacyNormalizeExpression.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/legacyNormalizeExpression.js\");\n\n/**\n * Parse radius options\n * @private\n * @param {Array<string|number>|string|number} _radius The radius to parse\n * @return {string} radius transformation string\n */\nfunction processRadius(_radius) {\n let radius = _radius;\n if (!radius) {\n return radius;\n }\n if (!Array.isArray(radius)) {\n radius = [radius];\n }\n if (radius.length === 0 || radius.length > 4) {\n throw new Error(\"Radius array should contain between 1 and 4 values\");\n }\n if (radius.findIndex((x) => x === null) >= 0) {\n throw new Error(\"Corner: Cannot be null\");\n }\n return radius.map(_utils_legacyNormalizeExpression_js__WEBPACK_IMPORTED_MODULE_0__.legacyNormalizeExpression).join(':');\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processRadius.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processVideoParams.js":
/*!****************************************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processVideoParams.js ***!
\****************************************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ processVideoParams: () => (/* binding */ processVideoParams)\n/* harmony export */ });\n/**\n * A video codec parameter can be either a String or a Hash.\n * @param {Object} param <code>vc_<codec>[ : <profile> : [<level>]]</code>\n * or <code>{ codec: 'h264', profile: 'basic', level: '3.1' }</code>\n * @return {String} <code><codec> : <profile> : [<level>]]</code> if a Hash was provided\n * or the param if a String was provided.\n * Returns null if param is not a Hash or String\n */\nfunction processVideoParams(param) {\n switch (param && param.constructor) {\n case Object: {\n let video = \"\";\n if ('codec' in param) {\n video = param.codec;\n if ('profile' in param) {\n video += \":\" + param.profile;\n if ('level' in param) {\n video += \":\" + param.level;\n }\n }\n }\n return video;\n }\n case String:\n return param;\n default:\n return null;\n }\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/transformationProcessing/processVideoParams.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/finalizeResourceType.js":
/*!***********************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/finalizeResourceType.js ***!
\***********************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ finalize_resource_type: () => (/* binding */ finalize_resource_type)\n/* harmony export */ });\nfunction finalize_resource_type(resource_type, type, url_suffix, use_root_path, shorten) {\n if (type == null) {\n type = 'upload';\n }\n if (url_suffix != null) {\n if (resource_type === 'image' && type === 'upload') {\n resource_type = \"images\";\n type = null;\n }\n else if (resource_type === 'image' && type === 'private') {\n resource_type = 'private_images';\n type = null;\n }\n else if (resource_type === 'image' && type === 'authenticated') {\n resource_type = 'authenticated_images';\n type = null;\n }\n else if (resource_type === 'raw' && type === 'upload') {\n resource_type = 'files';\n type = null;\n }\n else if (resource_type === 'video' && type === 'upload') {\n resource_type = 'videos';\n type = null;\n }\n else {\n throw new Error(\"URL Suffix only supported for image/upload, image/private, image/authenticated, video/upload and raw/upload\");\n }\n }\n if (use_root_path) {\n if ((resource_type === 'image' && type === 'upload') || (resource_type === 'images' && (type == null))) {\n resource_type = null;\n type = null;\n }\n else {\n throw new Error(\"Root path only supported for image/upload\");\n }\n }\n if (shorten && resource_type === 'image' && type === 'upload') {\n resource_type = 'iu';\n type = null;\n }\n return [resource_type, type];\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/finalizeResourceType.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/finalize_source.js":
/*!******************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/finalize_source.js ***!
\******************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ finalize_source: () => (/* binding */ finalize_source)\n/* harmony export */ });\n/* harmony import */ var _smartEscape_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./smartEscape.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/smartEscape.js\");\n\nfunction finalize_source(source, format, url_suffix) {\n let source_to_sign;\n source = source.replace(/([^:])\\/\\//g, '$1/');\n if (source.match(/^https?:\\//i)) {\n source = (0,_smartEscape_js__WEBPACK_IMPORTED_MODULE_0__.smartEscape)(source);\n source_to_sign = source;\n }\n else {\n source = encodeURIComponent(decodeURIComponent(source)).replace(/%3A/g, \":\").replace(/%2F/g, \"/\");\n source_to_sign = source;\n if (url_suffix) {\n if (url_suffix.match(/[\\.\\/]/)) {\n throw new Error('url_suffix should not include . or /');\n }\n source = source + '/' + url_suffix;\n }\n if (format != null) {\n source = source + '.' + format;\n source_to_sign = source_to_sign + '.' + format;\n }\n }\n return [source, source_to_sign];\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/finalize_source.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/isEmpty.js":
/*!**********************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/isEmpty.js ***!
\**********************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ isEmpty: () => (/* binding */ isEmpty)\n/* harmony export */ });\nfunction isEmpty(value) {\n return value === undefined ||\n value === null ||\n (typeof value === \"object\" && Object.keys(value).length === 0) ||\n (typeof value === \"string\" && value.trim().length === 0);\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/isEmpty.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/isFunction.js":
/*!*************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/isFunction.js ***!
\*************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ isFunction: () => (/* binding */ isFunction)\n/* harmony export */ });\n/**\n * Simple Is Function check\n *\n * @param variableToCheck\n * @returns {boolean}\n */\nfunction isFunction(variableToCheck) {\n return variableToCheck instanceof Function;\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/isFunction.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/isNumberLike.js":
/*!***************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/isNumberLike.js ***!
\***************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ isNumberLike: () => (/* binding */ isNumberLike)\n/* harmony export */ });\n/**\n * Return true is value is a number or a string representation of a number.\n * @function Util.isNumberLike\n * @param {*} value\n * @returns {boolean} true if value is a number\n * @example\n * Util.isNumber(0) // true\n * Util.isNumber(\"1.3\") // true\n * Util.isNumber(\"\") // false\n * Util.isNumber(undefined) // false\n */\nconst isNumberLike = function (value) {\n return (value != null) && !isNaN(parseFloat(value));\n};\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/isNumberLike.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/isObject.js":
/*!***********************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/isObject.js ***!
\***********************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ isObject: () => (/* binding */ isObject)\n/* harmony export */ });\n/**\n *\n * @param a\n */\nfunction isObject(a) {\n return typeof a === 'object' && a !== null;\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/isObject.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/legacyBaseUtil.js":
/*!*****************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/legacyBaseUtil.js ***!
\*****************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ camelCase: () => (/* binding */ camelCase),\n/* harmony export */ contains: () => (/* binding */ contains),\n/* harmony export */ convertKeys: () => (/* binding */ convertKeys),\n/* harmony export */ difference: () => (/* binding */ difference),\n/* harmony export */ identity: () => (/* binding */ identity),\n/* harmony export */ reWords: () => (/* binding */ reWords),\n/* harmony export */ withCamelCaseKeys: () => (/* binding */ withCamelCaseKeys)\n/* harmony export */ });\n/* harmony import */ var _isEmpty_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./isEmpty.js */ \"../node_modules/@cloudinary/url-gen/backwards/utils/isEmpty.js\");\n/**\n * Create a copy of the source object with all keys in camelCase\n * @function Util.withCamelCaseKeys\n * @return {Object} a new object\n * @param source\n */\n\nconst withCamelCaseKeys = function (source) {\n return convertKeys(source, camelCase);\n};\n/**\n * Convert string to camelCase\n * @function Util.camelCase\n * @param {string} source - the string to convert\n * @return {string} in camelCase format\n */\nconst camelCase = function (source) {\n let words = source.match(reWords);\n words = words.map(word => word.charAt(0).toLocaleUpperCase() + word.slice(1).toLocaleLowerCase());\n words[0] = words[0].toLocaleLowerCase();\n return words.join('');\n};\n/**\n * Creates a new object from source, with the keys transformed using the converter.\n * @param {object} source\n * @param {function|null} converter\n * @returns {object}\n */\nvar convertKeys = function (source, converter) {\n var result, value;\n result = {};\n for (let key in source) {\n value = source[key];\n if (converter) {\n key = converter(key);\n }\n if (!(0,_isEmpty_js__WEBPACK_IMPORTED_MODULE_0__.isEmpty)(key)) {\n // @ts-ignore\n result[key] = value;\n }\n }\n return result;\n};\nvar reWords = (function () {\n var lower, upper;\n upper = '[A-Z]';\n lower = '[a-z]+';\n return RegExp(upper + '+(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g');\n})();\nfunction identity(x) {\n return x;\n}\nfunction contains(a, obj) {\n for (let i = 0; i < a.length; i++) {\n if (a[i] === obj) {\n return true;\n }\n }\n return false;\n}\nfunction difference(arr1, arr2) {\n return arr1.filter(x => !arr2.includes(x));\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/legacyBaseUtil.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/legacyNormalizeExpression.js":
/*!****************************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/legacyNormalizeExpression.js ***!
\****************************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ legacyNormalizeExpression: () => (/* binding */ legacyNormalizeExpression)\n/* harmony export */ });\n/* harmony import */ var _consts_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../consts.js */ \"../node_modules/@cloudinary/url-gen/backwards/consts.js\");\n\n/**\n * Normalize an offset value\n * @param {String} expression a decimal value which may have a 'p' or '%' postfix. E.g. '35%', '0.4p'\n * @return {Object|String} a normalized String of the input value if possible otherwise the value itself\n */\nfunction legacyNormalizeExpression(expression) {\n if (typeof expression !== 'string' || expression.length === 0 || expression.match(/^!.+!$/)) {\n if (expression) {\n return expression.toString();\n }\n else {\n return expression;\n }\n }\n expression = String(expression);\n const operators = \"\\\\|\\\\||>=|<=|&&|!=|>|=|<|/|-|\\\\+|\\\\*|\\\\^\";\n // operators\n const operatorsPattern = \"((\" + operators + \")(?=[ _]))\";\n const operatorsReplaceRE = new RegExp(operatorsPattern, \"g\");\n expression = expression.replace(operatorsReplaceRE, (match) => {\n return _consts_js__WEBPACK_IMPORTED_MODULE_0__.LEGACY_CONDITIONAL_OPERATORS[match];\n });\n // predefined variables\n const predefinedVarsPattern = \"(\" + Object.keys(_consts_js__WEBPACK_IMPORTED_MODULE_0__.LEGACY_PREDEFINED_VARS).join(\"|\") + \")\";\n const userVariablePattern = '(\\\\$_*[^_ ]+)';\n const variablesReplaceRE = new RegExp(`${userVariablePattern}|${predefinedVarsPattern}`, \"g\");\n // @ts-ignore\n expression = expression.replace(variablesReplaceRE, (match) => (_consts_js__WEBPACK_IMPORTED_MODULE_0__.LEGACY_PREDEFINED_VARS[match] || match));\n return expression.replace(/[ _]+/g, '_');\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/legacyNormalizeExpression.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/norm_range_values.js":
/*!********************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/norm_range_values.js ***!
\********************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ normRangeValues: () => (/* binding */ normRangeValues)\n/* harmony export */ });\n/* harmony import */ var _consts_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../consts.js */ \"../node_modules/@cloudinary/url-gen/backwards/consts.js\");\n\n/**\n *\n * @param value\n */\nfunction normRangeValues(value) {\n const offset = String(value).match(_consts_js__WEBPACK_IMPORTED_MODULE_0__.RANGE_VALUE_RE);\n if (offset) {\n const modifier = offset[5] ? 'p' : '';\n return `${offset[1] || offset[4]}${modifier}`;\n }\n else {\n return value;\n }\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/norm_range_values.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/smartEscape.js":
/*!**************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/smartEscape.js ***!
\**************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ smartEscape: () => (/* binding */ smartEscape)\n/* harmony export */ });\n// Based on CGI::unescape. In addition does not escape / :\n// smart_escape = (string)->\n// encodeURIComponent(string).replace(/%3A/g, \":\").replace(/%2F/g, \"/\")\nfunction smartEscape(string, unsafe = /([^a-zA-Z0-9_.\\-\\/:]+)/g) {\n return string.replace(unsafe, function (match) {\n return match.split(\"\").map(function (c) {\n return \"%\" + c.charCodeAt(0).toString(16).toUpperCase();\n }).join(\"\");\n });\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/smartEscape.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/snakeCase.js":
/*!************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/snakeCase.js ***!
\************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ snakeCase: () => (/* binding */ snakeCase)\n/* harmony export */ });\n/**\n * Converts string to snake case\n * @param {string} str\n */\nconst snakeCase = (str) => str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/snakeCase.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/splitRange.js":
/*!*************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/splitRange.js ***!
\*************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ splitRange: () => (/* binding */ splitRange)\n/* harmony export */ });\n/* harmony import */ var _consts_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../consts.js */ \"../node_modules/@cloudinary/url-gen/backwards/consts.js\");\n/**\n * Split a range into the start and end values\n * @param range\n */\n\nfunction splitRange(range) {\n switch (range && range.constructor) {\n case String:\n if (!_consts_js__WEBPACK_IMPORTED_MODULE_0__.OFFSET_ANY_PATTERN_RE.test(range)) {\n return range;\n }\n return range.split(\"..\");\n case Array:\n return [[range], range[range.length - 1]];\n default:\n return [null, null];\n }\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/splitRange.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/toArray.js":
/*!**********************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/toArray.js ***!
\**********************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ toArray: () => (/* binding */ toArray)\n/* harmony export */ });\n/**\n *\n * @param arg\n */\nfunction toArray(arg) {\n switch (true) {\n case arg == null:\n return [];\n case Array.isArray(arg):\n return arg;\n default:\n return [arg];\n }\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/toArray.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/backwards/utils/unsigned_url_prefix.js":
/*!**********************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/backwards/utils/unsigned_url_prefix.js ***!
\**********************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ unsigned_url_prefix: () => (/* binding */ unsigned_url_prefix)\n/* harmony export */ });\n/* harmony import */ var _consts_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../consts.js */ \"../node_modules/@cloudinary/url-gen/backwards/consts.js\");\n\nfunction unsigned_url_prefix(source, cloud_name, private_cdn, cdn_subdomain, secure_cdn_subdomain, cname, secure, secure_distribution) {\n let prefix;\n if (cloud_name.indexOf(\"/\") === 0) {\n return '/res' + cloud_name;\n }\n let shared_domain = !private_cdn;\n if (secure) {\n if ((secure_distribution == null) || secure_distribution === _consts_js__WEBPACK_IMPORTED_MODULE_0__.OLD_AKAMAI_SHARED_CDN) {\n secure_distribution = private_cdn ? cloud_name + \"-res.cloudinary.com\" : _consts_js__WEBPACK_IMPORTED_MODULE_0__.SHARED_CDN;\n }\n if (shared_domain == null) {\n shared_domain = secure_distribution === _consts_js__WEBPACK_IMPORTED_MODULE_0__.SHARED_CDN;\n }\n prefix = 'https://' + secure_distribution;\n }\n else if (cname) {\n // let subdomain = cdn_subdomain ? 'a' + ((crc32(source) % 5) + 1) + '.' : '';\n prefix = 'http://' + cname;\n }\n else {\n let cdn_part = private_cdn ? cloud_name + '-' : '';\n let host = [cdn_part, 'res', '.cloudinary.com'].join('');\n prefix = 'http://' + host;\n }\n if (shared_domain) {\n prefix += '/' + cloud_name;\n }\n return prefix;\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/backwards/utils/unsigned_url_prefix.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/internal/utils/base64Encode.js":
/*!**************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/internal/utils/base64Encode.js ***!
\**************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ base64Encode: () => (/* binding */ base64Encode)\n/* harmony export */ });\n/**\n *\n * @private\n * @description An isomorphic Base64 function, provides browser and server support.\n * @param {string} input - A string to encode with base64\n */\nfunction base64Encode(input) {\n // Browser\n let encodedResult = '';\n if (typeof window !== 'undefined') {\n // encodeURI the input to support unicode characters\n // Since the URI might be encoded already, we try to decode it once before\n encodedResult = btoa(encodeURI(decodeURI(input)));\n }\n else {\n // NodeJS support\n encodedResult = global.Buffer.from(input).toString('base64');\n }\n return encodedResult\n .replace(/\\+/g, '-') // Convert '+' to '-'\n .replace(/\\//g, '_'); // Convert '/' to '_';\n}\n\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/internal/utils/base64Encode.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/internal/utils/cloneDeep.js":
/*!***********************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/internal/utils/cloneDeep.js ***!
\***********************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ cloneDeep: () => (/* binding */ cloneDeep)\n/* harmony export */ });\n/* eslint-disable */\n// @ts-nocheck\n// This file is a direct copy from lodash.clonedeep\n// Lodash.clonedeep has problems with the module exports, thus a copy was the shortest and cleanest solution\n/**\n * lodash (Custom Build) <https://lodash.com/>\n * Build: `lodash modularize exports=\"npm\" -o ./`\n * Copyright jQuery Foundation and other contributors <https://jquery.org/>\n * Released under MIT license <https://lodash.com/license>\n * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>\n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n/** Used as references for constious `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]', arrayTag = '[object Array]', boolTag = '[object Boolean]', dateTag = '[object Date]', errorTag = '[object Error]', funcTag = '[object Function]', genTag = '[object GeneratorFunction]', mapTag = '[object Map]', numberTag = '[object Number]', objectTag = '[object Object]', promiseTag = '[object Promise]', regexpTag = '[object RegExp]', setTag = '[object Set]', stringTag = '[object String]', symbolTag = '[object Symbol]', weakMapTag = '[object WeakMap]';\nvar arrayBufferTag = '[object ArrayBuffer]', dataViewTag = '[object DataView]', float32Tag = '[object Float32Array]', float64Tag = '[object Float64Array]', int8Tag = '[object Int8Array]', int16Tag = '[object Int16Array]', int32Tag = '[object Int32Array]', uint8Tag = '[object Uint8Array]', uint8ClampedTag = '[object Uint8ClampedArray]', uint16Tag = '[object Uint16Array]', uint32Tag = '[object Uint32Array]';\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n/** Used to match `RegExp` flags from their coerced string values. */\nvar reFlags = /\\w*$/;\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n/** Used to identify `toStringTag` values supported by `_.clone`. */\nvar cloneableTags = {};\ncloneableTags[argsTag] = cloneableTags[arrayTag] =\n cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =\n cloneableTags[boolTag] = cloneableTags[dateTag] =\n cloneableTags[float32Tag] = cloneableTags[float64Tag] =\n cloneableTags[int8Tag] = cloneableTags[int16Tag] =\n cloneableTags[int32Tag] = cloneableTags[mapTag] =\n cloneableTags[numberTag] = cloneableTags[objectTag] =\n cloneableTags[regexpTag] = cloneableTags[setTag] =\n cloneableTags[stringTag] = cloneableTags[symbolTag] =\n cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =\n cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;\ncloneableTags[errorTag] = cloneableTags[funcTag] =\n cloneableTags[weakMapTag] = false;\n/** Detect free constiable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n/** Detect free constiable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n/** Detect free constiable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n/** Detect free constiable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n/**\n * Adds the key-value `pair` to `map`.\n *\n * @private\n * @param {Object} map The map to modify.\n * @param {Array} pair The key-value pair to add.\n * @returns {Object} Returns `map`.\n */\nfunction addMapEntry(map, pair) {\n // Don't return `map.set` because it's not chainable in IE 11.\n map.set(pair[0], pair[1]);\n return map;\n}\n/**\n * Adds `value` to `set`.\n *\n * @private\n * @param {Object} set The set to modify.\n * @param {*} value The value to add.\n * @returns {Object} Returns `set`.\n */\nfunction addSetEntry(set, value) {\n // Don't return `set.add` because it's not chainable in IE 11.\n set.add(value);\n return set;\n}\n/**\n * A specialized version of `_.forEach` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns `array`.\n */\nfunction arrayEach(array, iteratee) {\n var index = -1, length = array ? array.length : 0;\n while (++index < length) {\n if (iteratee(array[index], index, array) === false) {\n break;\n }\n }\n return array;\n}\n/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1, length = values.length, offset = array.length;\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n/**\n * A specialized version of `_.reduce` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @param {*} [accumulator] The initial value.\n * @param {boolean} [initAccum] Specify using the first element of `array` as\n * the initial value.\n * @returns {*} Returns the accumulated value.\n */\nfunction arrayReduce(array, iteratee, accumulator, initAccum) {\n var index = -1, length = array ? array.length : 0;\n if (initAccum && length) {\n accumulator = array[++index];\n }\n while (++index < length) {\n accumulator = iteratee(accumulator, array[index], index, array);\n }\n return accumulator;\n}\n/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1, result = Array(n);\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n/**\n * Checks if `value` is a host object in IE < 9.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a host object, else `false`.\n */\nfunction isHostObject(value) {\n // Many host objects are `Object` objects that can coerce to strings\n // despite having improperly defined `toString` methods.\n var result = false;\n if (value != null && typeof value.toString != 'function') {\n try {\n result = !!(`${value}`);\n }\n catch (e) {\n }\n }\n return result;\n}\n/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n var index = -1, result = Array(map.size);\n map.forEach(function (value, key) {\n result[++index] = [key, value];\n });\n return result;\n}\n/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function (arg) {\n return func(transform(arg));\n };\n}\n/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1, result = Array(set.size);\n set.forEach(function (value) {\n result[++index] = value;\n });\n return result;\n}\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype, funcProto = Function.prototype, objectProto = Object.prototype;\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function () {\n var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n return uid ? (`Symbol(src)_1.${uid}`) : '';\n}());\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar objectToString = objectProto.toString;\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp(`^${funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?')}$`);\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined, Symbol = root.Symbol, Uint8Array = root.Uint8Array, getPrototype = overArg(Object.getPrototypeOf, Object), objectCreate = Object.create, propertyIsEnumerable = objectProto.propertyIsEnumerable, splice = arrayProto.splice;\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols, nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, nativeKeys = overArg(Object.keys, Object);\n/* Built-in method references that are verified to be native. */\nvar DataView = getNative(root, 'DataView'), Map = getNative(root, 'Map'), Promise = getNative(root, 'Promise'), Set = getNative(root, 'Set'), WeakMap = getNative(root, 'WeakMap'), nativeCreate = getNative(Object, 'create');\n/** Used to detect maps, sets, and weakmaps. */\nvar dataViewCtorString = toSource(DataView), mapCtorString = toSource(Map), promiseCtorString = toSource(Promise), setCtorString = toSource(Set), weakMapCtorString = toSource(WeakMap);\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined, symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n var index = -1, length = entries ? entries.length : 0;\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n this.__data__ = nativeCreate ? nativeCreate(null) : {};\n}\n/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n return this.has(key) && delete this.__data__[key];\n}\n/**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n var data = this.__data__;\n if (nativeCreate) {\n var result = data[key];\n return result === HASH_UNDEFINED ? undefined : result;\n }\n return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n/**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction hashHas(key) {\n var data = this.__data__;\n return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);\n}\n/**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n var data = this.__data__;\n data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n return this;\n}\n// Add methods to `Hash`.\nHash.prototype.clear = hashClear;\nHash.prototype.delete = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n var index = -1, length = entries ? entries.length : 0;\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n}\n/**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction listCacheDelete(key) {\n var data = this.__data__, index = assocIndexOf(data, key);\n if (index < 0) {\n return false;\n }\n var lastIndex = data.length - 1;\n if (index == lastIndex) {\n data.pop();\n }\n else {\n splice.call(data, index, 1);\n }\n return true;\n}\n/**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n var data = this.__data__, index = assocIndexOf(data, key);\n return index < 0 ? undefined : data[index][1];\n}\n/**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction listCacheHas(key) {\n return assocIndexOf(this.__data__, key) > -1;\n}\n/**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n var data = this.__data__, index = assocIndexOf(data, key);\n if (index < 0) {\n data.push([key, value]);\n }\n else {\n data[index][1] = value;\n }\n return this;\n}\n// Add methods to `ListCache`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype.delete = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n var index = -1, length = entries ? entries.length : 0;\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n this.__data__ = {\n 'hash': new Hash,\n 'map': new (Map || ListCache),\n 'string': new Hash\n };\n}\n/**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction mapCacheDelete(key) {\n return getMapData(this, key).delete(key);\n}\n/**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n return getMapData(this, key).get(key);\n}\n/**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction mapCacheHas(key) {\n return getMapData(this, key).has(key);\n}\n/**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n getMapData(this, key).set(key, value);\n return this;\n}\n// Add methods to `MapCache`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype.delete = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n/**\n * Creates a stack cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Stack(entries) {\n this.__data__ = new ListCache(entries);\n}\n/**\n * Removes all key-value entries from the stack.\n *\n * @private\n * @name clear\n * @memberOf Stack\n */\nfunction stackClear() {\n this.__data__ = new ListCache;\n}\n/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n return this.__data__.delete(key);\n}\n/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n/**\n * Sets the stack `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Stack\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the stack cache instance.\n */\nfunction stackSet(key, value) {\n var cache = this.__data__;\n if (cache instanceof ListCache) {\n var pairs = cache.__data__;\n if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {\n pairs.push([key, value]);\n return this;\n }\n cache = this.__data__ = new MapCache(pairs);\n }\n cache.set(key, value);\n return this;\n}\n// Add methods to `Stack`.\nStack.prototype.clear = stackClear;\nStack.prototype.delete = stackDelete;\nStack.prototype.get = stackGet;\nStack.prototype.has = stackHas;\nStack.prototype.set = stackSet;\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n // Safari 8.1 makes `arguments.callee` enumerable in strict mode.\n // Safari 9 makes `arguments.length` enumerable in strict mode.\n var result = (isArray(value) || isArguments(value))\n ? baseTimes(value.length, String)\n : [];\n var length = result.length, skipIndexes = !!length;\n for (var key in value) {\n if ((inherited || hasOwnProperty.call(value, key)) &&\n !(skipIndexes && (key == 'length' || isIndex(key, length)))) {\n result.push(key);\n }\n }\n return result;\n}\n/**\n * Assigns `value` to `key` of `object` if the existing value is not equivalent\n * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * for equality comparisons.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction assignValue(object, key, value) {\n var objValue = object[key];\n if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||\n (value === undefined && !(key in object))) {\n object[key] = value;\n }\n}\n/**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction assocIndexOf(array, key) {\n var length = array.length;\n while (length--) {\n if (eq(array[length][0], key)) {\n return length;\n }\n }\n return -1;\n}\n/**\n * The base implementation of `_.assign` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssign(object, source) {\n return object && copyObject(source, keys(source), object);\n}\n/**\n * The base implementation of `_.clone` and `_.cloneDeep` which tracks\n * traversed objects.\n *\n * @private\n * @param {*} value The value to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @param {boolean} [isFull] Specify a clone including symbols.\n * @param {Function} [customizer] The function to customize cloning.\n * @param {string} [key] The key of `value`.\n * @param {Object} [object] The parent object of `value`.\n * @param {Object} [stack] Tracks traversed objects and their clone counterparts.\n * @returns {*} Returns the cloned value.\n */\nfunction baseClone(value, isDeep, isFull, customizer, key, object, stack) {\n var result;\n if (customizer) {\n result = object ? customizer(value, key, object, stack) : customizer(value);\n }\n if (result !== undefined) {\n return result;\n }\n if (!isObject(value)) {\n return value;\n }\n var isArr = isArray(value);\n if (isArr) {\n result = initCloneArray(value);\n if (!isDeep) {\n return copyArray(value, result);\n }\n }\n else {\n var tag = getTag(value), isFunc = tag == funcTag || tag == genTag;\n if (isBuffer(value)) {\n return cloneBuffer(value, isDeep);\n }\n if (tag == objectTag || tag == argsTag || (isFunc && !object)) {\n if (isHostObject(value)) {\n return object ? value : {};\n }\n result = initCloneObject(isFunc ? {} : value);\n if (!isDeep) {\n return copySymbols(value, baseAssign(result, value));\n }\n }\n else {\n if (!cloneableTags[tag]) {\n return object ? value : {};\n }\n result = initCloneByTag(value, tag, baseClone, isDeep);\n }\n }\n // Check for circular references and return its corresponding clone.\n stack || (stack = new Stack);\n var stacked = stack.get(value);\n if (stacked) {\n return stacked;\n }\n stack.set(value, result);\n if (!isArr) {\n var props = isFull ? getAllKeys(value) : keys(value);\n }\n arrayEach(props || value, function (subValue, key) {\n if (props) {\n key = subValue;\n subValue = value[key];\n }\n // Recursively populate clone (susceptible to call stack limits).\n assignValue(result, key, baseClone(subValue, isDeep, isFull, customizer, key, value, stack));\n });\n return result;\n}\n/**\n * The base implementation of `_.create` without support for assigning\n * properties to the created object.\n *\n * @private\n * @param {Object} prototype The object to inherit from.\n * @returns {Object} Returns the new object.\n */\nfunction baseCreate(proto) {\n return isObject(proto) ? objectCreate(proto) : {};\n}\n/**\n * The base implementation of `getAllKeys` and `getAllKeysIn` which uses\n * `keysFunc` and `symbolsFunc` to get the enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @param {Function} symbolsFunc The function to get the symbols of `object`.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n var result = keysFunc(object);\n return isArray(object) ? result : arrayPush(result, symbolsFunc(object));\n}\n/**\n * The base implementation of `getTag`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n return objectToString.call(value);\n}\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n * else `false`.\n */\nfunction baseIsNative(value) {\n if (!isObject(value) || isMasked(value)) {\n return false;\n }\n var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;\n return pattern.test(toSource(value));\n}\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n if (!isPrototype(object)) {\n return nativeKeys(object);\n }\n var result = [];\n for (var key in Object(object)) {\n if (hasOwnProperty.call(object, key) && key != 'constructor') {\n result.push(key);\n }\n }\n return result;\n}\n/**\n * Creates a clone of `buffer`.\n *\n * @private\n * @param {Buffer} buffer The buffer to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Buffer} Returns the cloned buffer.\n */\nfunction cloneBuffer(buffer, isDeep) {\n if (isDeep) {\n return buffer.slice();\n }\n var result = new buffer.constructor(buffer.length);\n buffer.copy(result);\n return result;\n}\n/**\n * Creates a clone of `arrayBuffer`.\n *\n * @private\n * @param {ArrayBuffer} arrayBuffer The array buffer to clone.\n * @returns {ArrayBuffer} Returns the cloned array buffer.\n */\nfunction cloneArrayBuffer(arrayBuffer) {\n var result = new arrayBuffer.constructor(arrayBuffer.byteLength);\n new Uint8Array(result).set(new Uint8Array(arrayBuffer));\n return result;\n}\n/**\n * Creates a clone of `dataView`.\n *\n * @private\n * @param {Object} dataView The data view to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned data view.\n */\nfunction cloneDataView(dataView, isDeep) {\n var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;\n return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);\n}\n/**\n * Creates a clone of `map`.\n *\n * @private\n * @param {Object} map The map to clone.\n * @param {Function} cloneFunc The function to clone values.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned map.\n */\nfunction cloneMap(map, isDeep, cloneFunc) {\n var array = isDeep ? cloneFunc(mapToArray(map), true) : mapToArray(map);\n return arrayReduce(array, addMapEntry, new map.constructor);\n}\n/**\n * Creates a clone of `regexp`.\n *\n * @private\n * @param {Object} regexp The regexp to clone.\n * @returns {Object} Returns the cloned regexp.\n */\nfunction cloneRegExp(regexp) {\n var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));\n result.lastIndex = regexp.lastIndex;\n return result;\n}\n/**\n * Creates a clone of `set`.\n *\n * @private\n * @param {Object} set The set to clone.\n * @param {Function} cloneFunc The function to clone values.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned set.\n */\nfunction cloneSet(set, isDeep, cloneFunc) {\n var array = isDeep ? cloneFunc(setToArray(set), true) : setToArray(set);\n return arrayReduce(array, addSetEntry, new set.constructor);\n}\n/**\n * Creates a clone of the `symbol` object.\n *\n * @private\n * @param {Object} symbol The symbol object to clone.\n * @returns {Object} Returns the cloned symbol object.\n */\nfunction cloneSymbol(symbol) {\n return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};\n}\n/**\n * Creates a clone of `typedArray`.\n *\n * @private\n * @param {Object} typedArray The typed array to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned typed array.\n */\nfunction cloneTypedArray(typedArray, isDeep) {\n var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;\n return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);\n}\n/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1, length = source.length;\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n/**\n * Copies properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy properties from.\n * @param {Array} props The property identifiers to copy.\n * @param {Object} [object={}] The object to copy properties to.\n * @param {Function} [customizer] The function to customize copied values.\n * @returns {Object} Returns `object`.\n */\nfunction copyObject(source, props, object, customizer) {\n object || (object = {});\n var index = -1, length = props.length;\n while (++index < length) {\n var key = props[index];\n var newValue = customizer\n ? customizer(object[key], source[key], key, object, source)\n : undefined;\n assignValue(object, key, newValue === undefined ? source[key] : newValue);\n }\n return object;\n}\n/**\n * Copies own symbol properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbols(source, object) {\n return copyObject(source, getSymbols(source), object);\n}\n/**\n * Creates an array of own enumerable property names and symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeys(object) {\n return baseGetAllKeys(object, keys, getSymbols);\n}\n/**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n var data = map.__data__;\n return isKeyable(key)\n ? data[typeof key == 'string' ? 'string' : 'hash']\n : data.map;\n}\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n var value = getValue(object, key);\n return baseIsNative(value) ? value : undefined;\n}\n/**\n * Creates an array of the own enumerable symbol properties of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbols = nativeGetSymbols ? overArg(nativeGetSymbols, Object) : stubArray;\n/**\n * Gets the `toStringTag` of `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nvar getTag = baseGetTag;\n// Fallback for data views, maps, sets, and weak maps in IE 11,\n// for data views in Edge < 14, and promises in Node.js.\nif ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||\n (Map && getTag(new Map) != mapTag) ||\n (Promise && getTag(Promise.resolve()) != promiseTag) ||\n (Set && getTag(new Set) != setTag) ||\n (WeakMap && getTag(new WeakMap) != weakMapTag)) {\n getTag = function (value) {\n var result = objectToString.call(value), Ctor = result == objectTag ? value.constructor : undefined, ctorString = Ctor ? toSource(Ctor) : undefined;\n if (ctorString) {\n switch (ctorString) {\n case dataViewCtorString:\n return dataViewTag;\n case mapCtorString:\n return mapTag;\n case promiseCtorString:\n return promiseTag;\n case setCtorString:\n return setTag;\n case weakMapCtorString:\n return weakMapTag;\n }\n }\n return result;\n };\n}\n/**\n * Initializes an array clone.\n *\n * @private\n * @param {Array} array The array to clone.\n * @returns {Array} Returns the initialized clone.\n */\nfunction initCloneArray(array) {\n var length = array.length, result = array.constructor(length);\n // Add properties assigned by `RegExp#exec`.\n if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {\n result.index = array.index;\n result.input = array.input;\n }\n return result;\n}\n/**\n * Initializes an object clone.\n *\n * @private\n * @param {Object} object The object to clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneObject(object) {\n return (typeof object.constructor == 'function' && !isPrototype(object))\n ? baseCreate(getPrototype(object))\n : {};\n}\n/**\n * Initializes an object clone based on its `toStringTag`.\n *\n * **Note:** This function only supports cloning values with tags of\n * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.\n *\n * @private\n * @param {Object} object The object to clone.\n * @param {string} tag The `toStringTag` of the object to clone.\n * @param {Function} cloneFunc The function to clone values.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneByTag(object, tag, cloneFunc, isDeep) {\n var Ctor = object.constructor;\n switch (tag) {\n case arrayBufferTag:\n return cloneArrayBuffer(object);\n case boolTag:\n case dateTag:\n return new Ctor(+object);\n case dataViewTag:\n return cloneDataView(object, isDeep);\n case float32Tag:\n case float64Tag:\n case int8Tag:\n case int16Tag:\n case int32Tag:\n case uint8Tag:\n case uint8ClampedTag:\n case uint16Tag:\n case uint32Tag:\n return cloneTypedArray(object, isDeep);\n case mapTag:\n return cloneMap(object, isDeep, cloneFunc);\n case numberTag:\n case stringTag:\n return new Ctor(object);\n case regexpTag:\n return cloneRegExp(object);\n case setTag:\n return cloneSet(object, isDeep, cloneFunc);\n case symbolTag:\n return cloneSymbol(object);\n }\n}\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n length = length == null ? MAX_SAFE_INTEGER : length;\n return !!length &&\n (typeof value == 'number' || reIsUint.test(value)) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n return !!maskSrcKey && (maskSrcKey in func);\n}\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor, proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n return value === proto;\n}\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to process.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n }\n catch (e) {\n }\n try {\n return (`${func}`);\n }\n catch (e) {\n }\n }\n return '';\n}\n/**\n * This method is like `_.clone` except that it recursively clones `value`.\n *\n * @static\n * @memberOf _\n * @since 1.0.0\n * @category Lang\n * @param {*} value The value to recursively clone.\n * @returns {*} Returns the deep cloned value.\n * @see _.clone\n * @example\n *\n * var objects = [{ 'a': 1 }, { 'b': 2 }];\n *\n * var deep = _.cloneDeep(objects);\n * console.log(deep[0] === objects[0]);\n * // => false\n */\nfunction cloneDeep(value) {\n return baseClone(value, true, true);\n}\n/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n * else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nfunction isArguments(value) {\n // Safari 8.1 makes `arguments.callee` enumerable in strict mode.\n return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&\n (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);\n}\n/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n return value != null && isLength(value.length) && !isFunction(value);\n}\n/**\n * This method is like `_.isArrayLike` except that it also checks if `value`\n * is an object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array-like object,\n * else `false`.\n * @example\n *\n * _.isArrayLikeObject([1, 2, 3]);\n * // => true\n *\n * _.isArrayLikeObject(document.body.children);\n * // => true\n *\n * _.isArrayLikeObject('abc');\n * // => false\n *\n * _.isArrayLikeObject(_.noop);\n * // => false\n */\nfunction isArrayLikeObject(value) {\n return isObjectLike(value) && isArrayLike(value);\n}\n/**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 8-9 which returns 'object' for typed array and other constructors.\n var tag = isObject(value) ? objectToString.call(value) : '';\n return tag == funcTag || tag == genTag;\n}\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return !!value && (type == 'object' || type == 'function');\n}\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return !!value && typeof value == 'object';\n}\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/internal/utils/cloneDeep.js?");
/***/ }),
/***/ "../node_modules/@cloudinary/url-gen/internal/utils/dataStructureUtils.js":
/*!********************************************************************************!*\
!*** ../node_modules/@cloudinary/url-gen/internal/utils/dataStructureUtils.js ***!
\********************************************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ isString: () => (/* binding */ isString),\n/* harmony export */ mapToSortedArray: () => (/* binding */ mapToSortedArray)\n/* harmony export */ });\n/**\n * Sort a map by key\n * @private\n * @param map <string, any>\n * @Return array of map's values sorted by key\n */\nfunction mapToSortedArray(map, flags) {\n const array = Array.from(map.entries());\n // objects from the Array.from() method above are stored in array of arrays:\n // [[qualifierKey, QualifierObj], [qualifierKey, QualifierObj]]\n // Flags is an array of FlagQualifierObj\n // We need to convert it to the same form: [flagQualifier] => ['fl', flagQualifier]\n flags.forEach((flag) => {\n array.push(['fl', flag]); // push ['fl', flagQualifier]\n });\n return array.sort().map((v) => v[1]);\n}\n/**\n * Checks if `value` is a string.\n * @private\n * @param {*} value The value to check.\n * @return {boolean} `true` if `value` is a string, else `false`.\n */\nfunction isString(value) {\n return (typeof value === 'string' || value instanceof String);\n}\n\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/@cloudinary/url-gen/internal/utils/dataStructureUtils.js?");
/***/ }),
/***/ "../node_modules/uuid/dist/esm-browser/native.js":
/*!*******************************************************!*\
!*** ../node_modules/uuid/dist/esm-browser/native.js ***!
\*******************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nconst randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ randomUUID });\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/uuid/dist/esm-browser/native.js?");
/***/ }),
/***/ "../node_modules/uuid/dist/esm-browser/regex.js":
/*!******************************************************!*\
!*** ../node_modules/uuid/dist/esm-browser/regex.js ***!
\******************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i);\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/uuid/dist/esm-browser/regex.js?");
/***/ }),
/***/ "../node_modules/uuid/dist/esm-browser/rng.js":
/*!****************************************************!*\
!*** ../node_modules/uuid/dist/esm-browser/rng.js ***!
\****************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ rng)\n/* harmony export */ });\nlet getRandomValues;\nconst rnds8 = new Uint8Array(16);\nfunction rng() {\n if (!getRandomValues) {\n if (typeof crypto === 'undefined' || !crypto.getRandomValues) {\n throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');\n }\n getRandomValues = crypto.getRandomValues.bind(crypto);\n }\n return getRandomValues(rnds8);\n}\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/uuid/dist/esm-browser/rng.js?");
/***/ }),
/***/ "../node_modules/uuid/dist/esm-browser/stringify.js":
/*!**********************************************************!*\
!*** ../node_modules/uuid/dist/esm-browser/stringify.js ***!
\**********************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__),\n/* harmony export */ unsafeStringify: () => (/* binding */ unsafeStringify)\n/* harmony export */ });\n/* harmony import */ var _validate_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./validate.js */ \"../node_modules/uuid/dist/esm-browser/validate.js\");\n\nconst byteToHex = [];\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).slice(1));\n}\nfunction unsafeStringify(arr, offset = 0) {\n return (byteToHex[arr[offset + 0]] +\n byteToHex[arr[offset + 1]] +\n byteToHex[arr[offset + 2]] +\n byteToHex[arr[offset + 3]] +\n '-' +\n byteToHex[arr[offset + 4]] +\n byteToHex[arr[offset + 5]] +\n '-' +\n byteToHex[arr[offset + 6]] +\n byteToHex[arr[offset + 7]] +\n '-' +\n byteToHex[arr[offset + 8]] +\n byteToHex[arr[offset + 9]] +\n '-' +\n byteToHex[arr[offset + 10]] +\n byteToHex[arr[offset + 11]] +\n byteToHex[arr[offset + 12]] +\n byteToHex[arr[offset + 13]] +\n byteToHex[arr[offset + 14]] +\n byteToHex[arr[offset + 15]]).toLowerCase();\n}\nfunction stringify(arr, offset = 0) {\n const uuid = unsafeStringify(arr, offset);\n if (!(0,_validate_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n return uuid;\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (stringify);\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/uuid/dist/esm-browser/stringify.js?");
/***/ }),
/***/ "../node_modules/uuid/dist/esm-browser/v4.js":
/*!***************************************************!*\
!*** ../node_modules/uuid/dist/esm-browser/v4.js ***!
\***************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _native_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./native.js */ \"../node_modules/uuid/dist/esm-browser/native.js\");\n/* harmony import */ var _rng_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./rng.js */ \"../node_modules/uuid/dist/esm-browser/rng.js\");\n/* harmony import */ var _stringify_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./stringify.js */ \"../node_modules/uuid/dist/esm-browser/stringify.js\");\n\n\n\nfunction v4(options, buf, offset) {\n if (_native_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].randomUUID && !buf && !options) {\n return _native_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].randomUUID();\n }\n options = options || {};\n const rnds = options.random || (options.rng || _rng_js__WEBPACK_IMPORTED_MODULE_1__[\"default\"])();\n rnds[6] = (rnds[6] & 0x0f) | 0x40;\n rnds[8] = (rnds[8] & 0x3f) | 0x80;\n if (buf) {\n offset = offset || 0;\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n return buf;\n }\n return (0,_stringify_js__WEBPACK_IMPORTED_MODULE_2__.unsafeStringify)(rnds);\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (v4);\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/uuid/dist/esm-browser/v4.js?");
/***/ }),
/***/ "../node_modules/uuid/dist/esm-browser/validate.js":
/*!*********************************************************!*\
!*** ../node_modules/uuid/dist/esm-browser/validate.js ***!
\*********************************************************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _regex_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./regex.js */ \"../node_modules/uuid/dist/esm-browser/regex.js\");\n\nfunction validate(uuid) {\n return typeof uuid === 'string' && _regex_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"].test(uuid);\n}\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (validate);\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/uuid/dist/esm-browser/validate.js?");
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ id: moduleId,
/******/ loaded: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = __webpack_modules__;
/******/
/************************************************************************/
/******/ /* webpack/runtime/chunk loaded */
/******/ (() => {
/******/ var deferred = [];
/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
/******/ if(chunkIds) {
/******/ priority = priority || 0;
/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
/******/ deferred[i] = [chunkIds, fn, priority];
/******/ return;
/******/ }
/******/ var notFulfilled = Infinity;
/******/ for (var i = 0; i < deferred.length; i++) {
/******/ var [chunkIds, fn, priority] = deferred[i];
/******/ var fulfilled = true;
/******/ for (var j = 0; j < chunkIds.length; j++) {
/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
/******/ chunkIds.splice(j--, 1);
/******/ } else {
/******/ fulfilled = false;
/******/ if(priority < notFulfilled) notFulfilled = priority;
/******/ }
/******/ }
/******/ if(fulfilled) {
/******/ deferred.splice(i--, 1)
/******/ var r = fn();
/******/ if (r !== undefined) result = r;
/******/ }
/******/ }
/******/ return result;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/compat get default export */
/******/ (() => {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = (module) => {
/******/ var getter = module && module.__esModule ?
/******/ () => (module['default']) :
/******/ () => (module);
/******/ __webpack_require__.d(getter, { a: getter });
/******/ return getter;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/ensure chunk */
/******/ (() => {
/******/ __webpack_require__.f = {};
/******/ // This file contains only the entry chunk.
/******/ // The chunk loading function for additional chunks
/******/ __webpack_require__.e = (chunkId) => {
/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
/******/ __webpack_require__.f[key](chunkId, promises);
/******/ return promises;
/******/ }, []));
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/get javascript chunk filename */
/******/ (() => {
/******/ // This function allow to reference async chunks
/******/ __webpack_require__.u = (chunkId) => {
/******/ // return url for filenames based on template
/******/ return "" + chunkId + ".js";
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/get mini-css chunk filename */
/******/ (() => {
/******/ // This function allow to reference async chunks
/******/ __webpack_require__.miniCssF = (chunkId) => {
/******/ // return url for filenames based on template
/******/ return undefined;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/global */
/******/ (() => {
/******/ __webpack_require__.g = (function() {
/******/ if (typeof globalThis === 'object') return globalThis;
/******/ try {
/******/ return this || new Function('return this')();
/******/ } catch (e) {
/******/ if (typeof window === 'object') return window;
/******/ }
/******/ })();
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/load script */
/******/ (() => {
/******/ var inProgress = {};
/******/ var dataWebpackPrefix = "cloudinary-video-player:";
/******/ // loadScript function to load a script via script tag
/******/ __webpack_require__.l = (url, done, key, chunkId) => {
/******/ if(inProgress[url]) { inProgress[url].push(done); return; }
/******/ var script, needAttach;
/******/ if(key !== undefined) {
/******/ var scripts = document.getElementsByTagName("script");
/******/ for(var i = 0; i < scripts.length; i++) {
/******/ var s = scripts[i];
/******/ if(s.getAttribute("src") == url || s.getAttribute("data-webpack") == dataWebpackPrefix + key) { script = s; break; }
/******/ }
/******/ }
/******/ if(!script) {
/******/ needAttach = true;
/******/ script = document.createElement('script');
/******/
/******/ script.charset = 'utf-8';
/******/ script.timeout = 120;
/******/ if (__webpack_require__.nc) {
/******/ script.setAttribute("nonce", __webpack_require__.nc);
/******/ }
/******/ script.setAttribute("data-webpack", dataWebpackPrefix + key);
/******/
/******/ script.src = url;
/******/ }
/******/ inProgress[url] = [done];
/******/ var onScriptComplete = (prev, event) => {
/******/ // avoid mem leaks in IE.
/******/ script.onerror = script.onload = null;
/******/ clearTimeout(timeout);
/******/ var doneFns = inProgress[url];
/******/ delete inProgress[url];
/******/ script.parentNode && script.parentNode.removeChild(script);
/******/ doneFns && doneFns.forEach((fn) => (fn(event)));
/******/ if(prev) return prev(event);
/******/ }
/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);
/******/ script.onerror = onScriptComplete.bind(null, script.onerror);
/******/ script.onload = onScriptComplete.bind(null, script.onload);
/******/ needAttach && document.head.appendChild(script);
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/node module decorator */
/******/ (() => {
/******/ __webpack_require__.nmd = (module) => {
/******/ module.paths = [];
/******/ if (!module.children) module.children = [];
/******/ return module;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/publicPath */
/******/ (() => {
/******/ var scriptUrl;
/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + "";
/******/ var document = __webpack_require__.g.document;
/******/ if (!scriptUrl && document) {
/******/ if (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT')
/******/ scriptUrl = document.currentScript.src;
/******/ if (!scriptUrl) {
/******/ var scripts = document.getElementsByTagName("script");
/******/ if(scripts.length) {
/******/ var i = scripts.length - 1;
/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src;
/******/ }
/******/ }
/******/ }
/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration
/******/ // or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.
/******/ if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser");
/******/ scriptUrl = scriptUrl.replace(/#.*$/, "").replace(/\?.*$/, "").replace(/\/[^\/]+$/, "/");
/******/ __webpack_require__.p = scriptUrl;
/******/ })();
/******/
/******/ /* webpack/runtime/jsonp chunk loading */
/******/ (() => {
/******/ // no baseURI
/******/
/******/ // object to store loaded and loading chunks
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
/******/ var installedChunks = {
/******/ "cld-video-player": 0,
/******/ "styles": 0
/******/ };
/******/
/******/ __webpack_require__.f.j = (chunkId, promises) => {
/******/ // JSONP chunk loading for javascript
/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;
/******/ if(installedChunkData !== 0) { // 0 means "already installed".
/******/
/******/ // a Promise means "currently loading".
/******/ if(installedChunkData) {
/******/ promises.push(installedChunkData[2]);
/******/ } else {
/******/ if("styles" != chunkId) {
/******/ // setup Promise in chunk cache
/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));
/******/ promises.push(installedChunkData[2] = promise);
/******/
/******/ // start chunk loading
/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId);
/******/ // create error before stack unwound to get useful stacktrace later
/******/ var error = new Error();
/******/ var loadingEnded = (event) => {
/******/ if(__webpack_require__.o(installedChunks, chunkId)) {
/******/ installedChunkData = installedChunks[chunkId];
/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
/******/ if(installedChunkData) {
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
/******/ var realSrc = event && event.target && event.target.src;
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
/******/ error.name = 'ChunkLoadError';
/******/ error.type = errorType;
/******/ error.request = realSrc;
/******/ installedChunkData[1](error);
/******/ }
/******/ }
/******/ };
/******/ __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId);
/******/ } else installedChunks[chunkId] = 0;
/******/ }
/******/ }
/******/ };
/******/
/******/ // no prefetching
/******/
/******/ // no preloaded
/******/
/******/ // no HMR
/******/
/******/ // no HMR manifest
/******/
/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
/******/
/******/ // install a JSONP callback for chunk loading
/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
/******/ var [chunkIds, moreModules, runtime] = data;
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0;
/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
/******/ for(moduleId in moreModules) {
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(runtime) var result = runtime(__webpack_require__);
/******/ }
/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ installedChunks[chunkId][0]();
/******/ }
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/ return __webpack_require__.O(result);
/******/ }
/******/
/******/ var chunkLoadingGlobal = self["cloudinaryVideoPlayerChunkLoading"] = self["cloudinaryVideoPlayerChunkLoading"] || [];
/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
/******/ })();
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module depends on other loaded chunks and execution need to be delayed
/******/ var __webpack_exports__ = __webpack_require__.O(undefined, ["styles"], () => (__webpack_require__("./index.js")))
/******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__);
/******/
/******/ return __webpack_exports__;
/******/ })()
;
});