(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{237:function(n,e){n.exports=function(n){function e(n){"undefined"!=typeof console&&(console.error||console.log)("[Script Loader]",n)}try{"undefined"!=typeof execScript&&"undefined"!=typeof attachEvent&&"undefined"==typeof addEventListener?execScript(n):"undefined"!=typeof eval?eval.call(null,n):e("EvalError: No eval function available")}catch(n){e(n)}}},243:function(n,e){n.exports="(function (global, factory) {\n\ttypeof exports === 'object' && typeof module !== 'undefined' ? factory(require('video.js')) :\n\ttypeof define === 'function' && define.amd ? define(['video.js'], factory) :\n\t(factory(global.videojs));\n}(this, (function (videojs) { 'use strict';\n\nvideojs = videojs && videojs.hasOwnProperty('default') ? videojs['default'] : videojs;\n\n/**\n * Copyright 2017 Google Inc.\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 * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * Wraps the video.js player for the plugin.\n *\n * @param {Object} player Video.js player instance.\n * @param {Object} adsPluginSettings Settings for the contrib-ads plugin.\n * @param {Controller} controller Reference to the parent controller.\n */\nvar PlayerWrapper = function PlayerWrapper(player, adsPluginSettings, controller) {\n /**\n * Instance of the video.js player.\n */\n this.vjsPlayer = player;\n\n /**\n * Plugin controller.\n */\n this.controller = controller;\n\n /**\n * Timer used to track content progress.\n */\n this.contentTrackingTimer = null;\n\n /**\n * True if our content video has completed, false otherwise.\n */\n this.contentComplete = false;\n\n /**\n * Handle to interval that repeatedly updates current time.\n */\n this.updateTimeIntervalHandle = null;\n\n /**\n * Interval (ms) to check for player resize for fluid support.\n */\n this.updateTimeInterval = 1000;\n\n /**\n * Handle to interval that repeatedly checks for seeking.\n */\n this.seekCheckIntervalHandle = null;\n\n /**\n * Interval (ms) on which to check if the user is seeking through the\n * content.\n */\n this.seekCheckInterval = 1000;\n\n /**\n * Handle to interval that repeatedly checks for player resize.\n */\n this.resizeCheckIntervalHandle = null;\n\n /**\n * Interval (ms) to check for player resize for fluid support.\n */\n this.resizeCheckInterval = 250;\n\n /**\n * Threshold by which to judge user seeking. We check every 1000 ms to see\n * if the user is seeking. In order for us to decide that they are *not*\n * seeking, the content video playhead must only change by 900-1100 ms\n * between checks. Any greater change and we assume the user is seeking\n * through the video.\n */\n this.seekThreshold = 100;\n\n /**\n * Content ended listeners passed by the publisher to the plugin. Publishers\n * should allow the plugin to handle content ended to ensure proper support\n * of custom ad playback.\n */\n this.contentEndedListeners = [];\n\n /**\n * Stores the content source so we can re-populate it manually after a\n * post-roll on iOS.\n */\n this.contentSource = '';\n\n /**\n * Stores data for the content playhead tracker.\n */\n this.contentPlayheadTracker = {\n currentTime: 0,\n previousTime: 0,\n seeking: false,\n duration: 0\n };\n\n /**\n * Player dimensions. Used in our resize check.\n */\n this.vjsPlayerDimensions = {\n width: this.getPlayerWidth(),\n height: this.getPlayerHeight()\n };\n\n /**\n * Video.js control bar.\n */\n this.vjsControls = this.vjsPlayer.getChild('controlBar');\n\n /**\n * Vanilla HTML5 video player underneath the video.js player.\n */\n this.h5Player = null;\n\n this.vjsPlayer.one('play', this.setUpPlayerIntervals.bind(this));\n this.boundContentEndedListener = this.localContentEndedListener.bind(this);\n this.vjsPlayer.on('contentended', this.boundContentEndedListener);\n this.vjsPlayer.on('dispose', this.playerDisposedListener.bind(this));\n this.vjsPlayer.on('readyforpreroll', this.onReadyForPreroll.bind(this));\n this.vjsPlayer.ready(this.onPlayerReady.bind(this));\n\n this.vjsPlayer.ads(adsPluginSettings);\n};\n\n/**\n * Set up the intervals we use on the player.\n */\nPlayerWrapper.prototype.setUpPlayerIntervals = function () {\n this.updateTimeIntervalHandle = setInterval(this.updateCurrentTime.bind(this), this.updateTimeInterval);\n this.seekCheckIntervalHandle = setInterval(this.checkForSeeking.bind(this), this.seekCheckInterval);\n this.resizeCheckIntervalHandle = setInterval(this.checkForResize.bind(this), this.resizeCheckInterval);\n};\n\n/**\n * Updates the current time of the video\n */\nPlayerWrapper.prototype.updateCurrentTime = function () {\n if (!this.contentPlayheadTracker.seeking) {\n this.contentPlayheadTracker.currentTime = this.vjsPlayer.currentTime();\n }\n};\n\n/**\n * Detects when the user is seeking through a video.\n * This is used to prevent mid-rolls from playing while a user is seeking.\n *\n * There *is* a seeking property of the HTML5 video element, but it's not\n * properly implemented on all platforms (e.g. mobile safari), so we have to\n * check ourselves to be sure.\n */\nPlayerWrapper.prototype.checkForSeeking = function () {\n var tempCurrentTime = this.vjsPlayer.currentTime();\n var diff = (tempCurrentTime - this.contentPlayheadTracker.previousTime) * 1000;\n if (Math.abs(diff) > this.seekCheckInterval + this.seekThreshold) {\n this.contentPlayheadTracker.seeking = true;\n } else {\n this.contentPlayheadTracker.seeking = false;\n }\n this.contentPlayheadTracker.previousTime = this.vjsPlayer.currentTime();\n};\n\n/**\n * Detects when the player is resized (for fluid support) and resizes the\n * ads manager to match.\n */\nPlayerWrapper.prototype.checkForResize = function () {\n var currentWidth = this.getPlayerWidth();\n var currentHeight = this.getPlayerHeight();\n\n if (currentWidth != this.vjsPlayerDimensions.width || currentHeight != this.vjsPlayerDimensions.height) {\n this.vjsPlayerDimensions.width = currentWidth;\n this.vjsPlayerDimensions.height = currentHeight;\n this.controller.onPlayerResize(currentWidth, currentHeight);\n }\n};\n\n/**\n * Local content ended listener for contentComplete.\n */\nPlayerWrapper.prototype.localContentEndedListener = function () {\n if (!this.contentComplete) {\n this.contentComplete = true;\n this.controller.onContentComplete();\n }\n\n for (var index in this.contentEndedListeners) {\n if (typeof this.contentEndedListeners[index] === 'function') {\n this.contentEndedListeners[index]();\n }\n }\n\n clearInterval(this.updateTimeIntervalHandle);\n clearInterval(this.seekCheckIntervalHandle);\n clearInterval(this.resizeCheckIntervalHandle);\n if (this.vjsPlayer.el()) {\n this.vjsPlayer.one('play', this.setUpPlayerIntervals.bind(this));\n }\n};\n\n/**\n * Called when it's time to play a post-roll but we don't have one to play.\n */\nPlayerWrapper.prototype.onNoPostroll = function () {\n this.vjsPlayer.trigger('nopostroll');\n};\n\n/**\n * Detects when the video.js player has been disposed.\n */\nPlayerWrapper.prototype.playerDisposedListener = function () {\n this.contentEndedListeners = [];\n this.controller.onPlayerDisposed();\n\n this.contentComplete = true;\n this.vjsPlayer.off('contentended', this.boundContentEndedListener);\n\n // Bug fix: https://github.com/googleads/videojs-ima/issues/306\n if (this.vjsPlayer.ads.adTimeoutTimeout) {\n clearTimeout(this.vjsPlayer.ads.adTimeoutTimeout);\n }\n\n var intervalsToClear = [this.updateTimeIntervalHandle, this.seekCheckIntervalHandle, this.resizeCheckIntervalHandle];\n for (var index in intervalsToClear) {\n if (intervalsToClear[index]) {\n clearInterval(intervalsToClear[index]);\n }\n }\n};\n\n/**\n * Start ad playback, or content video playback in the absence of a\n * pre-roll.\n */\nPlayerWrapper.prototype.onReadyForPreroll = function () {\n this.controller.onPlayerReadyForPreroll();\n};\n\n/**\n * Called when the player fires its 'ready' event.\n */\nPlayerWrapper.prototype.onPlayerReady = function () {\n this.h5Player = document.getElementById(this.getPlayerId()).getElementsByClassName('vjs-tech')[0];\n\n // Detect inline options\n if (this.h5Player.hasAttribute('autoplay')) {\n this.controller.setSetting('adWillAutoPlay', true);\n }\n\n // Sync ad volume with player volume.\n this.onVolumeChange();\n this.vjsPlayer.on('fullscreenchange', this.onFullscreenChange.bind(this));\n this.vjsPlayer.on('volumechange', this.onVolumeChange.bind(this));\n\n this.controller.onPlayerReady();\n};\n\n/**\n * Listens for the video.js player to change its fullscreen status. This\n * keeps the fullscreen-ness of the AdContainer in sync with the player.\n */\nPlayerWrapper.prototype.onFullscreenChange = function () {\n if (this.vjsPlayer.isFullscreen()) {\n this.controller.onPlayerEnterFullscreen();\n } else {\n this.controller.onPlayerExitFullscreen();\n }\n};\n\n/**\n * Listens for the video.js player to change its volume. This keeps the ad\n * volume in sync with the content volume if the volume of the player is\n * changed while content is playing.\n */\nPlayerWrapper.prototype.onVolumeChange = function () {\n var newVolume = this.vjsPlayer.muted() ? 0 : this.vjsPlayer.volume();\n this.controller.onPlayerVolumeChanged(newVolume);\n};\n\n/**\n * Inject the ad container div into the DOM.\n *\n * @param{HTMLElement} adContainerDiv The ad container div.\n */\nPlayerWrapper.prototype.injectAdContainerDiv = function (adContainerDiv) {\n this.vjsControls.el().parentNode.appendChild(adContainerDiv);\n};\n\n/**\n * @return {Object} The content player.\n */\nPlayerWrapper.prototype.getContentPlayer = function () {\n return this.h5Player;\n};\n\n/**\n * @return {number} The volume, 0-1.\n */\nPlayerWrapper.prototype.getVolume = function () {\n return this.vjsPlayer.muted() ? 0 : this.vjsPlayer.volume();\n};\n\n/**\n * Set the volume of the player. 0-1.\n *\n * @param {number} volume The new volume.\n */\nPlayerWrapper.prototype.setVolume = function (volume) {\n this.vjsPlayer.volume(volume);\n if (volume == 0) {\n this.vjsPlayer.muted(true);\n } else {\n this.vjsPlayer.muted(false);\n }\n};\n\n/**\n * Ummute the player.\n */\nPlayerWrapper.prototype.unmute = function () {\n this.vjsPlayer.muted(false);\n};\n\n/**\n * Mute the player.\n */\nPlayerWrapper.prototype.mute = function () {\n this.vjsPlayer.muted(true);\n};\n\n/**\n * Play the video.\n */\nPlayerWrapper.prototype.play = function () {\n this.vjsPlayer.play();\n};\n\n/**\n * Get the player width.\n *\n * @return {number} The player's width.\n */\nPlayerWrapper.prototype.getPlayerWidth = function () {\n var width = (getComputedStyle(this.vjsPlayer.el()) || {}).width;\n\n if (!width || parseInt(width, 10) === 0) {\n width = (this.vjsPlayer.el().getBoundingClientRect() || {}).width;\n }\n\n return parseInt(width, 10) || this.vjsPlayer.width();\n};\n\n/**\n * Get the player height.\n *\n * @return {number} The player's height.\n */\nPlayerWrapper.prototype.getPlayerHeight = function () {\n var height = (getComputedStyle(this.vjsPlayer.el()) || {}).height;\n\n if (!height || parseInt(height, 10) === 0) {\n height = (this.vjsPlayer.el().getBoundingClientRect() || {}).height;\n }\n\n return parseInt(height, 10) || this.vjsPlayer.height();\n};\n\n/**\n * @return {Object} The vjs player's options object.\n */\nPlayerWrapper.prototype.getPlayerOptions = function () {\n return this.vjsPlayer.options_;\n};\n\n/**\n * Returns the instance of the player id.\n * @return {string} The player id.\n */\nPlayerWrapper.prototype.getPlayerId = function () {\n return this.vjsPlayer.id();\n};\n\n/**\n * Toggle fullscreen state.\n */\nPlayerWrapper.prototype.toggleFullscreen = function () {\n if (this.vjsPlayer.isFullscreen()) {\n this.vjsPlayer.exitFullscreen();\n } else {\n this.vjsPlayer.requestFullscreen();\n }\n};\n\n/**\n * Returns the content playhead tracker.\n *\n * @return {Object} The content playhead tracker.\n */\nPlayerWrapper.prototype.getContentPlayheadTracker = function () {\n return this.contentPlayheadTracker;\n};\n\n/**\n * Handles ad errors.\n *\n * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nPlayerWrapper.prototype.onAdError = function (adErrorEvent) {\n this.vjsControls.show();\n var errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack;\n this.vjsPlayer.trigger({ type: 'adserror', data: {\n AdError: errorMessage,\n AdErrorEvent: adErrorEvent\n } });\n};\n\n/**\n * Handles ad break starting.\n */\nPlayerWrapper.prototype.onAdBreakStart = function () {\n this.contentSource = this.vjsPlayer.currentSrc();\n this.vjsPlayer.off('contentended', this.boundContentEndedListener);\n this.vjsPlayer.ads.startLinearAdMode();\n this.vjsControls.hide();\n this.vjsPlayer.pause();\n};\n\n/**\n * Handles ad break ending.\n */\nPlayerWrapper.prototype.onAdBreakEnd = function () {\n this.vjsPlayer.on('contentended', this.boundContentEndedListener);\n if (this.vjsPlayer.ads.inAdBreak()) {\n this.vjsPlayer.ads.endLinearAdMode();\n }\n this.vjsControls.show();\n};\n\n/**\n * Handles an individual ad start.\n */\nPlayerWrapper.prototype.onAdStart = function () {\n this.vjsPlayer.trigger('ads-ad-started');\n};\n\n/**\n * Handles when all ads have finished playing.\n */\nPlayerWrapper.prototype.onAllAdsCompleted = function () {\n if (this.contentComplete == true) {\n if (this.h5Player.src != this.contentSource) {\n this.vjsPlayer.src(this.contentSource);\n }\n this.controller.onContentAndAdsCompleted();\n }\n};\n\n/**\n * Triggers adsready for contrib-ads.\n */\nPlayerWrapper.prototype.onAdsReady = function () {\n this.vjsPlayer.trigger('adsready');\n};\n\n/**\n * Changes the player source.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?boolean} playOnLoad True to play the content once it has loaded,\n * false to only load the content but not start playback.\n */\nPlayerWrapper.prototype.changeSource = function (contentSrc, playOnLoad) {\n // Only try to pause the player when initialised with a source already\n if (this.vjsPlayer.currentSrc()) {\n this.vjsPlayer.currentTime(0);\n this.vjsPlayer.pause();\n }\n if (contentSrc) {\n this.vjsPlayer.src(contentSrc);\n }\n if (playOnLoad) {\n this.vjsPlayer.one('loadedmetadata', this.playContentFromZero.bind(this));\n } else {\n this.vjsPlayer.one('loadedmetadata', this.seekContentToZero.bind(this));\n }\n};\n\n/**\n * Seeks content to 00:00:00. This is used as an event handler for the\n * loadedmetadata event, since seeking is not possible until that event has\n * fired.\n */\nPlayerWrapper.prototype.seekContentToZero = function () {\n this.vjsPlayer.currentTime(0);\n};\n\n/**\n * Seeks content to 00:00:00 and starts playback. This is used as an event\n * handler for the loadedmetadata event, since seeking is not possible until\n * that event has fired.\n */\nPlayerWrapper.prototype.playContentFromZero = function () {\n this.vjsPlayer.currentTime(0);\n this.vjsPlayer.play();\n};\n\n/**\n * Triggers an event on the VJS player\n * @param {string} name The event name.\n * @param {Object} data The event data.\n */\nPlayerWrapper.prototype.triggerPlayerEvent = function (name, data) {\n this.vjsPlayer.trigger(name, data);\n};\n\n/**\n * Listener JSDoc for ESLint. This listener can be passed to\n * addContentEndedListener.\n * @callback listener\n */\n\n/**\n * Adds a listener for the 'contentended' event of the video player. This should\n * be used instead of setting an 'contentended' listener directly to ensure that\n * the ima can do proper cleanup of the SDK before other event listeners are\n * called.\n * @param {listener} listener The listener to be called when content\n * completes.\n */\nPlayerWrapper.prototype.addContentEndedListener = function (listener) {\n this.contentEndedListeners.push(listener);\n};\n\n/**\n * Reset the player.\n */\nPlayerWrapper.prototype.reset = function () {\n this.vjsPlayer.on('contentended', this.boundContentEndedListener);\n this.vjsControls.show();\n if (this.vjsPlayer.ads.inAdBreak()) {\n this.vjsPlayer.ads.endLinearAdMode();\n }\n // Reset the content time we give the SDK. Fixes an issue where requesting\n // VMAP followed by VMAP would play the second mid-rolls as pre-rolls if\n // the first playthrough of the video passed the second response's\n // mid-roll time.\n this.contentPlayheadTracker.currentTime = 0;\n this.contentComplete = false;\n};\n\n/**\n * Copyright 2017 Google Inc.\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 * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * Ad UI implementation.\n *\n * @param {Controller} controller Plugin controller.\n * @constructor\n * @struct\n * @final\n */\nvar AdUi = function AdUi(controller) {\n /**\n * Plugin controller.\n */\n this.controller = controller;\n\n /**\n * Div used as an ad container.\n */\n this.adContainerDiv = document.createElement('div');\n\n /**\n * Div used to display ad controls.\n */\n this.controlsDiv = document.createElement('div');\n\n /**\n * Div used to display ad countdown timer.\n */\n this.countdownDiv = document.createElement('div');\n\n /**\n * Div used to display add seek bar.\n */\n this.seekBarDiv = document.createElement('div');\n\n /**\n * Div used to display ad progress (in seek bar).\n */\n this.progressDiv = document.createElement('div');\n\n /**\n * Div used to display ad play/pause button.\n */\n this.playPauseDiv = document.createElement('div');\n\n /**\n * Div used to display ad mute button.\n */\n this.muteDiv = document.createElement('div');\n\n /**\n * Div used by the volume slider.\n */\n this.sliderDiv = document.createElement('div');\n\n /**\n * Volume slider level visuals\n */\n this.sliderLevelDiv = document.createElement('div');\n\n /**\n * Div used to display ad fullscreen button.\n */\n this.fullscreenDiv = document.createElement('div');\n\n /**\n * Bound event handler for onMouseUp.\n */\n this.boundOnMouseUp = this.onMouseUp.bind(this);\n\n /**\n * Bound event handler for onMouseMove.\n */\n this.boundOnMouseMove = this.onMouseMove.bind(this);\n\n /**\n * Stores data for the ad playhead tracker.\n */\n this.adPlayheadTracker = {\n 'currentTime': 0,\n 'duration': 0,\n 'isPod': false,\n 'adPosition': 0,\n 'totalAds': 0\n };\n\n /**\n * Used to prefix videojs ima controls.\n */\n this.controlPrefix = this.controller.getPlayerId() + '_';\n\n /**\n * Boolean flag to show or hide the ad countdown timer.\n */\n this.showCountdown = true;\n if (this.controller.getSettings().showCountdown === false) {\n this.showCountdown = false;\n }\n\n this.createAdContainer();\n};\n\n/**\n * Creates the ad container.\n */\nAdUi.prototype.createAdContainer = function () {\n this.assignControlAttributes(this.adContainerDiv, 'ima-ad-container');\n this.adContainerDiv.style.position = 'absolute';\n this.adContainerDiv.style.zIndex = 1111;\n this.adContainerDiv.addEventListener('mouseenter', this.showAdControls.bind(this), false);\n this.adContainerDiv.addEventListener('mouseleave', this.hideAdControls.bind(this), false);\n this.createControls();\n this.controller.injectAdContainerDiv(this.adContainerDiv);\n};\n\n/**\n * Create the controls.\n */\nAdUi.prototype.createControls = function () {\n this.assignControlAttributes(this.controlsDiv, 'ima-controls-div');\n this.controlsDiv.style.width = '100%';\n\n this.assignControlAttributes(this.countdownDiv, 'ima-countdown-div');\n this.countdownDiv.innerHTML = this.controller.getSettings().adLabel;\n this.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';\n\n this.assignControlAttributes(this.seekBarDiv, 'ima-seek-bar-div');\n this.seekBarDiv.style.width = '100%';\n\n this.assignControlAttributes(this.progressDiv, 'ima-progress-div');\n\n this.assignControlAttributes(this.playPauseDiv, 'ima-play-pause-div');\n this.addClass(this.playPauseDiv, 'ima-playing');\n this.playPauseDiv.addEventListener('click', this.onAdPlayPauseClick.bind(this), false);\n\n this.assignControlAttributes(this.muteDiv, 'ima-mute-div');\n this.addClass(this.muteDiv, 'ima-non-muted');\n this.muteDiv.addEventListener('click', this.onAdMuteClick.bind(this), false);\n\n this.assignControlAttributes(this.sliderDiv, 'ima-slider-div');\n this.sliderDiv.addEventListener('mousedown', this.onAdVolumeSliderMouseDown.bind(this), false);\n\n // Hide volume slider controls on iOS as they aren't supported.\n if (this.controller.getIsIos()) {\n this.sliderDiv.style.display = 'none';\n }\n\n this.assignControlAttributes(this.sliderLevelDiv, 'ima-slider-level-div');\n\n this.assignControlAttributes(this.fullscreenDiv, 'ima-fullscreen-div');\n this.addClass(this.fullscreenDiv, 'ima-non-fullscreen');\n this.fullscreenDiv.addEventListener('click', this.onAdFullscreenClick.bind(this), false);\n\n this.adContainerDiv.appendChild(this.controlsDiv);\n this.controlsDiv.appendChild(this.countdownDiv);\n this.controlsDiv.appendChild(this.seekBarDiv);\n this.controlsDiv.appendChild(this.playPauseDiv);\n this.controlsDiv.appendChild(this.muteDiv);\n this.controlsDiv.appendChild(this.sliderDiv);\n this.controlsDiv.appendChild(this.fullscreenDiv);\n this.seekBarDiv.appendChild(this.progressDiv);\n this.sliderDiv.appendChild(this.sliderLevelDiv);\n};\n\n/**\n * Listener for clicks on the play/pause button during ad playback.\n */\nAdUi.prototype.onAdPlayPauseClick = function () {\n this.controller.onAdPlayPauseClick();\n};\n\n/**\n * Listener for clicks on the play/pause button during ad playback.\n */\nAdUi.prototype.onAdMuteClick = function () {\n this.controller.onAdMuteClick();\n};\n\n/**\n * Listener for clicks on the fullscreen button during ad playback.\n */\nAdUi.prototype.onAdFullscreenClick = function () {\n this.controller.toggleFullscreen();\n};\n\n/**\n * Show pause and hide play button\n */\nAdUi.prototype.onAdsPaused = function () {\n this.addClass(this.playPauseDiv, 'ima-paused');\n this.removeClass(this.playPauseDiv, 'ima-playing');\n this.showAdControls();\n};\n\n/**\n * Show pause and hide play button\n */\nAdUi.prototype.onAdsResumed = function () {\n this.onAdsPlaying();\n this.showAdControls();\n};\n\n/**\n * Show play and hide pause button\n */\nAdUi.prototype.onAdsPlaying = function () {\n this.addClass(this.playPauseDiv, 'ima-playing');\n this.removeClass(this.playPauseDiv, 'ima-paused');\n};\n\n/**\n * Takes data from the controller to update the UI.\n *\n * @param {number} currentTime Current time of the ad.\n * @param {number} remainingTime Remaining time of the ad.\n * @param {number} duration Duration of the ad.\n * @param {number} adPosition Index of the ad in the pod.\n * @param {number} totalAds Total number of ads in the pod.\n */\nAdUi.prototype.updateAdUi = function (currentTime, remainingTime, duration, adPosition, totalAds) {\n // Update countdown timer data\n var remainingMinutes = Math.floor(remainingTime / 60);\n var remainingSeconds = Math.floor(remainingTime % 60);\n if (remainingSeconds.toString().length < 2) {\n remainingSeconds = '0' + remainingSeconds;\n }\n var podCount = ': ';\n if (totalAds > 1) {\n podCount = ' (' + adPosition + ' ' + this.controller.getSettings().adLabelNofN + ' ' + totalAds + '): ';\n }\n this.countdownDiv.innerHTML = this.controller.getSettings().adLabel + podCount + remainingMinutes + ':' + remainingSeconds;\n\n // Update UI\n var playProgressRatio = currentTime / duration;\n var playProgressPercent = playProgressRatio * 100;\n this.progressDiv.style.width = playProgressPercent + '%';\n};\n\n/**\n * Handles UI changes when the ad is unmuted.\n */\nAdUi.prototype.unmute = function () {\n this.addClass(this.muteDiv, 'ima-non-muted');\n this.removeClass(this.muteDiv, 'ima-muted');\n this.sliderLevelDiv.style.width = this.controller.getPlayerVolume() * 100 + '%';\n};\n\n/**\n * Handles UI changes when the ad is muted.\n */\nAdUi.prototype.mute = function () {\n this.addClass(this.muteDiv, 'ima-muted');\n this.removeClass(this.muteDiv, 'ima-non-muted');\n this.sliderLevelDiv.style.width = '0%';\n};\n\n/*\n * Listener for mouse down events during ad playback. Used for volume.\n */\nAdUi.prototype.onAdVolumeSliderMouseDown = function () {\n document.addEventListener('mouseup', this.boundOnMouseUp, false);\n document.addEventListener('mousemove', this.boundOnMouseMove, false);\n};\n\n/*\n * Mouse movement listener used for volume slider.\n */\nAdUi.prototype.onMouseMove = function (event) {\n this.changeVolume(event);\n};\n\n/*\n * Mouse release listener used for volume slider.\n */\nAdUi.prototype.onMouseUp = function (event) {\n this.changeVolume(event);\n document.removeEventListener('mouseup', this.boundOnMouseUp);\n document.removeEventListener('mousemove', this.boundOnMouseMove);\n};\n\n/*\n * Utility function to set volume and associated UI\n */\nAdUi.prototype.changeVolume = function (event) {\n var percent = (event.clientX - this.sliderDiv.getBoundingClientRect().left) / this.sliderDiv.offsetWidth;\n percent *= 100;\n // Bounds value 0-100 if mouse is outside slider region.\n percent = Math.min(Math.max(percent, 0), 100);\n this.sliderLevelDiv.style.width = percent + '%';\n if (this.percent == 0) {\n this.addClass(this.muteDiv, 'ima-muted');\n this.removeClass(this.muteDiv, 'ima-non-muted');\n } else {\n this.addClass(this.muteDiv, 'ima-non-muted');\n this.removeClass(this.muteDiv, 'ima-muted');\n }\n this.controller.setVolume(percent / 100); // 0-1\n};\n\n/**\n * Show the ad container.\n */\nAdUi.prototype.showAdContainer = function () {\n this.adContainerDiv.style.display = 'block';\n};\n\n/**\n * Handles ad errors.\n */\nAdUi.prototype.onAdError = function () {\n this.adContainerDiv.style.display = 'none';\n};\n\n/**\n * Handles ad break starting.\n *\n * @param {Object} adEvent The event fired by the IMA SDK.\n */\nAdUi.prototype.onAdBreakStart = function (adEvent) {\n this.adContainerDiv.style.display = 'block';\n\n var contentType = adEvent.getAd().getContentType();\n if (contentType === 'application/javascript' && !this.controller.getSettings().showControlsForJSAds) {\n this.controlsDiv.style.display = 'none';\n } else {\n this.controlsDiv.style.display = 'block';\n }\n this.onAdsPlaying();\n // Start with the ad controls minimized.\n this.hideAdControls();\n};\n\n/**\n * Handles ad break ending.\n */\nAdUi.prototype.onAdBreakEnd = function () {\n var currentAd = this.controller.getCurrentAd();\n if (currentAd == null || // hide for post-roll only playlist\n currentAd.isLinear()) {\n // don't hide for non-linear ads\n this.adContainerDiv.style.display = 'none';\n }\n this.controlsDiv.style.display = 'none';\n this.countdownDiv.innerHTML = '';\n};\n\n/**\n * Handles when all ads have finished playing.\n */\nAdUi.prototype.onAllAdsCompleted = function () {\n this.adContainerDiv.style.display = 'none';\n};\n\n/**\n * Handles when a linear ad starts.\n */\nAdUi.prototype.onLinearAdStart = function () {\n // Don't bump container when controls are shown\n this.removeClass(this.adContainerDiv, 'bumpable-ima-ad-container');\n};\n\n/**\n * Handles when a non-linear ad starts.\n */\nAdUi.prototype.onNonLinearAdLoad = function () {\n // For non-linear ads that show after a linear ad. For linear ads, we show the\n // ad container in onAdBreakStart to prevent blinking in pods.\n this.adContainerDiv.style.display = 'block';\n // Bump container when controls are shown\n this.addClass(this.adContainerDiv, 'bumpable-ima-ad-container');\n};\n\nAdUi.prototype.onPlayerEnterFullscreen = function () {\n this.addClass(this.fullscreenDiv, 'ima-fullscreen');\n this.removeClass(this.fullscreenDiv, 'ima-non-fullscreen');\n};\n\nAdUi.prototype.onPlayerExitFullscreen = function () {\n this.addClass(this.fullscreenDiv, 'ima-non-fullscreen');\n this.removeClass(this.fullscreenDiv, 'ima-fullscreen');\n};\n\n/**\n * Called when the player volume changes.\n *\n * @param {number} volume The new player volume.\n */\nAdUi.prototype.onPlayerVolumeChanged = function (volume) {\n if (volume == 0) {\n this.addClass(this.muteDiv, 'ima-muted');\n this.removeClass(this.muteDiv, 'ima-non-muted');\n this.sliderLevelDiv.style.width = '0%';\n } else {\n this.addClass(this.muteDiv, 'ima-non-muted');\n this.removeClass(this.muteDiv, 'ima-muted');\n this.sliderLevelDiv.style.width = volume * 100 + '%';\n }\n};\n\n/**\n * Shows ad controls on mouseover.\n */\nAdUi.prototype.showAdControls = function () {\n this.addClass(this.controlsDiv, 'ima-controls-div-showing');\n this.playPauseDiv.style.display = 'block';\n this.muteDiv.style.display = 'block';\n this.fullscreenDiv.style.display = 'block';\n // Don't show on iOS.\n if (!this.controller.getIsIos()) {\n this.sliderDiv.style.display = 'block';\n }\n};\n\n/**\n * Hide the ad controls.\n */\nAdUi.prototype.hideAdControls = function () {\n this.removeClass(this.controlsDiv, 'ima-controls-div-showing');\n this.playPauseDiv.style.display = 'none';\n this.muteDiv.style.display = 'none';\n this.sliderDiv.style.display = 'none';\n this.fullscreenDiv.style.display = 'none';\n};\n\n/**\n * Assigns the unique id and class names to the given element as well as the\n * style class.\n * @param {HTMLElement} element Element that needs the controlName assigned.\n * @param {string} controlName Control name to assign.\n */\nAdUi.prototype.assignControlAttributes = function (element, controlName) {\n element.id = this.controlPrefix + controlName;\n element.className = this.controlPrefix + controlName + ' ' + controlName;\n};\n\n/**\n * Returns a regular expression to test a string for the given className.\n *\n * @param {string} className The name of the class.\n * @return {RegExp} The regular expression used to test for that class.\n */\nAdUi.prototype.getClassRegexp = function (className) {\n // Matches on\n // (beginning of string OR NOT word char)\n // classname\n // (negative lookahead word char OR end of string)\n return new RegExp('(^|[^A-Za-z-])' + className + '((?![A-Za-z-])|$)', 'gi');\n};\n\n/**\n * Returns whether or not the provided element has the provied class in its\n * className.\n * @param {HTMLElement} element Element to tes.t\n * @param {string} className Class to look for.\n * @return {boolean} True if element has className in class list. False\n * otherwise.\n */\nAdUi.prototype.elementHasClass = function (element, className) {\n var classRegexp = this.getClassRegexp(className);\n return classRegexp.test(element.className);\n};\n\n/**\n * Adds a class to the given element if it doesn't already have the class\n * @param {HTMLElement} element Element to which the class will be added.\n * @param {string} classToAdd Class to add.\n */\nAdUi.prototype.addClass = function (element, classToAdd) {\n element.className = element.className.trim() + ' ' + classToAdd;\n};\n\n/**\n * Removes a class from the given element if it has the given class\n *\n * @param {HTMLElement} element Element from which the class will be removed.\n * @param {string} classToRemove Class to remove.\n */\nAdUi.prototype.removeClass = function (element, classToRemove) {\n var classRegexp = this.getClassRegexp(classToRemove);\n element.className = element.className.trim().replace(classRegexp, '');\n};\n\n/**\n * @return {HTMLElement} The div for the ad container.\n */\nAdUi.prototype.getAdContainerDiv = function () {\n return this.adContainerDiv;\n};\n\n/**\n * Changes the flag to show or hide the ad countdown timer.\n *\n * @param {boolean} showCountdownIn Show or hide the countdown timer.\n */\nAdUi.prototype.setShowCountdown = function (showCountdownIn) {\n this.showCountdown = showCountdownIn;\n this.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';\n};\n\nvar name = \"videojs-ima\";\nvar version = \"1.5.1\";\nvar license = \"Apache-2.0\";\nvar main = \"./dist/videojs.ima.js\";\nvar author = { \"name\": \"Google Inc.\" };\nvar engines = { \"node\": \">=0.8.0\" };\nvar scripts = { \"contBuild\": \"watch 'npm run rollup:max' src\", \"predevServer\": \"echo \\\"Starting up server on localhost:8000.\\\"\", \"devServer\": \"forever start ./node_modules/http-server/bin/http-server -p 8000 && npm run contBuild\", \"postdevServer\": \"forever stop ./node_modules/http-server/bin/http-server\", \"lint\": \"eslint \\\"src/*.js\\\"\", \"rollup\": \"npm-run-all rollup:*\", \"rollup:max\": \"rollup -c configs/rollup.config.js\", \"rollup:min\": \"rollup -c configs/rollup.config.min.js\", \"pretest\": \"npm run rollup\", \"start\": \"npm run devServer\", \"test\": \"npm-run-all test:*\", \"test:vjs5\": \"npm install video.js@5.19.2 --no-save && npm-run-all -p -r testServer webdriver\", \"test:vjs6\": \"npm install video.js@6 --no-save && npm-run-all -p -r testServer webdriver\", \"testServer\": \"http-server --cors -p 8000 --silent\", \"preversion\": \"node scripts/preversion.js && npm run lint && npm test\", \"version\": \"node scripts/version.js\", \"postversion\": \"node scripts/postversion.js\", \"webdriver\": \"mocha test/webdriver/*.js --no-timeouts\" };\nvar repository = { \"type\": \"git\", \"url\": \"https://github.com/googleads/videojs-ima\" };\nvar files = [\"CHANGELOG.md\", \"LICENSE\", \"README.md\", \"dist/\", \"src/\"];\nvar dependencies = { \"can-autoplay\": \"^3.0.0\", \"video.js\": \"^5.19.2 || ^6\", \"videojs-contrib-ads\": \"^6\" };\nvar devDependencies = { \"babel-core\": \"^6.26.0\", \"babel-preset-env\": \"^1.6.1\", \"child_process\": \"^1.0.2\", \"chromedriver\": \"^2.35.0\", \"conventional-changelog-cli\": \"^1.3.5\", \"conventional-changelog-videojs\": \"^3.0.0\", \"eslint\": \"^4.11.0\", \"eslint-config-google\": \"^0.9.1\", \"eslint-plugin-jsdoc\": \"^3.2.0\", \"forever\": \"^0.15.3\", \"geckodriver\": \"^1.10.0\", \"http-server\": \"^0.10.0\", \"mocha\": \"^4.0.1\", \"npm-run-all\": \"^4.1.2\", \"path\": \"^0.12.7\", \"rimraf\": \"^2.6.2\", \"rollup\": \"^0.51.8\", \"rollup-plugin-babel\": \"^3.0.3\", \"rollup-plugin-copy\": \"^0.2.3\", \"rollup-plugin-json\": \"^2.3.0\", \"rollup-plugin-uglify\": \"^2.0.1\", \"selenium-webdriver\": \"^3.6.0\", \"uglify-es\": \"^3.1.10\", \"watch\": \"^1.0.2\" };\nvar keywords = [\"videojs\", \"videojs-plugin\"];\nvar pkg = {\n\tname: name,\n\tversion: version,\n\tlicense: license,\n\tmain: main,\n\tauthor: author,\n\tengines: engines,\n\tscripts: scripts,\n\trepository: repository,\n\tfiles: files,\n\tdependencies: dependencies,\n\tdevDependencies: devDependencies,\n\tkeywords: keywords\n};\n\n/**\n * Copyright 2017 Google Inc.\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 * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * Implementation of the IMA SDK for the plugin.\n *\n * @param {Object} controller Reference to the parent controller.\n *\n * @constructor\n * @struct\n * @final\n */\nvar SdkImpl = function SdkImpl(controller) {\n /**\n * Plugin controller.\n */\n this.controller = controller;\n\n /**\n * IMA SDK AdDisplayContainer.\n */\n this.adDisplayContainer = null;\n\n /**\n * True if the AdDisplayContainer has been initialized. False otherwise.\n */\n this.adDisplayContainerInitialized = false;\n\n /**\n * IMA SDK AdsLoader\n */\n this.adsLoader = null;\n\n /**\n * IMA SDK AdsManager\n */\n this.adsManager = null;\n\n /**\n * IMA SDK AdsRenderingSettings.\n */\n this.adsRenderingSettings = null;\n\n /**\n * Ad tag URL. Should return VAST, VMAP, or ad rules.\n */\n this.adTagUrl = null;\n\n /**\n * VAST, VMAP, or ad rules response. Used in lieu of fetching a response\n * from an ad tag URL.\n */\n this.adsResponse = null;\n\n /**\n * Current IMA SDK Ad.\n */\n this.currentAd = null;\n\n /**\n * Timer used to track ad progress.\n */\n this.adTrackingTimer = null;\n\n /**\n * True if ALL_ADS_COMPLETED has fired, false until then.\n */\n this.allAdsCompleted = false;\n\n /**\n * True if ads are currently displayed, false otherwise.\n * True regardless of ad pause state if an ad is currently being displayed.\n */\n this.adsActive = false;\n\n /**\n * True if ad is currently playing, false if ad is paused or ads are not\n * currently displayed.\n */\n this.adPlaying = false;\n\n /**\n * True if the ad is muted, false otherwise.\n */\n this.adMuted = false;\n\n /**\n * Listener to be called to trigger manual ad break playback.\n */\n this.adBreakReadyListener = undefined;\n\n /**\n * Tracks whether or not we have already called adsLoader.contentComplete().\n */\n this.contentCompleteCalled = false;\n\n /**\n * Stores the dimensions for the ads manager.\n */\n this.adsManagerDimensions = {\n width: 0,\n height: 0\n };\n\n /**\n * Boolean flag to enable manual ad break playback.\n */\n this.autoPlayAdBreaks = true;\n if (this.controller.getSettings().autoPlayAdBreaks === false) {\n this.autoPlayAdBreaks = false;\n }\n\n // Set SDK settings from plugin settings.\n if (this.controller.getSettings().locale) {\n /* eslint no-undef: 'error' */\n /* global google */\n google.ima.settings.setLocale(this.controller.getSettings().locale);\n }\n if (this.controller.getSettings().disableFlashAds) {\n google.ima.settings.setDisableFlashAds(this.controller.getSettings().disableFlashAds);\n }\n if (this.controller.getSettings().disableCustomPlaybackForIOS10Plus) {\n google.ima.settings.setDisableCustomPlaybackForIOS10Plus(this.controller.getSettings().disableCustomPlaybackForIOS10Plus);\n }\n};\n\n/**\n * Creates and initializes the IMA SDK objects.\n */\nSdkImpl.prototype.initAdObjects = function () {\n this.adDisplayContainer = new google.ima.AdDisplayContainer(this.controller.getAdContainerDiv(), this.controller.getContentPlayer());\n\n this.adsLoader = new google.ima.AdsLoader(this.adDisplayContainer);\n\n this.adsLoader.getSettings().setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.ENABLED);\n if (this.controller.getSettings().vpaidAllowed == false) {\n this.adsLoader.getSettings().setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.DISABLED);\n }\n if (this.controller.getSettings().vpaidMode) {\n this.adsLoader.getSettings().setVpaidMode(this.controller.getSettings().vpaidMode);\n }\n\n if (this.controller.getSettings().locale) {\n this.adsLoader.getSettings().setLocale(this.controller.getSettings().locale);\n }\n\n if (this.controller.getSettings().numRedirects) {\n this.adsLoader.getSettings().setNumRedirects(this.controller.getSettings().numRedirects);\n }\n\n this.adsLoader.getSettings().setPlayerType('videojs-ima');\n this.adsLoader.getSettings().setPlayerVersion(pkg.version);\n this.adsLoader.getSettings().setAutoPlayAdBreaks(this.autoPlayAdBreaks);\n\n this.adsLoader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, this.onAdsManagerLoaded.bind(this), false);\n this.adsLoader.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, this.onAdsLoaderError.bind(this), false);\n};\n\n/**\n * Creates the AdsRequest and request ads through the AdsLoader.\n */\nSdkImpl.prototype.requestAds = function () {\n var adsRequest = new google.ima.AdsRequest();\n if (this.controller.getSettings().adTagUrl) {\n adsRequest.adTagUrl = this.controller.getSettings().adTagUrl;\n } else {\n adsRequest.adsResponse = this.controller.getSettings().adsResponse;\n }\n if (this.controller.getSettings().forceNonLinearFullSlot) {\n adsRequest.forceNonLinearFullSlot = true;\n }\n\n if (this.controller.getSettings().vastLoadTimeout) {\n adsRequest.vastLoadTimeout = this.controller.getSettings().vastLoadTimeout;\n }\n\n adsRequest.linearAdSlotWidth = this.controller.getPlayerWidth();\n adsRequest.linearAdSlotHeight = this.controller.getPlayerHeight();\n adsRequest.nonLinearAdSlotWidth = this.controller.getSettings().nonLinearWidth || this.controller.getPlayerWidth();\n adsRequest.nonLinearAdSlotHeight = this.controller.getSettings().nonLinearHeight || this.controller.getPlayerHeight();\n adsRequest.setAdWillAutoPlay(this.controller.adsWillAutoplay());\n adsRequest.setAdWillPlayMuted(this.controller.adsWillPlayMuted());\n\n this.adsLoader.requestAds(adsRequest);\n this.controller.triggerPlayerEvent('ads-request', adsRequest);\n};\n\n/**\n * Listener for the ADS_MANAGER_LOADED event. Creates the AdsManager,\n * sets up event listeners, and triggers the 'adsready' event for\n * videojs-ads-contrib.\n *\n * @param {google.ima.AdsManagerLoadedEvent} adsManagerLoadedEvent Fired when\n * the AdsManager loads.\n */\nSdkImpl.prototype.onAdsManagerLoaded = function (adsManagerLoadedEvent) {\n this.createAdsRenderingSettings();\n\n this.adsManager = adsManagerLoadedEvent.getAdsManager(this.controller.getContentPlayheadTracker(), this.adsRenderingSettings);\n\n this.adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, this.onAdError.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.AD_BREAK_READY, this.onAdBreakReady.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, this.onContentPauseRequested.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, this.onContentResumeRequested.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.ALL_ADS_COMPLETED, this.onAllAdsCompleted.bind(this));\n\n this.adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, this.onAdLoaded.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, this.onAdStarted.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.CLICK, this.onAdPaused.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, this.onAdComplete.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.SKIPPED, this.onAdComplete.bind(this));\n\n if (this.controller.getIsMobile()) {\n // Show/hide controls on pause and resume (triggered by tap).\n this.adsManager.addEventListener(google.ima.AdEvent.Type.PAUSED, this.onAdPaused.bind(this));\n this.adsManager.addEventListener(google.ima.AdEvent.Type.RESUMED, this.onAdResumed.bind(this));\n }\n\n if (!this.autoPlayAdBreaks) {\n this.initAdsManager();\n }\n\n this.controller.onAdsReady();\n\n if (this.controller.getSettings().adsManagerLoadedCallback) {\n this.controller.getSettings().adsManagerLoadedCallback();\n }\n};\n\n/**\n * Listener for errors fired by the AdsLoader.\n * @param {google.ima.AdErrorEvent} event The error event thrown by the\n * AdsLoader. See\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdError.Type\n */\nSdkImpl.prototype.onAdsLoaderError = function (event) {\n window.console.warn('AdsLoader error: ' + event.getError());\n this.controller.onErrorLoadingAds(event);\n if (this.adsManager) {\n this.adsManager.destroy();\n }\n};\n\n/**\n * Initialize the ads manager.\n */\nSdkImpl.prototype.initAdsManager = function () {\n try {\n var initWidth = this.controller.getPlayerWidth();\n var initHeight = this.controller.getPlayerHeight();\n this.adsManagerDimensions.width = initWidth;\n this.adsManagerDimensions.height = initHeight;\n this.adsManager.init(initWidth, initHeight, google.ima.ViewMode.NORMAL);\n this.adsManager.setVolume(this.controller.getPlayerVolume());\n if (!this.adDisplayContainerInitialized) {\n this.adDisplayContainer.initialize();\n this.adDisplayContainer.initialized = true;\n }\n } catch (adError) {\n this.onAdError(adError);\n }\n};\n\n/**\n * Create AdsRenderingSettings for the IMA SDK.\n */\nSdkImpl.prototype.createAdsRenderingSettings = function () {\n this.adsRenderingSettings = new google.ima.AdsRenderingSettings();\n this.adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true;\n if (this.controller.getSettings().adsRenderingSettings) {\n for (var setting in this.controller.getSettings().adsRenderingSettings) {\n if (setting !== '') {\n this.adsRenderingSettings[setting] = this.controller.getSettings().adsRenderingSettings[setting];\n }\n }\n }\n};\n\n/**\n * Listener for errors thrown by the AdsManager.\n * @param {google.ima.AdErrorEvent} adErrorEvent The error event thrown by\n * the AdsManager.\n */\nSdkImpl.prototype.onAdError = function (adErrorEvent) {\n var errorMessage = adErrorEvent.getError !== undefined ? adErrorEvent.getError() : adErrorEvent.stack;\n window.console.warn('Ad error: ' + errorMessage);\n\n this.adsManager.destroy();\n this.controller.onAdError(adErrorEvent);\n\n // reset these so consumers don't think we are still in an ad break,\n // but reset them after any prior cleanup happens\n this.adsActive = false;\n this.adPlaying = false;\n};\n\n/**\n * Listener for AD_BREAK_READY. Passes event on to publisher's listener.\n * @param {google.ima.AdEvent} adEvent AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onAdBreakReady = function (adEvent) {\n this.adBreakReadyListener(adEvent);\n};\n\n/**\n * Pauses the content video and displays the ad container so ads can play.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onContentPauseRequested = function (adEvent) {\n this.adsActive = true;\n this.adPlaying = true;\n this.controller.onAdBreakStart(adEvent);\n};\n\n/**\n * Resumes content video and hides the ad container.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onContentResumeRequested = function (adEvent) {\n this.adsActive = false;\n this.adPlaying = false;\n this.controller.onAdBreakEnd();\n // Hide controls in case of future non-linear ads. They'll be unhidden in\n // content_pause_requested.\n};\n\n/**\n * Records that ads have completed and calls contentAndAdsEndedListeners\n * if content is also complete.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onAllAdsCompleted = function (adEvent) {\n this.allAdsCompleted = true;\n this.controller.onAllAdsCompleted();\n};\n\n/**\n * Starts the content video when a non-linear ad is loaded.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onAdLoaded = function (adEvent) {\n if (!adEvent.getAd().isLinear()) {\n this.controller.onNonLinearAdLoad();\n this.controller.playContent();\n }\n};\n\n/**\n * Starts the interval timer to check the current ad time when an ad starts\n * playing.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onAdStarted = function (adEvent) {\n this.currentAd = adEvent.getAd();\n if (this.currentAd.isLinear()) {\n this.adTrackingTimer = setInterval(this.onAdPlayheadTrackerInterval.bind(this), 250);\n this.controller.onLinearAdStart();\n } else {\n this.controller.onNonLinearAdStart();\n }\n};\n\n/**\n * Handles an ad click. Puts the player UI in a paused state.\n */\nSdkImpl.prototype.onAdPaused = function () {\n this.controller.onAdsPaused();\n};\n\n/**\n * Syncs controls when an ad resumes.\n * @param {google.ima.AdEvent} adEvent The AdEvent thrown by the AdsManager.\n */\nSdkImpl.prototype.onAdResumed = function (adEvent) {\n this.controller.onAdsResumed();\n};\n\n/**\n * Clears the interval timer for current ad time when an ad completes.\n */\nSdkImpl.prototype.onAdComplete = function () {\n if (this.currentAd.isLinear()) {\n clearInterval(this.adTrackingTimer);\n }\n};\n\n/**\n * Gets the current time and duration of the ad and calls the method to\n * update the ad UI.\n */\nSdkImpl.prototype.onAdPlayheadTrackerInterval = function () {\n var remainingTime = this.adsManager.getRemainingTime();\n var duration = this.currentAd.getDuration();\n var currentTime = duration - remainingTime;\n currentTime = currentTime > 0 ? currentTime : 0;\n var totalAds = 0;\n var adPosition = void 0;\n if (this.currentAd.getAdPodInfo()) {\n adPosition = this.currentAd.getAdPodInfo().getAdPosition();\n totalAds = this.currentAd.getAdPodInfo().getTotalAds();\n }\n\n this.controller.onAdPlayheadUpdated(currentTime, remainingTime, duration, adPosition, totalAds);\n};\n\n/**\n * Called by the player wrapper when content completes.\n */\nSdkImpl.prototype.onContentComplete = function () {\n if (this.adsLoader) {\n this.adsLoader.contentComplete();\n this.contentCompleteCalled = true;\n }\n\n if (this.adsManager && this.adsManager.getCuePoints() && !this.adsManager.getCuePoints().includes(-1)) {\n this.controller.onNoPostroll();\n }\n\n if (this.allAdsCompleted) {\n this.controller.onContentAndAdsCompleted();\n }\n};\n\n/**\n * Called when the player is disposed.\n */\nSdkImpl.prototype.onPlayerDisposed = function () {\n if (this.adTrackingTimer) {\n clearInterval(this.adTrackingTimer);\n }\n if (this.adsManager) {\n this.adsManager.destroy();\n this.adsManager = null;\n }\n};\n\nSdkImpl.prototype.onPlayerReadyForPreroll = function () {\n if (this.autoPlayAdBreaks) {\n this.initAdsManager();\n try {\n this.controller.showAdContainer();\n // Sync ad volume with content volume.\n this.adsManager.setVolume(this.controller.getPlayerVolume());\n this.adsManager.start();\n } catch (adError) {\n this.onAdError(adError);\n }\n }\n};\n\nSdkImpl.prototype.onPlayerReady = function () {\n this.initAdObjects();\n\n if (this.controller.getSettings().adTagUrl || this.controller.getSettings().adsResponse) {\n this.requestAds();\n }\n};\n\nSdkImpl.prototype.onPlayerEnterFullscreen = function () {\n if (this.adsManager) {\n this.adsManager.resize(window.screen.width, window.screen.height, google.ima.ViewMode.FULLSCREEN);\n }\n};\n\nSdkImpl.prototype.onPlayerExitFullscreen = function () {\n if (this.adsManager) {\n this.adsManager.resize(this.controller.getPlayerWidth(), this.controller.getPlayerHeight(), google.ima.ViewMode.NORMAL);\n }\n};\n\n/**\n * Called when the player volume changes.\n *\n * @param {number} volume The new player volume.\n */\nSdkImpl.prototype.onPlayerVolumeChanged = function (volume) {\n if (this.adsManager) {\n this.adsManager.setVolume(volume);\n }\n\n if (volume == 0) {\n this.adMuted = true;\n } else {\n this.adMuted = false;\n }\n};\n\n/**\n * Called when the player wrapper detects that the player has been resized.\n *\n * @param {number} width The post-resize width of the player.\n * @param {number} height The post-resize height of the player.\n */\nSdkImpl.prototype.onPlayerResize = function (width, height) {\n if (this.adsManager) {\n this.adsManagerDimensions.width = width;\n this.adsManagerDimensions.height = height;\n /* global google */\n /* eslint no-undef: 'error' */\n this.adsManager.resize(width, height, google.ima.ViewMode.NORMAL);\n }\n};\n\n/**\n * @return {Object} The current ad.\n */\nSdkImpl.prototype.getCurrentAd = function () {\n return this.currentAd;\n};\n\n/**\n * Listener JSDoc for ESLint. This listener can be passed to\n * setAdBreakReadyListener.\n * @callback listener\n */\n\n/**\n * Sets the listener to be called to trigger manual ad break playback.\n * @param {listener} listener The listener to be called to trigger manual ad\n * break playback.\n */\nSdkImpl.prototype.setAdBreakReadyListener = function (listener) {\n this.adBreakReadyListener = listener;\n};\n\n/**\n * @return {boolean} True if an ad is currently playing. False otherwise.\n */\nSdkImpl.prototype.isAdPlaying = function () {\n return this.adPlaying;\n};\n\n/**\n * @return {boolean} True if an ad is currently playing. False otherwise.\n */\nSdkImpl.prototype.isAdMuted = function () {\n return this.adMuted;\n};\n\n/**\n * Pause ads.\n */\nSdkImpl.prototype.pauseAds = function () {\n this.adsManager.pause();\n this.adPlaying = false;\n};\n\n/**\n * Resume ads.\n */\nSdkImpl.prototype.resumeAds = function () {\n this.adsManager.resume();\n this.adPlaying = true;\n};\n\n/**\n * Unmute ads.\n */\nSdkImpl.prototype.unmute = function () {\n this.adsManager.setVolume(1);\n this.adMuted = false;\n};\n\n/**\n * Mute ads.\n */\nSdkImpl.prototype.mute = function () {\n this.adsManager.setVolume(0);\n this.adMuted = true;\n};\n\n/**\n * Set the volume of the ads. 0-1.\n *\n * @param {number} volume The new volume.\n */\nSdkImpl.prototype.setVolume = function (volume) {\n this.adsManager.setVolume(volume);\n if (volume == 0) {\n this.adMuted = true;\n } else {\n this.adMuted = false;\n }\n};\n\n/**\n * Initializes the AdDisplayContainer. On mobile, this must be done as a\n * result of user action.\n */\nSdkImpl.prototype.initializeAdDisplayContainer = function () {\n if (this.adDisplayContainer) {\n this.adDisplayContainerInitialized = true;\n this.adDisplayContainer.initialize();\n }\n};\n\n/**\n * Called by publishers in manual ad break playback mode to start an ad\n * break.\n */\nSdkImpl.prototype.playAdBreak = function () {\n if (!this.autoPlayAdBreaks) {\n this.controller.showAdContainer();\n // Sync ad volume with content volume.\n this.adsManager.setVolume(this.controller.getPlayerVolume());\n this.adsManager.start();\n }\n};\n\n/**\n * Callback JSDoc for ESLint. This callback can be passed to addEventListener.\n * @callback callback\n */\n\n/**\n * Ads an EventListener to the AdsManager. For a list of available events,\n * see\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdEvent.Type\n * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to\n * listen.\n * @param {callback} callback The method to call when the event is fired.\n */\nSdkImpl.prototype.addEventListener = function (event, callback) {\n if (this.adsManager) {\n this.adsManager.addEventListener(event, callback);\n }\n};\n\n/**\n * Returns the instance of the AdsManager.\n * @return {google.ima.AdsManager} The AdsManager being used by the plugin.\n */\nSdkImpl.prototype.getAdsManager = function () {\n return this.adsManager;\n};\n\n/**\n * Reset the SDK implementation.\n */\nSdkImpl.prototype.reset = function () {\n this.adsActive = false;\n this.adPlaying = false;\n if (this.adTrackingTimer) {\n // If this is called while an ad is playing, stop trying to get that\n // ad's current time.\n clearInterval(this.adTrackingTimer);\n }\n if (this.adsManager) {\n this.adsManager.destroy();\n this.adsManager = null;\n }\n if (this.adsLoader && !this.contentCompleteCalled) {\n this.adsLoader.contentComplete();\n }\n this.contentCompleteCalled = false;\n this.allAdsCompleted = false;\n};\n\n/**\n * Copyright 2017 Google Inc.\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 * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n/**\n * The grand coordinator of the plugin. Facilitates communication between all\n * other plugin classes.\n *\n * @param {Object} player Instance of the video.js player.\n * @param {Object} options Options provided by the implementation.\n * @constructor\n * @struct\n * @final\n */\nvar Controller = function Controller(player, options) {\n /**\n * Stores user-provided settings.\n * @type {Object}\n */\n this.settings = {};\n\n /**\n * Content and ads ended listeners passed by the publisher to the plugin.\n * These will be called when the plugin detects that content *and all\n * ads* have completed. This differs from the contentEndedListeners in that\n * contentEndedListeners will fire between content ending and a post-roll\n * playing, whereas the contentAndAdsEndedListeners will fire after the\n * post-roll completes.\n */\n this.contentAndAdsEndedListeners = [];\n\n /**\n * Whether or not we are running on a mobile platform.\n */\n this.isMobile = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/Android/i);\n\n /**\n * Whether or not we are running on an iOS platform.\n */\n this.isIos = navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i);\n\n this.initWithSettings(options);\n\n /**\n * Stores contrib-ads default settings.\n */\n var contribAdsDefaults = {\n debug: this.settings.debug,\n timeout: this.settings.timeout,\n prerollTimeout: this.settings.prerollTimeout\n };\n var adsPluginSettings = this.extend({}, contribAdsDefaults, options.contribAdsSettings || {});\n\n this.playerWrapper = new PlayerWrapper(player, adsPluginSettings, this);\n this.adUi = new AdUi(this);\n this.sdkImpl = new SdkImpl(this);\n};\n\nController.IMA_DEFAULTS = {\n debug: false,\n timeout: 5000,\n prerollTimeout: 1000,\n adLabel: 'Advertisement',\n adLabelNofN: 'of',\n showControlsForJSAds: true\n};\n\n/**\n * Extends the settings to include user-provided settings.\n *\n * @param {Object} options Options to be used in initialization.\n */\nController.prototype.initWithSettings = function (options) {\n this.settings = this.extend({}, Controller.IMA_DEFAULTS, options || {});\n\n this.warnAboutDeprecatedSettings();\n\n // Default showing countdown timer to true.\n this.showCountdown = true;\n if (this.settings.showCountdown === false) {\n this.showCountdown = false;\n }\n};\n\n/**\n * Logs console warnings when deprecated settings are used.\n */\nController.prototype.warnAboutDeprecatedSettings = function () {\n var _this = this;\n\n var deprecatedSettings = ['adWillAutoplay', 'adsWillAutoplay', 'adWillPlayMuted', 'adsWillPlayMuted'];\n deprecatedSettings.forEach(function (setting) {\n if (_this.settings[setting] !== undefined) {\n console.warn('WARNING: videojs.ima setting ' + setting + ' is deprecated');\n }\n });\n};\n\n/**\n * Return the settings object.\n *\n * @return {Object} The settings object.\n */\nController.prototype.getSettings = function () {\n return this.settings;\n};\n\n/**\n * Return whether or not we're in a mobile environment.\n *\n * @return {boolean} True if running on mobile, false otherwise.\n */\nController.prototype.getIsMobile = function () {\n return this.isMobile;\n};\n\n/**\n * Return whether or not we're in an iOS environment.\n *\n * @return {boolean} True if running on iOS, false otherwise.\n */\nController.prototype.getIsIos = function () {\n return this.isIos;\n};\n\n/**\n * Inject the ad container div into the DOM.\n *\n * @param{HTMLElement} adContainerDiv The ad container div.\n */\nController.prototype.injectAdContainerDiv = function (adContainerDiv) {\n this.playerWrapper.injectAdContainerDiv(adContainerDiv);\n};\n\n/**\n * @return {HTMLElement} The div for the ad container.\n */\nController.prototype.getAdContainerDiv = function () {\n return this.adUi.getAdContainerDiv();\n};\n\n/**\n * @return {Object} The content player.\n */\nController.prototype.getContentPlayer = function () {\n return this.playerWrapper.getContentPlayer();\n};\n\n/**\n * Returns the content playhead tracker.\n *\n * @return {Object} The content playhead tracker.\n */\nController.prototype.getContentPlayheadTracker = function () {\n return this.playerWrapper.getContentPlayheadTracker();\n};\n\n/**\n * Requests ads.\n */\nController.prototype.requestAds = function () {\n this.sdkImpl.requestAds();\n};\n\n/**\n * Add or modify a setting.\n *\n * @param {string} key Key to modify\n * @param {Object} value Value to set at key.\n */\nController.prototype.setSetting = function (key, value) {\n this.settings[key] = value;\n};\n\n/**\n * Called when there is an error loading ads.\n *\n * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nController.prototype.onErrorLoadingAds = function (adErrorEvent) {\n this.adUi.onAdError();\n this.playerWrapper.onAdError(adErrorEvent);\n};\n\n/**\n * Called by the ad UI when the play/pause button is clicked.\n */\nController.prototype.onAdPlayPauseClick = function () {\n if (this.sdkImpl.isAdPlaying()) {\n this.adUi.onAdsPaused();\n this.sdkImpl.pauseAds();\n } else {\n this.adUi.onAdsPlaying();\n this.sdkImpl.resumeAds();\n }\n};\n\n/**\n * Called by the ad UI when the mute button is clicked.\n *\n */\nController.prototype.onAdMuteClick = function () {\n if (this.sdkImpl.isAdMuted()) {\n this.playerWrapper.unmute();\n this.adUi.unmute();\n this.sdkImpl.unmute();\n } else {\n this.playerWrapper.mute();\n this.adUi.mute();\n this.sdkImpl.mute();\n }\n};\n\n/**\n * Set the volume of the player and ads. 0-1.\n *\n * @param {number} volume The new volume.\n */\nController.prototype.setVolume = function (volume) {\n this.playerWrapper.setVolume(volume);\n this.sdkImpl.setVolume(volume);\n};\n\n/**\n * @return {number} The volume of the content player.\n */\nController.prototype.getPlayerVolume = function () {\n return this.playerWrapper.getVolume();\n};\n\n/**\n * Toggle fullscreen state.\n */\nController.prototype.toggleFullscreen = function () {\n this.playerWrapper.toggleFullscreen();\n};\n\n/**\n * Relays ad errors to the player wrapper.\n *\n * @param {Object} adErrorEvent The ad error event thrown by the IMA SDK.\n */\nController.prototype.onAdError = function (adErrorEvent) {\n this.adUi.onAdError();\n this.playerWrapper.onAdError(adErrorEvent);\n};\n\n/**\n * Handles ad break starting.\n *\n * @param {Object} adEvent The event fired by the IMA SDK.\n */\nController.prototype.onAdBreakStart = function (adEvent) {\n this.playerWrapper.onAdBreakStart();\n this.adUi.onAdBreakStart(adEvent);\n};\n\n/**\n * Show the ad container.\n */\nController.prototype.showAdContainer = function () {\n this.adUi.showAdContainer();\n};\n\n/**\n * Handles ad break ending.\n */\nController.prototype.onAdBreakEnd = function () {\n this.playerWrapper.onAdBreakEnd();\n this.adUi.onAdBreakEnd();\n};\n\n/**\n * Handles when all ads have finished playing.\n */\nController.prototype.onAllAdsCompleted = function () {\n this.adUi.onAllAdsCompleted();\n this.playerWrapper.onAllAdsCompleted();\n};\n\n/**\n * Handles the SDK firing an ad paused event.\n */\nController.prototype.onAdsPaused = function () {\n this.adUi.onAdsPaused();\n};\n\n/**\n * Handles the SDK firing an ad resumed event.\n */\nController.prototype.onAdsResumed = function () {\n this.adUi.onAdsResumed();\n};\n\n/**\n * Takes data from the sdk impl and passes it to the ad UI to update the UI.\n *\n * @param {number} currentTime Current time of the ad.\n * @param {number} remainingTime Remaining time of the ad.\n * @param {number} duration Duration of the ad.\n * @param {number} adPosition Index of the ad in the pod.\n * @param {number} totalAds Total number of ads in the pod.\n */\nController.prototype.onAdPlayheadUpdated = function (currentTime, remainingTime, duration, adPosition, totalAds) {\n this.adUi.updateAdUi(currentTime, remainingTime, duration, adPosition, totalAds);\n};\n\n/**\n * @return {Object} The current ad.\n */\nController.prototype.getCurrentAd = function () {\n return this.sdkImpl.getCurrentAd();\n};\n\n/**\n * Play content.\n */\nController.prototype.playContent = function () {\n this.playerWrapper.play();\n};\n\n/**\n * Handles when a linear ad starts.\n */\nController.prototype.onLinearAdStart = function () {\n this.adUi.onLinearAdStart();\n this.playerWrapper.onAdStart();\n};\n\n/**\n * Handles when a non-linear ad loads.\n */\nController.prototype.onNonLinearAdLoad = function () {\n this.adUi.onNonLinearAdLoad();\n};\n\n/**\n * Handles when a non-linear ad starts.\n */\nController.prototype.onNonLinearAdStart = function () {\n this.adUi.onNonLinearAdLoad();\n this.playerWrapper.onAdStart();\n};\n\n/**\n * Get the player width.\n *\n * @return {number} The width of the player.\n */\nController.prototype.getPlayerWidth = function () {\n return this.playerWrapper.getPlayerWidth();\n};\n\n/**\n * Get the player height.\n *\n * @return {number} The height of the player.\n */\nController.prototype.getPlayerHeight = function () {\n return this.playerWrapper.getPlayerHeight();\n};\n\n/**\n * Tells the player wrapper that ads are ready.\n */\nController.prototype.onAdsReady = function () {\n this.playerWrapper.onAdsReady();\n};\n\n/**\n * Called when the player wrapper detects that the player has been resized.\n *\n * @param {number} width The post-resize width of the player.\n * @param {number} height The post-resize height of the player.\n */\nController.prototype.onPlayerResize = function (width, height) {\n this.sdkImpl.onPlayerResize(width, height);\n};\n\n/**\n * Called by the player wrapper when content completes.\n */\nController.prototype.onContentComplete = function () {\n this.sdkImpl.onContentComplete();\n};\n\n/**\n * Called by the player wrapper when it's time to play a post-roll but we don't\n * have one to play.\n */\nController.prototype.onNoPostroll = function () {\n this.playerWrapper.onNoPostroll();\n};\n\n/**\n * Called when content and all ads have completed.\n */\nController.prototype.onContentAndAdsCompleted = function () {\n for (var index in this.contentAndAdsEndedListeners) {\n if (typeof this.contentAndAdsEndedListeners[index] === 'function') {\n this.contentAndAdsEndedListeners[index]();\n }\n }\n};\n\n/**\n * Called when the player is disposed.\n */\nController.prototype.onPlayerDisposed = function () {\n this.contentAndAdsEndedListeners = [];\n this.sdkImpl.onPlayerDisposed();\n};\n\n/**\n * Called when the player is ready to play a pre-roll.\n */\nController.prototype.onPlayerReadyForPreroll = function () {\n this.sdkImpl.onPlayerReadyForPreroll();\n};\n\n/**\n * Called when the player is ready.\n */\nController.prototype.onPlayerReady = function () {\n this.sdkImpl.onPlayerReady();\n};\n\n/**\n * Called when the player enters fullscreen.\n */\nController.prototype.onPlayerEnterFullscreen = function () {\n this.adUi.onPlayerEnterFullscreen();\n this.sdkImpl.onPlayerEnterFullscreen();\n};\n\n/**\n * Called when the player exits fullscreen.\n */\nController.prototype.onPlayerExitFullscreen = function () {\n this.adUi.onPlayerExitFullscreen();\n this.sdkImpl.onPlayerExitFullscreen();\n};\n\n/**\n * Called when the player volume changes.\n *\n * @param {number} volume The new player volume.\n */\nController.prototype.onPlayerVolumeChanged = function (volume) {\n this.adUi.onPlayerVolumeChanged(volume);\n this.sdkImpl.onPlayerVolumeChanged(volume);\n};\n\n/**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ad tag is\n * requested when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?string} adTag The ad tag to be requested when the content loads.\n * Leave blank to use the existing ad tag.\n * @param {?boolean} playOnLoad True to play the content once it has loaded,\n * false to only load the content but not start playback.\n */\nController.prototype.setContentWithAdTag = function (contentSrc, adTag, playOnLoad) {\n this.reset();\n this.settings.adTagUrl = adTag ? adTag : this.settings.adTagUrl;\n this.playerWrapper.changeSource(contentSrc, playOnLoad);\n};\n\n/**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ads response is\n * used when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?string} adsResponse The ads response to be requested when the\n * content loads. Leave blank to use the existing ads response.\n * @param {?boolean} playOnLoad True to play the content once it has loaded,\n * false to only load the content but not start playback.\n */\nController.prototype.setContentWithAdsResponse = function (contentSrc, adsResponse, playOnLoad) {\n this.reset();\n this.settings.adsResponse = adsResponse ? adsResponse : this.settings.adsResponse;\n this.playerWrapper.changeSource(contentSrc, playOnLoad);\n};\n\n/**\n * Resets the state of the plugin.\n */\nController.prototype.reset = function () {\n this.sdkImpl.reset();\n this.playerWrapper.reset();\n};\n\n/**\n * Listener JSDoc for ESLint. This listener can be passed to\n * (add|remove)ContentEndedListener.\n * @callback listener\n */\n\n/**\n * Adds a listener for the 'contentended' event of the video player. This should\n * be used instead of setting an 'contentended' listener directly to ensure that\n * the ima can do proper cleanup of the SDK before other event listeners are\n * called.\n * @param {listener} listener The listener to be called when content\n * completes.\n */\nController.prototype.addContentEndedListener = function (listener) {\n this.playerWrapper.addContentEndedListener(listener);\n};\n\n/**\n * Adds a listener that will be called when content and all ads have\n * finished playing.\n * @param {listener} listener The listener to be called when content and ads\n * complete.\n */\nController.prototype.addContentAndAdsEndedListener = function (listener) {\n this.contentAndAdsEndedListeners.push(listener);\n};\n\n/**\n * Sets the listener to be called to trigger manual ad break playback.\n * @param {listener} listener The listener to be called to trigger manual ad\n * break playback.\n */\nController.prototype.setAdBreakReadyListener = function (listener) {\n this.sdkImpl.setAdBreakReadyListener(listener);\n};\n\n/**\n * Changes the flag to show or hide the ad countdown timer.\n *\n * @param {boolean} showCountdownIn Show or hide the countdown timer.\n */\nController.prototype.setShowCountdown = function (showCountdownIn) {\n this.adUi.setShowCountdown(showCountdownIn);\n this.showCountdown = showCountdownIn;\n this.countdownDiv.style.display = this.showCountdown ? 'block' : 'none';\n};\n\n/**\n * Initializes the AdDisplayContainer. On mobile, this must be done as a\n * result of user action.\n */\nController.prototype.initializeAdDisplayContainer = function () {\n this.sdkImpl.initializeAdDisplayContainer();\n};\n\n/**\n * Called by publishers in manual ad break playback mode to start an ad\n * break.\n */\nController.prototype.playAdBreak = function () {\n this.sdkImpl.playAdBreak();\n};\n\n/**\n * Callback JSDoc for ESLint. This callback can be passed to addEventListener.\n * @callback callback\n */\n\n/**\n * Ads an EventListener to the AdsManager. For a list of available events,\n * see\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdEvent.Type\n * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to\n * listen.\n * @param {callback} callback The method to call when the event is fired.\n */\nController.prototype.addEventListener = function (event, callback) {\n this.sdkImpl.addEventListener(event, callback);\n};\n\n/**\n * Returns the instance of the AdsManager.\n * @return {google.ima.AdsManager} The AdsManager being used by the plugin.\n */\nController.prototype.getAdsManager = function () {\n return this.sdkImpl.getAdsManager();\n};\n\n/**\n * Returns the instance of the player id.\n * @return {string} The player id.\n */\nController.prototype.getPlayerId = function () {\n return this.playerWrapper.getPlayerId();\n};\n\n/**\n * Changes the ad tag. You will need to call requestAds after this method\n * for the new ads to be requested.\n * @param {?string} adTag The ad tag to be requested the next time\n * requestAds is called.\n */\nController.prototype.changeAdTag = function (adTag) {\n this.reset();\n this.settings.adTagUrl = adTag;\n};\n\n/**\n * Pauses the ad.\n */\nController.prototype.pauseAd = function () {\n this.adUi.onAdsPaused();\n this.sdkImpl.pauseAds();\n};\n\n/**\n * Resumes the ad.\n */\nController.prototype.resumeAd = function () {\n this.adUi.onAdsPlaying();\n this.sdkImpl.resumeAds();\n};\n\n/**\n * @return {boolean} true if we expect that ads will autoplay. false otherwise.\n */\nController.prototype.adsWillAutoplay = function () {\n if (this.settings.adsWillAutoplay !== undefined) {\n return this.settings.adsWillAutoplay;\n } else if (this.settings.adWillAutoplay !== undefined) {\n return this.settings.adWillAutoplay;\n } else {\n return !!this.playerWrapper.getPlayerOptions().autoplay;\n }\n};\n\n/**\n * @return {boolean} true if we expect that ads will autoplay. false otherwise.\n */\nController.prototype.adsWillPlayMuted = function () {\n if (this.settings.adsWillPlayMuted !== undefined) {\n return this.settings.adsWillPlayMuted;\n } else if (this.settings.adWillPlayMuted !== undefined) {\n return this.settings.adWillPlayMuted;\n } else if (this.playerWrapper.getPlayerOptions().muted !== undefined) {\n return this.playerWrapper.getPlayerOptions().muted;\n } else {\n return this.playerWrapper.getVolume() == 0;\n }\n};\n\n/**\n * Triggers an event on the VJS player\n * @param {string} name The event name.\n * @param {Object} data The event data.\n */\nController.prototype.triggerPlayerEvent = function (name, data) {\n this.playerWrapper.triggerPlayerEvent(name, data);\n};\n\n/**\n * Extends an object to include the contents of objects at parameters 2 onward.\n *\n * @param {Object} obj The object onto which the subsequent objects' parameters\n * will be extended. This object will be modified.\n * @param {...Object} var_args The objects whose properties are to be extended\n * onto obj.\n * @return {Object} The extended object.\n */\nController.prototype.extend = function (obj) {\n var arg = void 0;\n var index = void 0;\n var key = void 0;\n\n for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n\n for (index = 0; index < args.length; index++) {\n arg = args[index];\n for (key in arg) {\n if (arg.hasOwnProperty(key)) {\n obj[key] = arg[key];\n }\n }\n }\n return obj;\n};\n\n/**\n * Copyright 2017 Google Inc.\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 * IMA SDK integration plugin for Video.js. For more information see\n * https://www.github.com/googleads/videojs-ima\n */\n\n/**\n * Exposes the ImaPlugin to a publisher implementation.\n *\n * @param {Object} player Instance of the video.js player to which this plugin\n * will be added.\n * @param {Object} options Options provided by the implementation.\n * @constructor\n * @struct\n * @final\n */\nvar ImaPlugin = function ImaPlugin(player, options) {\n this.controller = new Controller(player, options);\n\n /**\n * Listener JSDoc for ESLint. This listener can be passed to\n * addContent(AndAds)EndedListener.\n * @callback listener\n */\n\n /**\n * Adds a listener that will be called when content and all ads have\n * finished playing.\n * @param {listener} listener The listener to be called when content and ads\n * complete.\n */\n this.addContentAndAdsEndedListener = function (listener) {\n this.controller.addContentAndAdsEndedListener(listener);\n }.bind(this);\n\n /**\n * Adds a listener for the 'contentended' event of the video player. This\n * should be used instead of setting an 'contentended' listener directly to\n * ensure that the ima can do proper cleanup of the SDK before other event\n * listeners are called.\n * @param {listener} listener The listener to be called when content\n * completes.\n */\n this.addContentEndedListener = function (listener) {\n this.controller.addContentEndedListener(listener);\n }.bind(this);\n\n /**\n * Callback JSDoc for ESLint. This callback can be passed to addEventListener.\n * @callback callback\n */\n\n /**\n * Ads an EventListener to the AdsManager. For a list of available events,\n * see\n * https://developers.google.com/interactive-media-ads/docs/sdks/html5/v3/apis#ima.AdEvent.Type\n * @param {google.ima.AdEvent.Type} event The AdEvent.Type for which to\n * listen.\n * @param {callback} callback The method to call when the event is fired.\n */\n this.addEventListener = function (event, callback) {\n this.controller.addEventListener(event, callback);\n }.bind(this);\n\n /**\n * Changes the ad tag. You will need to call requestAds after this method\n * for the new ads to be requested.\n * @param {?string} adTag The ad tag to be requested the next time requestAds\n * is called.\n */\n this.changeAdTag = function (adTag) {\n this.controller.changeAdTag(adTag);\n }.bind(this);\n\n /**\n * Returns the instance of the AdsManager.\n * @return {google.ima.AdsManager} The AdsManager being used by the plugin.\n */\n this.getAdsManager = function () {\n return this.controller.getAdsManager();\n }.bind(this);\n\n /**\n * Initializes the AdDisplayContainer. On mobile, this must be done as a\n * result of user action.\n */\n this.initializeAdDisplayContainer = function () {\n this.controller.initializeAdDisplayContainer();\n }.bind(this);\n\n /**\n * Pauses the ad.\n */\n this.pauseAd = function () {\n this.controller.pauseAd();\n }.bind(this);\n\n /**\n * Called by publishers in manual ad break playback mode to start an ad\n * break.\n */\n this.playAdBreak = function () {\n this.controller.playAdBreak();\n }.bind(this);\n\n /**\n * Creates the AdsRequest and request ads through the AdsLoader.\n */\n this.requestAds = function () {\n this.controller.requestAds();\n }.bind(this);\n\n /**\n * Resumes the ad.\n */\n this.resumeAd = function () {\n this.controller.resumeAd();\n }.bind(this);\n\n /**\n * Sets the listener to be called to trigger manual ad break playback.\n * @param {listener} listener The listener to be called to trigger manual ad\n * break playback.\n */\n this.setAdBreakReadyListener = function (listener) {\n this.controller.setAdBreakReadyListener(listener);\n }.bind(this);\n\n /**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ad tag is\n * requested when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?string} adTag The ad tag to be requested when the content loads.\n * Leave blank to use the existing ad tag.\n * @param {?boolean} playOnLoad True to play the content once it has loaded,\n * false to only load the content but not start playback.\n */\n this.setContentWithAdTag = function (contentSrc, adTag, playOnLoad) {\n this.controller.setContentWithAdTag(contentSrc, adTag, playOnLoad);\n }.bind(this);\n\n /**\n * Sets the content of the video player. You should use this method instead\n * of setting the content src directly to ensure the proper ads response is\n * used when the video content is loaded.\n * @param {?string} contentSrc The URI for the content to be played. Leave\n * blank to use the existing content.\n * @param {?string} adsResponse The ads response to be requested when the\n * content loads. Leave blank to use the existing ads response.\n * @param {?boolean} playOnLoad True to play the content once it has loaded,\n * false to only load the content but not start playback.\n */\n this.setContentWithAdsResponse = function (contentSrc, adsResponse, playOnLoad) {\n this.controller.setContentWithAdsResponse(contentSrc, adsResponse, playOnLoad);\n }.bind(this);\n\n /**\n * Changes the flag to show or hide the ad countdown timer.\n *\n * @param {boolean} showCountdownIn Show or hide the countdown timer.\n */\n this.setShowCountdown = function (showCountdownIn) {\n this.controller.setShowCountdown(showCountdownIn);\n }.bind(this);\n};\n\nvar init = function init(options) {\n /* eslint no-invalid-this: 'off' */\n this.ima = new ImaPlugin(this, options);\n};\n\nvar registerPlugin = videojs.registerPlugin || videojs.plugin;\nregisterPlugin('ima', init);\n\n})));\n"},246:function(n,e,t){t(237)(t(243))}}]);